# Migrating from Semantic Kernel to Microsoft Agent Framework in .NET: A Step-by-Step Guide

If you shipped an AI agent in .NET over the last two years, there is a good chance it runs on Semantic Kernel. That was the right call at the time. But with Microsoft Agent Framework reaching GA in April 2026, migrating from Semantic Kernel to Microsoft Agent Framework is now the path [Microsoft's own migration guide](https://learn.microsoft.com/en-us/agent-framework/migration-guide/from-semantic-kernel/) points existing teams toward, and the API surface is different enough that a "find and replace" migration will not compile. This guide walks the exact changes I make when moving a production agent across, from `ChatCompletionAgent` to `AIAgent`, tool registration, sessions, and the dependency injection wiring inside an ASP.NET Core API.

I have done this migration on a real support-triage service, and the trade-off that bit us early was treating it as a mechanical rename. It is not. The two frameworks share vocabulary but differ in how agents are created, how tools attach, and how a conversation keeps state. If you want the complete, runnable version of these patterns wired into a working ASP.NET Core API, the annotated source on [Patreon](https://www.patreon.com/CodingDroplets) carries the full implementation with the edge cases and error handling this article deliberately keeps short.

Agent Framework is the same primitive the [AI-Powered .NET APIs course](https://aiapis.codingdroplets.com/) builds on from the first agent onwards. Chapter 12 constructs an `AIAgent` with instructions, tools, and agent threads inside one running support API, so the framework you are migrating to is shown in the context you actually deploy it in, not as an isolated console demo.

[![AI-Powered .NET APIs](https://newsletter.codingdroplets.com/images/ai-api-course-banner-1.jpg align="center")](https://aiapis.codingdroplets.com/)

## Why Migrate from Semantic Kernel at All?

Semantic Kernel is not being deleted. Microsoft has committed to critical bug fixes for the Semantic Kernel agent abstractions for at least a year after Agent Framework GA, so a stable, in-production agent that needs nothing new is safe to leave alone for now. The reasons to move are concrete rather than cosmetic:

*   **A simpler mental model.** Agent Framework works directly against `IChatClient` from `Microsoft.Extensions.AI`. There is no `Kernel` object to construct, own, and thread through every agent.
    
*   **One agent type instead of many.** Semantic Kernel gives you `ChatCompletionAgent`, `OpenAIAssistantAgent`, `AzureAIAgent`, and more. Agent Framework consolidates these into a single `ChatClientAgent` (exposed through the `AIAgent` base type) that works with any provider offering an `IChatClient`.
    
*   **Less boilerplate for tools.** Exposing a method as a tool no longer needs an attribute, a plugin wrapper, and a kernel registration.
    
*   **A unified future.** Agent Framework is where AutoGen and Semantic Kernel's agent stories converge, so new orchestration patterns land here first.
    

The honest answer to "should I migrate today?" is: migrate new agent work now, and plan the migration of stable production agents rather than rushing it. If your agent is actively growing new capabilities, every week you wait is more Semantic Kernel code to convert later.

## What Actually Changed Between the Two Frameworks

Before touching code, it helps to hold the shape of the change in your head. Almost every migration edit falls into one of five buckets.

| Concern | Semantic Kernel | Microsoft Agent Framework |
| --- | --- | --- |
| Namespaces | `Microsoft.SemanticKernel`, `Microsoft.SemanticKernel.Agents` | `Microsoft.Extensions.AI`, `Microsoft.Agents.AI` |
| Agent type | `ChatCompletionAgent`, `AzureAIAgent`, etc. | `AIAgent` / `ChatClientAgent` |
| Creation | `new ChatCompletionAgent { Kernel = ... }` | `chatClient.AsAIAgent(...)` |
| Tools | `[KernelFunction]` + `KernelPlugin` + `Kernel` | `AIFunctionFactory.Create(method)` |
| Conversation state | Manually constructed `AgentThread` | `agent.CreateSessionAsync()` |
| Invocation | `InvokeAsync` / `InvokeStreamingAsync` | `RunAsync` / `RunStreamingAsync` |

These snippets assume .NET 10 and `Microsoft.Agents.AI` 1.x (GA April 2026), with `Microsoft.Extensions.AI` providing the `IChatClient` your agent talks through.

## The Step-by-Step Migration Path

### Step 1: Swap the Packages and Namespaces

Add the `Microsoft.Agents.AI` package (plus the provider integration you use, for example the OpenAI or Azure AI Foundry package) and update the using directives. Semantic Kernel leans on `Microsoft.SemanticKernel.Agents`; Agent Framework lives under `Microsoft.Agents.AI` and borrows its message and content types from `Microsoft.Extensions.AI`.

```csharp
// Before
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents;

// After
using Microsoft.Extensions.AI;
using Microsoft.Agents.AI;
```

### Step 2: Replace the Agent Construction

In Semantic Kernel every agent needs a `Kernel` instance, even an empty one. Agent Framework drops that requirement: you build the agent straight off an `IChatClient` using the `AsAIAgent` extension.

```csharp
// Before - Semantic Kernel
ChatCompletionAgent agent = new()
{
    Instructions = "You triage support tickets and set a priority.",
    Kernel = kernel   // every agent must carry a Kernel
};
```

```csharp
// After - Agent Framework
AIAgent agent = chatClient.AsAIAgent(
    instructions: "You triage support tickets and set a priority.");
```

That `chatClient` is any `IChatClient` you already register for OpenAI, Azure OpenAI, GitHub Models, or a local Ollama model. The agent no longer owns provider configuration; the chat client does.

### Step 3: Convert Your Tools

This is where Semantic Kernel asked for the most ceremony: decorate the method with `[KernelFunction]`, wrap it in a plugin, add the plugin to a kernel, and hand the kernel to the agent. Agent Framework collapses that into a single argument.

```csharp
// Before - Semantic Kernel
KernelFunction fn = KernelFunctionFactory.CreateFromMethod(GetTicketStatus);
KernelPlugin plugin = KernelPluginFactory.CreateFromFunctions("Support", [fn]);
kernel.Plugins.Add(plugin);
// ...then the kernel is passed to the agent
```

```csharp
// After - Agent Framework
AIAgent agent = chatClient.AsAIAgent(
    instructions: "...",
    tools: [AIFunctionFactory.Create(GetTicketStatus)]);
```

The `[KernelFunction]` attribute is gone. A plain method works as a tool, and a `[Description]` attribute on the method or its parameters is optional context for the model rather than a requirement.

### Step 4: Move from Threads to Sessions

Semantic Kernel made the caller pick and construct the correct thread type. Agent Framework asks the agent to create a session for you, which keeps provider-specific details out of your code.

```csharp
// Before - Semantic Kernel
AgentThread thread = new AzureAIAgentThread(client);

// After - Agent Framework
AgentSession session = await agent.CreateSessionAsync();
```

### Step 5: Update the Invocation Calls

Semantic Kernel returned an async stream even when you wanted a single reply. Agent Framework's non-streaming call returns one `AgentResponse`, with the text in `response.Text`.

```csharp
// Before - Semantic Kernel
await foreach (var item in agent.InvokeAsync(userInput, thread))
    Console.WriteLine(item.Message);

// After - Agent Framework
AgentResponse response = await agent.RunAsync(userInput, session);
Console.WriteLine(response.Text);
```

For token-by-token output, `InvokeStreamingAsync` becomes `RunStreamingAsync`, which yields `AgentResponseUpdate` objects you concatenate as they arrive.

### Step 6: Rewire Dependency Injection in Your ASP.NET Core API

This is the step that matters most for a web API, and it is where the simplification pays off. Under Semantic Kernel you registered a `Kernel` and built the agent from it. Under Agent Framework you register the `IChatClient` once and produce the agent directly.

```csharp
// Before - Semantic Kernel
services.AddKernel();
services.AddKeyedSingleton<Agent>("triage", (sp, _) =>
    new ChatCompletionAgent { Kernel = sp.GetRequiredService<Kernel>() });
```

```csharp
// After - Agent Framework
services.AddKeyedSingleton<AIAgent>("triage", (sp, _) =>
    sp.GetRequiredService<IChatClient>().AsAIAgent(
        instructions: "You triage support tickets and set a priority."));
```

Getting the DI boundary right in a real API means also thinking about how the agent shares the same `IChatClient`, resilience, and telemetry you already configured. Wiring an agent into a production endpoint alongside those concerns is exactly what [Chapter 12 of the AI-Powered .NET APIs course](https://aiapis.codingdroplets.com/) walks through against a running support API, so the registration above is shown inside a full request pipeline rather than in isolation.

## What Are the Most Common Migration Pitfalls?

Most migrations fail in the same few places. Here is the short answer, then the detail.

The biggest mistakes are migrating agent creation without migrating orchestration, forgetting that `RunAsync` returns a single response instead of a stream, and leaving `[KernelFunction]` attributes on methods that no longer need them.

**Splitting agents from their orchestration.** The instinct is to convert each `ChatCompletionAgent` to an `AIAgent` first and deal with `AgentGroupChat` later. That leaves you with a hybrid where Semantic Kernel's group chat is trying to coordinate Agent Framework agents, and it does not work. Migrate a group of agents and the code that orchestrates them in the same pass, or keep the whole group on Semantic Kernel until you are ready to move all of it.

**Assuming the invocation shape is unchanged.** `InvokeAsync` streamed; `RunAsync` does not. If you paste a `RunAsync` call into an old `await foreach`, it will not compile, and if you only skim the change you may drop tool-call and reasoning messages that now live in `response.Messages`.

**Carrying dead ceremony across.** Old `[KernelFunction]` attributes, plugin factories, and `Kernel` plumbing compile away slowly. Delete them as you migrate each tool; leaving them makes the new code look more complex than it is and confuses the next reader.

**Mapping options one to one.** Semantic Kernel's `OpenAIPromptExecutionSettings` and `AgentInvokeOptions` do not carry over verbatim. Per-run options move to `ChatClientAgentRunOptions`, so budget a little time to re-express settings like `MaxOutputTokens` rather than expecting a direct swap.

## Verification Checklist Before You Ship

Do not declare the migration done until each of these holds:

1.  The project no longer references `Microsoft.SemanticKernel.Agents`, and the build is clean with no leftover `Kernel` construction.
    
2.  Every tool is a plain method registered through `AIFunctionFactory.Create`, with no `[KernelFunction]` attributes remaining.
    
3.  Non-streaming endpoints read `response.Text`; streaming endpoints consume `AgentResponseUpdate` from `RunStreamingAsync`.
    
4.  Multi-agent flows use Agent Framework orchestration end to end, with no `AgentGroupChat` left coordinating migrated agents.
    
5.  Your integration tests exercise a real request through the ASP.NET Core endpoint, not just the agent in isolation, so the DI wiring is proven.
    

If you are still deciding whether Agent Framework is even the right destination versus staying on Semantic Kernel or using `Microsoft.Extensions.AI` directly, my [comparison of MEAI vs Semantic Kernel vs Agent Framework](https://codingdroplets.com/meai-vs-semantic-kernel-vs-agent-framework-dotnet-2026) lays out when each one fits. And once you are on Agent Framework, [when to reach for an agent at all in ASP.NET Core](https://codingdroplets.com/ai-agents-aspnet-core-microsoft-agent-framework) is worth a read before you add more of them.

## Frequently Asked Questions

### Is Semantic Kernel deprecated now that Agent Framework is GA?

No. Semantic Kernel is not deprecated, and its agent abstractions receive critical bug fixes for at least a year after Agent Framework's GA. Microsoft's guidance is to start new agent projects on Agent Framework and plan the migration of existing production agents, not to treat Semantic Kernel as dead the day you read this.

### Can I run Semantic Kernel and Agent Framework side by side during migration?

Yes, within limits. You can migrate one agent or one service at a time, but you cannot mix them inside a single orchestration. If Semantic Kernel's `AgentGroupChat` is coordinating a set of agents, migrate that whole group together. Isolated single agents are the safe unit to move one at a time.

### Do I still need a Kernel object in Microsoft Agent Framework?

No. That is one of the central simplifications. Agent Framework builds agents directly from an `IChatClient` using `AsAIAgent`, so there is no `Kernel` to create, register in DI, or pass into each agent. Your provider configuration lives on the chat client instead.

### How do my Semantic Kernel plugins map to Agent Framework tools?

A Semantic Kernel plugin method decorated with `[KernelFunction]` becomes a plain method passed through `AIFunctionFactory.Create` in the agent's `tools` argument. You drop the attribute and the plugin wrapper entirely. An optional `[Description]` on the method or parameters gives the model extra hints, but nothing is required.

### Will migrating change how my ASP.NET Core API streams responses to clients?

The pattern stays familiar but the types change. `InvokeStreamingAsync` becomes `RunStreamingAsync`, and each yielded item is an `AgentResponseUpdate` instead of a `StreamingChatMessageContent`. If you already stream over Server-Sent Events, you keep that transport and only adjust how you read each update before writing it to the response.

* * *

## About the Author

I'm Celin Daniel, Co-founder of [Coding Droplets](https://codingdroplets.com/). I've been building .NET and ASP.NET Core systems in production for 13+ years - APIs, distributed backends, enterprise platforms. Everything I write here comes from real shipping experience: patterns that held up, trade-offs that bit us, and lessons learned the hard way.

*   GitHub: [codingdroplets](http://github.com/codingdroplets/)
    
*   YouTube: [Coding Droplets](https://www.youtube.com/@CodingDroplets)
    
*   Website: [codingdroplets.com](https://codingdroplets.com/)
