Semantic Kernel Free code examples in C#, Python and Java
Microsoft's agent framework for C#, Python and Java.
WHAT THIS PAGE COVERS
Plugins — turning ordinary methods into tools the model can call.
gpt-5.4-mini
Microsoft.SemanticKernel
Model ids change. If a sample returns a 404 on the model, that is the first thing to check against the official docs.
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
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}.");
}
}
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);
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.
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"
@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}."
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())
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.
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"
@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 + ".";
}
}
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();
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.
https://learn.microsoft.com/semantic-kernel/