← Code Recipes
Frameworks & SDKs

Semantic Kernel Free code examples in C#, Python and Java

Microsoft's agent framework for C#, Python and Java.

C# Python Java JavaScript

WHAT THIS PAGE COVERS

Plugins — turning ordinary methods into tools the model can call.

Model gpt-5.4-mini
Package Microsoft.SemanticKernel
Checked

Model ids change. If a sample returns a 404 on the model, that is the first thing to check against the official docs.

Install

One package covers most scenarios. Add the logging packages early — watching which functions the kernel chose is how you debug a plugin that is never called.

dotnet add package Microsoft.SemanticKernel
dotnet add package Microsoft.Extensions.Logging.Console

setx OPENAI_API_KEY "sk-your-key"     # Windows, then open a new shell
export OPENAI_API_KEY="sk-your-key"   # macOS / Linux
A plugin is an ordinary class

THE DESCRIPTION IS THE PROMPT. It is the only thing the model reads when deciding whether this method is the right one, so vague wording produces a tool that is never chosen — and the symptom looks like the model ignoring you.

using System.ComponentModel;
using Microsoft.SemanticKernel;

public class StockPlugin
{
    [KernelFunction("get_stock")]
    [Description("Gets the current stock level for a single product code.")]
    public Task<int> GetStockAsync(
        [Description("The product code, e.g. X-17")] string code)
    {
        return Task.FromResult(42);
    }

    [KernelFunction("reorder")]
    [Description("Places a reorder for a product. Only call after confirming with the user.")]
    public Task<string> ReorderAsync(string code, int quantity)
    {
        return Task.FromResult($"Ordered {quantity} of {code}.");
    }
}
Build the kernel and let it call them

FunctionChoiceBehavior.Auto() is what closes the loop. Without it the model returns a description of the call it wants and nothing runs.

using Microsoft.SemanticKernel.ChatCompletion;
using Microsoft.SemanticKernel.Connectors.OpenAI;

var builder = Kernel.CreateBuilder()
    .AddOpenAIChatCompletion(
        modelId: "gpt-5.4-mini",
        apiKey: Environment.GetEnvironmentVariable("OPENAI_API_KEY")!);

Kernel kernel = builder.Build();
kernel.Plugins.AddFromType<StockPlugin>("Stock");

var chat = kernel.GetRequiredService<IChatCompletionService>();

OpenAIPromptExecutionSettings settings = new()
{
    FunctionChoiceBehavior = FunctionChoiceBehavior.Auto(),
};

var history = new ChatHistory();
history.AddUserMessage("How many X-17 do we have?");

var result = await chat.GetChatMessageContentAsync(history, settings, kernel);
Console.WriteLine(result);
Narrowing what the model may call

Auto() exposes every registered function. For anything with side effects — the reorder above — hand the model a SHORTLIST instead, so a bad turn cannot reach a method that spends money.

// Read-only turn: the model can look things up and nothing else.
var readOnly = new OpenAIPromptExecutionSettings
{
    FunctionChoiceBehavior = FunctionChoiceBehavior.Auto(
        functions: [kernel.Plugins["Stock"]["get_stock"]]),
};

// Or require the model to produce arguments and let YOU run it —
// the right shape when a human has to approve the action.
var manual = new OpenAIPromptExecutionSettings
{
    FunctionChoiceBehavior = FunctionChoiceBehavior.Auto(
        autoInvoke: false),
};

var proposal = await chat.GetChatMessageContentAsync(history, manual, kernel);
// Inspect proposal's function calls, confirm with the user, then invoke.
Install

The PyPI name is semantic-kernel; the import is semantic_kernel. Everything is async, so the samples below run inside asyncio.

pip install semantic-kernel

export OPENAI_API_KEY="sk-your-key"
A plugin is an ordinary class

@kernel_function takes the name and description the model will see. The description decides whether the function is ever chosen — treat it as prompt text, not as a docstring.

from typing import Annotated
from semantic_kernel.functions import kernel_function

class StockPlugin:
    @kernel_function(
        name="get_stock",
        description="Gets the current stock level for a single product code.",
    )
    def get_stock(
        self,
        code: Annotated[str, "The product code, e.g. X-17"],
    ) -> int:
        return 42

    @kernel_function(
        name="reorder",
        description="Places a reorder. Only call after confirming with the user.",
    )
    def reorder(self, code: str, quantity: int) -> str:
        return f"Ordered {quantity} of {code}."
Build the kernel and let it call them

function_choice_behavior is the switch. Set it to Auto() and the kernel runs the loop; leave it out and the model can only say what it would like to call.

import asyncio
import os

from semantic_kernel import Kernel
from semantic_kernel.connectors.ai.open_ai import (
    OpenAIChatCompletion,
    OpenAIChatPromptExecutionSettings,
)
from semantic_kernel.connectors.ai.function_choice_behavior import (
    FunctionChoiceBehavior,
)
from semantic_kernel.contents.chat_history import ChatHistory

async def main() -> None:
    kernel = Kernel()

    chat = OpenAIChatCompletion(
        ai_model_id="gpt-5.4-mini",
        api_key=os.environ["OPENAI_API_KEY"],
    )
    kernel.add_service(chat)
    kernel.add_plugin(StockPlugin(), plugin_name="Stock")

    settings = OpenAIChatPromptExecutionSettings()
    settings.function_choice_behavior = FunctionChoiceBehavior.Auto()

    history = ChatHistory()
    history.add_user_message("How many X-17 do we have?")

    result = await chat.get_chat_message_content(
        chat_history=history, settings=settings, kernel=kernel)

    print(result)

asyncio.run(main())
Narrowing what the model may call

Auto() offers every registered function, including the ones that spend money. Pass a filtered list when the turn should only be able to read.

# Read-only: the model can look things up and nothing else.
settings.function_choice_behavior = FunctionChoiceBehavior.Auto(
    filters={"included_functions": ["Stock-get_stock"]},
)

# Or take the loop back: the model proposes, you decide.
settings.function_choice_behavior = FunctionChoiceBehavior.Auto(
    auto_invoke=False,
)

proposal = await chat.get_chat_message_content(
    chat_history=history, settings=settings, kernel=kernel)

# proposal carries the function calls the model wanted. Confirm with
# a human, then invoke them yourself.
Install

Use the BOM. The Semantic Kernel Java artifacts are versioned together and mixing versions across semantickernel-api and the aiservices packages fails at runtime rather than at build time.

# Gradle
implementation(platform("com.microsoft.semantic-kernel:semantickernel-bom:1.7.0"))
implementation("com.microsoft.semantic-kernel:semantickernel-api")
implementation("com.microsoft.semantic-kernel:semantickernel-aiservices-openai")

export OPENAI_API_KEY="sk-your-key"
A plugin is an ordinary class

@DefineKernelFunction and @KernelFunctionParameter carry the descriptions. As everywhere in this framework, those strings are what the model reads — they are prompt, not comment.

import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction;
import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter;

public class StockPlugin {

    @DefineKernelFunction(
        name = "get_stock",
        description = "Gets the current stock level for a single product code.")
    public int getStock(
        @KernelFunctionParameter(
            name = "code",
            description = "The product code, e.g. X-17") String code) {
        return 42;
    }

    @DefineKernelFunction(
        name = "reorder",
        description = "Places a reorder. Only call after confirming with the user.")
    public String reorder(
        @KernelFunctionParameter(name = "code") String code,
        @KernelFunctionParameter(name = "quantity") int quantity) {
        return "Ordered " + quantity + " of " + code + ".";
    }
}
Build the kernel and let it call them

Java's switch is ToolCallBehavior on the InvocationContext, not FunctionChoiceBehavior. allowAllKernelFunctions(true) is the equivalent of Auto().

import com.azure.ai.openai.OpenAIAsyncClient;
import com.azure.ai.openai.OpenAIClientBuilder;
import com.azure.core.credential.KeyCredential;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion;
import com.microsoft.semantickernel.orchestration.InvocationContext;
import com.microsoft.semantickernel.orchestration.ToolCallBehavior;
import com.microsoft.semantickernel.plugin.KernelPluginFactory;
import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService;
import com.microsoft.semantickernel.services.chatcompletion.ChatHistory;

OpenAIAsyncClient client = new OpenAIClientBuilder()
    .credential(new KeyCredential(System.getenv("OPENAI_API_KEY")))
    .buildAsyncClient();

ChatCompletionService chat = OpenAIChatCompletion.builder()
    .withModelId("gpt-5.4-mini")
    .withOpenAIAsyncClient(client)
    .build();

Kernel kernel = Kernel.builder()
    .withAIService(ChatCompletionService.class, chat)
    .withPlugin(KernelPluginFactory.createFromObject(new StockPlugin(), "Stock"))
    .build();

InvocationContext context = new InvocationContext.Builder()
    .withToolCallBehavior(ToolCallBehavior.allowAllKernelFunctions(true))
    .build();
Invoking, and narrowing what may be called

The service returns a list because a turn can produce several messages. For side-effecting functions, allow only the ones the turn needs rather than everything the kernel knows about.

import com.microsoft.semantickernel.services.chatcompletion.ChatMessageContent;
import java.util.List;

ChatHistory history = new ChatHistory();
history.addUserMessage("How many X-17 do we have?");

List<ChatMessageContent<?>> results = chat
    .getChatMessageContentsAsync(history, kernel, context)
    .block();

results.forEach(System.out::println);

// Read-only turn: only the lookup is reachable, so a bad turn cannot
// place an order.
InvocationContext readOnly = new InvocationContext.Builder()
    .withToolCallBehavior(ToolCallBehavior.allowOnlyKernelFunctions(
        true, kernel.getFunction("Stock", "get_stock")))
    .build();

QUESTIONS

Which languages are the Semantic Kernel examples in?

C#, Python and Java. Every sample runs as pasted and reads its credentials from an environment variable — no key is ever written into the code.

Which package do I install for Semantic Kernel?

The samples use Microsoft.SemanticKernel. The install step on each language tab gives the exact command.

Which Semantic Kernel model do these examples use?

gpt-5.4-mini, checked against the official documentation on 26 September 2026. Model ids change often; if a call returns a model-not-found error, check the current list in the official docs.

Where is the official Semantic Kernel documentation?

https://learn.microsoft.com/semantic-kernel/ — it is linked at the bottom of this page, and it is the authority whenever it disagrees with a sample here.

ALSO IN FRAMEWORKS & SDKS

The authority

Official Semantic Kernel documentation

Model names, pricing and rate limits change faster than any page here can. When this page and the official docs disagree, the official docs are right.

Read the docs ↗

https://learn.microsoft.com/semantic-kernel/

New drops, every week

Free tools & Claude templates, landing regularly.

We keep shipping new free tools, code recipes and Claude Code templates. Follow @freeyantra on Instagram or join the newsletter so you never miss one.

Follow @freeyantra

or get them by email

Double opt-in. Unsubscribe any time. Privacy