Semantic Kernel is Microsoft's open-source SDK for integrating large language models into C#, Python and Java applications through plugins, prompt templates, automatic function calling and filters. It powers a large number of production systems, and in 2026 it sits in an unusual position: still maintained and still shipping releases, but officially succeeded by Microsoft Agent Framework. This guide shows how to use Semantic Kernel well in practice, explains where it stands today, and helps you decide when it is still the right fit and how to plan a migration.

What Is Semantic Kernel?#

At its core, Semantic Kernel is a lightweight dependency injection container, the Kernel, that holds two kinds of components: services, such as chat completion, embedding generation, logging and HTTP clients, and plugins, which are named groups of functions the model can call or that prompts can reference. Around that core it adds prompt templating, automatic function calling, filters for cross-cutting control, agent abstractions and connectors for many model providers.

The .NET packages are versioned together. Microsoft.SemanticKernel is the convenience package that brings in the core and the OpenAI connectors, and version 1.80.1 shipped in September 2026. Some areas, notably the agent orchestration and in-process runtime packages, are still published with a -preview suffix, and individual experimental APIs carry SKEXP diagnostic IDs.

Semantic Kernel also shaped the rest of the .NET AI stack. The IChatClient and IEmbeddingGenerator abstractions in Microsoft.Extensions.AI were extracted from it, and its vector store abstractions became Microsoft.Extensions.VectorData. Modern Semantic Kernel builds on those shared types, so you can register an IChatClient in a kernel with AddOpenAIChatClient or use the classic IChatCompletionService registered by AddOpenAIChatCompletion.

Where Semantic Kernel Stands in 2026#

The most important fact for any team evaluating Semantic Kernel today is that the project's own README now states that Microsoft Agent Framework is its enterprise-ready successor. Agent Framework was built by the Semantic Kernel and AutoGen teams, reached 1.0 in April 2026, and receives the new features. Semantic Kernel continues to publish releases, but you should read those releases as maintenance of a mature product rather than a signal of where investment is going.

Two concrete changes illustrate the shift:

  • Vector store connectors moved out. The packages that used to be named Microsoft.SemanticKernel.Connectors.InMemory, .AzureAISearch, .PgVector, .Qdrant, .SqlServer and others are deprecated on NuGet. They were renamed to CommunityToolkit.VectorData.* packages with stable 1.0 releases, because they implement Microsoft.Extensions.VectorData and have no dependency on Semantic Kernel.
  • Agent features converged in Agent Framework. Semantic Kernel's agent orchestration APIs remained experimental, while Agent Framework shipped stable workflows with sequential, concurrent, handoff, group chat and Magentic patterns.

The practical guidance follows directly. Start new projects on Agent Framework or, for simpler features, directly on Microsoft.Extensions.AI. Keep existing Semantic Kernel applications running, keep them patched, and plan a migration on your own schedule. For the official statement about the support window, check the Semantic Kernel and Agent Framework announcement linked from the Semantic Kernel repository, since support terms are the kind of detail that should come from the source.

How Semantic Kernel Works#

When you invoke a prompt or function through the kernel, a predictable sequence runs:

  1. The kernel selects the AI service that should run the prompt, optionally using a service ID.
  2. The prompt template is rendered with KernelArguments, which can call other kernel functions inline.
  3. Prompt render filters can inspect or rewrite the rendered prompt.
  4. The rendered prompt goes to the model with PromptExecutionSettings, including the function choice behavior that advertises plugins as tools.
  5. If the model requests tool calls, the kernel invokes the matching KernelFunctions, running auto function invocation filters and function invocation filters around each call.
  6. The final result comes back as a FunctionResult or chat message content.
ConceptWhat it isTypical API
KernelContainer of services and pluginsKernel.CreateBuilder(), kernel.Plugins
KernelFunctionA callable unit, native or prompt-based[KernelFunction], CreateFunctionFromPrompt
KernelPluginA named group of functionsPlugins.AddFromType<T>(), AddFromObject
KernelArgumentsVariables plus execution settingsnew KernelArguments(settings) { ["input"] = text }
PromptExecutionSettingsModel parameters and tool behaviorFunctionChoiceBehavior.Auto()
FiltersMiddleware for functions and promptsIFunctionInvocationFilter, IPromptRenderFilter, IAutoFunctionInvocationFilter
AgentsHigher-level conversational wrappersChatCompletionAgent, AgentThread

Getting Started with Semantic Kernel#

Install the core package and, if you plan to use agents, the agents package:

Bash
dotnet add package Microsoft.SemanticKernel
dotnet add package Microsoft.SemanticKernel.Agents.Core

The canonical first program builds a kernel with a chat completion service, registers a plugin and lets the model call it automatically:

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

IKernelBuilder builder = Kernel.CreateBuilder();
builder.AddOpenAIChatCompletion("gpt-5-mini",
    Environment.GetEnvironmentVariable("OPENAI_API_KEY")!);
builder.Plugins.AddFromType<OrderPlugin>("orders");
Kernel kernel = builder.Build();

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

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

ChatHistory history = [];
history.AddSystemMessage("You are a support assistant for an online bookstore.");
history.AddUserMessage("Has order 1042 shipped yet?");

ChatMessageContent reply = await chat.GetChatMessageContentAsync(history, settings, kernel);
Console.WriteLine(reply.Content);
history.Add(reply);

Passing the kernel into GetChatMessageContentAsync is what makes plugins available as tools and what triggers filters. Forgetting it is the most common reason function calling "does nothing".

Building Plugins with KernelFunction#

A native plugin is an ordinary class whose methods carry [KernelFunction] and [Description] attributes. Descriptions are not decoration: they become the tool schema the model reads, so they directly affect how accurately the model picks and fills functions. Plugin classes support constructor injection, which is one of Semantic Kernel's strengths for enterprise code:

C#
using System.ComponentModel;
using Microsoft.SemanticKernel;

public sealed class OrderPlugin(IOrderRepository orders, TimeProvider clock)
{
    [KernelFunction("get_order_status")]
    [Description("Gets the shipping status of an order by its number.")]
    public async Task<OrderStatus?> GetOrderStatusAsync(
        [Description("The numeric order number, for example 1042.")] int orderNumber,
        CancellationToken cancellationToken)
    {
        return await orders.GetStatusAsync(orderNumber, cancellationToken);
    }

    [KernelFunction("get_business_date")]
    [Description("Gets today's date in UTC. Use it to reason about delivery times.")]
    public string GetBusinessDate() => clock.GetUtcNow().ToString("yyyy-MM-dd");
}

public sealed record OrderStatus(int OrderNumber, string State, DateOnly? ShippedOn);

Plugins.AddFromType<OrderPlugin>() resolves constructor parameters from the kernel's service provider, and AddFromObject registers an instance you created yourself. The documentation recommends snake_case function names because many models are trained on Python-style tool names, and it echoes OpenAI's advice to keep the number of tools per request small, ideally around ten, because selection accuracy degrades as the list grows. Beyond native code, Semantic Kernel can import plugins from OpenAPI specifications and from MCP servers.

Prompt Functions and Prompt Templates#

Prompt functions turn a template into a reusable KernelFunction. The default template syntax uses {{$variable}} for arguments and {{plugin.function}} to call another function and inline its result. Execution settings travel with the function or with the arguments:

C#
KernelFunction summarize = kernel.CreateFunctionFromPrompt(
    """
    Summarize the customer email below for a support agent.
    Today is {{orders.get_business_date}}.
    Respond with at most {{$maxBullets}} bullet points.

    Email:
    {{$email}}
    """,
    new OpenAIPromptExecutionSettings { MaxTokens = 300, Temperature = 0.2 },
    functionName: "summarize_email",
    description: "Summarizes a customer email for triage.");

FunctionResult summary = await kernel.InvokeAsync(summarize, new KernelArguments
{
    ["email"] = incomingEmail,
    ["maxBullets"] = 4,
});

Console.WriteLine(summary.GetValue<string>());

For one-off prompts, kernel.InvokePromptAsync(template, arguments) renders and runs a template without creating a named function. When you need loops or conditionals, install Microsoft.SemanticKernel.PromptTemplates.Handlebars or .Liquid and pass the matching template format and factory. Prompts can also live in YAML files, loaded through the Microsoft.SemanticKernel.Yaml package, which keeps them out of code and makes them reviewable like any other configuration.

One security note belongs next to templates: any value you insert from users, emails or documents is untrusted. Semantic Kernel HTML-encodes inserted variables and function results by default, so they cannot smuggle extra chat messages into a prompt, and you must opt in with AllowUnsafeContent to trust them. No templating feature, however, can stop a model from following instructions hidden in the content itself. Keep system instructions separate, constrain tools and treat model output as untrusted; the prompt engineering guide covers these techniques in more depth.

Automatic and Manual Function Calling#

FunctionChoiceBehavior controls how plugins are advertised to the model:

  • FunctionChoiceBehavior.Auto() lets the model decide whether to call functions, and invokes them automatically by default.
  • FunctionChoiceBehavior.Required() forces the model to call at least one of the specified functions, which is useful for extraction.
  • FunctionChoiceBehavior.None() describes functions without letting the model call them.

Each accepts an optional list of functions to restrict what is advertised, which is an easy way to keep the tool list small per request. Passing autoInvoke: false switches to manual invocation, where you inspect each requested call and decide what to run:

C#
PromptExecutionSettings manual = new()
{
    FunctionChoiceBehavior = FunctionChoiceBehavior.Auto(autoInvoke: false),
};

while (true)
{
    ChatMessageContent result = await chat.GetChatMessageContentAsync(history, manual, kernel);
    if (result.Content is not null)
    {
        Console.WriteLine(result.Content);
        break;
    }

    history.Add(result); // keep the model's tool requests in the history

    foreach (FunctionCallContent call in FunctionCallContent.GetFunctionCalls(result))
    {
        if (!await policy.IsAllowedAsync(call.PluginName, call.FunctionName, call.Arguments))
        {
            history.Add(new FunctionResultContent(call, "Not permitted.").ToChatMessage());
            continue;
        }

        FunctionResultContent output = await call.InvokeAsync(kernel);
        history.Add(output.ToChatMessage());
    }
}

Manual invocation is the right choice when each call needs its own authorization, auditing or user confirmation, and it is also how you parallelize independent calls under your own control.

Filters: Function Invocation, Prompt Render and Auto Function Invocation#

Filters are Semantic Kernel's middleware. Each receives a context object and a next delegate, and must call next for the operation to proceed. There are three kinds:

  • Function invocation filters run around every KernelFunction call, whether the function is native or prompt-based. Use them for logging, caching, exception handling, retries and result overrides.
  • Prompt render filters run around prompt rendering. Use them to redact personal data, inject retrieved context or short-circuit with a cached answer.
  • Auto function invocation filters run inside the automatic tool loop and see the chat history, the list of pending calls and iteration counters. Use them to terminate the loop early or veto calls.
C#
public sealed class ToolAuditFilter(ILogger<ToolAuditFilter> logger) : IAutoFunctionInvocationFilter
{
    private static readonly HashSet<string> Blocked = ["delete_order", "issue_refund"];

    public async Task OnAutoFunctionInvocationAsync(AutoFunctionInvocationContext context,
        Func<AutoFunctionInvocationContext, Task> next)
    {
        string name = context.Function.Name;
        if (Blocked.Contains(name))
        {
            context.Result = new FunctionResult(context.Function, "This action requires a human agent.");
            context.Terminate = true; // stop the tool loop and return to the caller
            return;
        }

        logger.LogInformation("Model called {Plugin}.{Function} (request {Index})",
            context.Function.PluginName, name, context.RequestSequenceIndex);
        await next(context);
    }
}

public sealed class EmailRedactionFilter : IPromptRenderFilter
{
    public async Task OnPromptRenderAsync(PromptRenderContext context,
        Func<PromptRenderContext, Task> next)
    {
        await next(context);
        context.RenderedPrompt = Regex.Replace(context.RenderedPrompt ?? "",
            @"[\w.+-]+@[\w-]+(\.[\w-]+)+", "[email]");
    }
}

Register filters on the kernel's collections, such as kernel.AutoFunctionInvocationFilters.Add(...) and kernel.PromptRenderFilters.Add(...), or through dependency injection. The documentation notes that the execution order of filters registered through DI is not guaranteed, so add them directly to the kernel when order matters.

Vector Stores and RAG with Semantic Kernel#

Semantic Kernel's vector store support is now provided by Microsoft.Extensions.VectorData, with connectors in the CommunityToolkit.VectorData.* packages. That means retrieval code written for a Semantic Kernel app is plain MEVD code that also works in Agent Framework. The simplest way to use retrieval in a kernel is a plugin that searches a collection and returns formatted snippets with sources:

C#
using System.ComponentModel;
using System.Text;
using Microsoft.Extensions.VectorData;
using Microsoft.SemanticKernel;

public sealed class PolicySearchPlugin(VectorStoreCollection<string, PolicyChunk> policies)
{
    [KernelFunction("search_policies")]
    [Description("Searches company policies. Returns excerpts with their source titles.")]
    public async Task<string> SearchAsync(
        [Description("A natural-language search query.")] string query,
        CancellationToken cancellationToken)
    {
        var sb = new StringBuilder();
        await foreach (var hit in policies.SearchAsync(query, top: 4,
            new() { Filter = p => p.IsPublished }, cancellationToken))
        {
            sb.AppendLine($"[{hit.Record.Title}] {hit.Record.Text}");
        }
        return sb.Length > 0 ? sb.ToString() : "No matching policy found.";
    }
}

The collection handles embedding generation if you configured an IEmbeddingGenerator on the store, and the Filter expression pushes metadata filtering into the database, provided the property is marked as indexed. Chunking, hybrid search, reranking and evaluation are covered in depth in the RAG in .NET guide.

Agents in Semantic Kernel#

Semantic Kernel's agent framework wraps a kernel in conversational abstractions. ChatCompletionAgent is the general-purpose agent, backed by any chat completion service in the kernel, and AgentThread implementations such as ChatHistoryAgentThread hold the conversation:

C#
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents;
using Microsoft.SemanticKernel.ChatCompletion;

ChatCompletionAgent agent = new()
{
    Name = "SupportAgent",
    Instructions = "Answer order questions using the available tools. Be concise.",
    Kernel = kernel,
    Arguments = new KernelArguments(new PromptExecutionSettings
    {
        FunctionChoiceBehavior = FunctionChoiceBehavior.Auto(),
    }),
};

AgentThread thread = new ChatHistoryAgentThread();

await foreach (AgentResponseItem<ChatMessageContent> item in agent.InvokeAsync(
    new ChatMessageContent(AuthorRole.User, "Where is order 1042?"), thread))
{
    Console.WriteLine(item.Message.Content);
    thread = item.Thread;
}

Semantic Kernel also offers SequentialOrchestration, ConcurrentOrchestration, HandoffOrchestration, GroupChatOrchestration and MagenticOrchestration, run on an InProcessRuntime. Those packages are still marked as preview and the documentation labels orchestration as experimental, which is a strong reason to build new multi-agent systems on Agent Framework workflows instead.

Migrating to Microsoft Agent Framework#

Migration is mostly mechanical because both frameworks share Microsoft.Extensions.AI types underneath. The main changes: agents no longer need a Kernel; they wrap an IChatClient. Plugins become plain methods described with [Description] and passed as tools. AgentThread becomes AgentSession, created by the agent. InvokeAsync becomes RunAsync, and filters become agent, function and chat client middleware. The same support agent in Agent Framework looks like this:

C#
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;

AIAgent agent = chatClient.AsAIAgent(
    name: "SupportAgent",
    instructions: "Answer order questions using the available tools. Be concise.",
    tools: [AIFunctionFactory.Create(orderTools.GetOrderStatusAsync)]);

AgentSession session = await agent.CreateSessionAsync();
AgentResponse response = await agent.RunAsync("Where is order 1042?", session);
Console.WriteLine(response.Text);

A pragmatic migration plan is to move retrieval to Microsoft.Extensions.VectorData first (often already done if you use current connectors), then replace direct IChatCompletionService calls with IChatClient, then port agents and filters, and finally replace experimental orchestrations with Agent Framework workflows. The Microsoft Agent Framework guide covers the target APIs in detail.

Best Practices#

  • Pass the kernel wherever tools or filters should apply. Chat completion calls made without a kernel skip function calling and filters.
  • Write descriptions for the model, not for humans. Explain when to use a function, required formats and units, and keep parameter lists short and primitive.
  • Scope tools per request. Pass explicit function lists to FunctionChoiceBehavior.Auto rather than exposing every plugin on every call.
  • Create kernels per operation. The documentation recommends registering the kernel as transient because its plugin collection is mutable; kernels are cheap containers.
  • Put policy in filters. Authorization, redaction and auditing belong in function and prompt filters, where they apply consistently.
  • Adopt shared abstractions now. Use IChatClient, IEmbeddingGenerator and Microsoft.Extensions.VectorData in new code, which shortens any future migration.

Common Pitfalls#

  • Using deprecated connector packages. The Microsoft.SemanticKernel.Connectors.* vector store packages are deprecated; switch to the CommunityToolkit.VectorData.* equivalents.
  • Relying on legacy memory APIs. The old memory store connectors are superseded by the vector store abstractions.
  • Filter order surprises. Filters registered through DI run in an unspecified order; register order-sensitive filters directly on the kernel.
  • Unbounded automatic tool loops. Use an auto function invocation filter to terminate loops that meet their goal early or run too long.
  • Building new multi-agent systems on experimental orchestration. Semantic Kernel orchestrations are still preview; Agent Framework workflows are stable.
  • Starting greenfield projects on Semantic Kernel. The project points new users to Agent Framework, so new code on Semantic Kernel creates migration work later.

Semantic Kernel vs Microsoft Agent Framework vs Microsoft.Extensions.AI#

CriterionSemantic KernelMicrosoft Agent FrameworkMicrosoft.Extensions.AI
Status in 2026Maintained, successor announcedStable 1.x, active developmentStable, active development
Core abstractionKernel with plugins and servicesAIAgent, AgentSession, workflowsIChatClient, IEmbeddingGenerator
Tools[KernelFunction] plugins, OpenAPI, MCPAIFunction tools, MCP, hosted toolsAIFunction with UseFunctionInvocation
Prompt templatesBuilt in, Handlebars and LiquidInstructions and context providersNot included
MiddlewareFiltersAgent, function and chat client middlewareDelegating chat clients
Multi-agent orchestrationPreview orchestrationsStable workflows with checkpointsNot included
Best fitExisting SK apps, template-heavy prompt pipelinesNew agents and multi-agent systemsDirect model features and libraries

Semantic Kernel is still a good fit when you already run it in production and it meets your needs, when your application relies heavily on its prompt templating and plugin model, or when a team's Java or Python codebases already standardize on it. For everything new, prefer Agent Framework or Microsoft.Extensions.AI.

Frequently Asked Questions#

Is Semantic Kernel deprecated?#

No, it is not marked as deprecated, and it continues to ship releases. However, its repository states that Microsoft Agent Framework is its enterprise-ready successor, and new features are developed there. Treat Semantic Kernel as a maintained platform for existing applications rather than the default for new ones.

Can I use Semantic Kernel and Agent Framework in the same application?#

Yes. Both build on Microsoft.Extensions.AI types, so an IChatClient and a Microsoft.Extensions.VectorData collection can be shared between them. This makes incremental migration practical: new features use Agent Framework while existing plugins keep running until you port them.

What replaced the Semantic Kernel vector store connectors?#

The abstractions are in Microsoft.Extensions.VectorData.Abstractions, and the connectors were renamed to CommunityToolkit.VectorData.* packages, such as CommunityToolkit.VectorData.AzureAISearch and CommunityToolkit.VectorData.PgVector. The APIs are the same abstractions you already use, so the move is mostly a package and namespace change.

Should I use IChatCompletionService or IChatClient with Semantic Kernel?#

Both work. IChatCompletionService is the classic Semantic Kernel interface used by most samples and filters, while IChatClient is the shared Microsoft.Extensions.AI abstraction registered with methods such as AddOpenAIChatClient. Prefer IChatClient in new code because it carries over directly to Agent Framework.

How do I stop a runaway automatic function calling loop?#

Implement an IAutoFunctionInvocationFilter that inspects the request sequence and function names, and set context.Terminate = true when the goal is met or a limit is reached. Restricting the functions passed to FunctionChoiceBehavior.Auto also reduces unnecessary calls.

Summary#

  • Semantic Kernel organizes AI apps around a Kernel of services and plugins, with prompt templates, automatic function calling and filters.
  • It remains maintained in 2026, but Microsoft Agent Framework is its official successor and receives new features.
  • Vector store support now comes from Microsoft.Extensions.VectorData with CommunityToolkit.VectorData.* connectors.
  • Filters provide consistent control over function calls, prompt rendering and tool loops.
  • Keep stable Semantic Kernel apps running, adopt shared abstractions such as IChatClient, and migrate to Agent Framework on your own schedule.

Further Reading#