{"slug": "migrating-semantic-kernel-agents-to-microsoft-agent-framework-in-asp-net-core", "title": "Migrating Semantic Kernel Agents to Microsoft Agent Framework in ASP.NET Core", "summary": "A developer documented an incremental migration of a tool-using Semantic Kernel agent to Microsoft Agent Framework (MAF) 1.0 inside an ASP.NET Core application. The walkthrough shows how MAF replaces Semantic Kernel's mandatory Kernel object with an IChatClient, an AIAgent built via the .AsAIAgent() extension, AIFunctionFactory-created tools, and agent-created AgentSession objects. The author notes Semantic Kernel is now in maintenance mode at MAF 1.26, with new capabilities such as graph workflows, native MCP/A2A, and durable execution landing only in MAF.", "body_md": "Semantic Kernel has been the default .NET agent toolkit for years. In April 2026 Microsoft shipped Microsoft Agent Framework (MAF) 1.0 as the unification of Semantic Kernel’s enterprise features and AutoGen’s orchestration patterns. As of October 2026 the package sits at 1.26, Semantic Kernel is in maintenance mode (critical fixes only), and every new capability—graph workflows, native MCP/A2A, durable execution, better middleware—lands only in MAF.\n\nTeams that already have working Semantic Kernel agents are not forced to rewrite overnight, but the longer you wait the larger the gap becomes. This article shows a concrete, incremental migration of a tool-using agent into an ASP.NET Core application using current package names and APIs.\n\nThe biggest shift is architectural. Semantic Kernel centered everything on a `Kernel` object that owned the chat service, plugins, filters, and memory. MAF splits those responsibilities:\n\n`IChatClient` (from Microsoft.Extensions.AI).`AIAgent` (most commonly a `ChatClientAgent`).` AIFunction`s created with `AIFunctionFactory.Create`.` AgentSession` created by the agent itself.\nThere is no longer a mandatory Kernel. You create a chat client for your provider, then call the extension method `.AsAIAgent(...)`.\n\nFor a typical ASP.NET Core migration:\n\n```\ndotnet add package Microsoft.Agents.AI\ndotnet add package Microsoft.Extensions.AI\n# Provider-specific (examples)\ndotnet add package Azure.AI.OpenAI\ndotnet add package Microsoft.Extensions.AI.OpenAI  # AsIChatClient() for OpenAI/Azure OpenAI clients\ndotnet add package Azure.Identity\n# or for local\ndotnet add package OllamaSharp\n```\n\n`Microsoft.Agents.AI` 1.26 is the current stable release. Prefer the non-prerelease package unless you need a preview feature.\n\nA typical SK agent that can look up weather:\n\n```\nusing System.ComponentModel;\nusing Microsoft.SemanticKernel;\nusing Microsoft.SemanticKernel.Agents;\n\n// Values from configuration\nstring endpoint = \"https://<your-resource>.openai.azure.com/\";\nstring deploymentName = \"gpt-4o-mini\";\nstring apiKey = Environment.GetEnvironmentVariable(\"AZURE_OPENAI_API_KEY\")!;\n\npublic class WeatherPlugin\n{\n    [KernelFunction, Description(\"Gets the current weather for a city\")]\n    public string GetWeather(string city) =>\n        $\"Weather in {city}: 18°C, partly cloudy\";\n}\n\n// In Program.cs or a factory\nvar kernel = Kernel.CreateBuilder()\n    .AddAzureOpenAIChatCompletion(deploymentName, endpoint, apiKey)\n    .Build();\n\nkernel.Plugins.AddFromType<WeatherPlugin>();\n\nvar agent = new ChatCompletionAgent\n{\n    Name = \"WeatherAgent\",\n    Instructions = \"You are a helpful weather assistant. Use the available tools.\",\n    Kernel = kernel\n};\n\n// Invocation\nAgentThread thread = new ChatHistoryAgentThread();\nawait foreach (var item in agent.InvokeAsync(\"What's the weather in Seattle?\", thread))\n{\n    Console.WriteLine(item.Message);\n}\n```\n\nThe Kernel is required, the plugin must be registered on it, the thread type is caller-created, and invocation returns an `IAsyncEnumerable`.\n\nThe same agent becomes:\n\n```\nusing System.ComponentModel;\nusing Azure.AI.OpenAI;\nusing Azure.Identity;\nusing Microsoft.Agents.AI;\nusing Microsoft.Extensions.AI;\n\nstring endpoint = \"https://<your-resource>.openai.azure.com/\";\nstring deploymentName = \"gpt-4o-mini\";\n\n[Description(\"Gets the current weather for a city\")]\nstatic string GetWeather(string city) =>\n    $\"Weather in {city}: 18°C, partly cloudy\";\n\n// Create the chat client (Azure OpenAI example)\nvar azureClient = new AzureOpenAIClient(new Uri(endpoint), new DefaultAzureCredential());\nIChatClient chatClient = azureClient.GetChatClient(deploymentName).AsIChatClient();\n\n// Turn it into an agent and register the tool in one call\nAIAgent agent = chatClient.AsAIAgent(\n    name: \"WeatherAgent\",\n    instructions: \"You are a helpful weather assistant. Use the available tools when needed.\",\n    tools: [AIFunctionFactory.Create(GetWeather)]);\n\n// Session is created by the agent\nAgentSession session = await agent.CreateSessionAsync();\n\n// Non-streaming invocation returns a single AgentResponse\nAgentResponse response = await agent.RunAsync(\"What's the weather in Seattle?\", session);\nConsole.WriteLine(response.Text);\n```\n\nNo Kernel, no plugin class required (a static method or instance method works), no `[KernelFunction]` attribute, and the session is owned by the agent. Streaming uses `RunStreamingAsync` and yields `AgentResponseUpdate` objects.\n\nFor a local model the client creation changes but the rest of the API stays identical:\n\n``` js\nusing OllamaSharp;\n\nvar ollama = new OllamaApiClient(new Uri(\"http://localhost:11434\"), \"llama3.2\");\n\nAIAgent localAgent = ollama.AsAIAgent(\n    instructions: \"You are a helpful local assistant.\",\n    tools: [AIFunctionFactory.Create(GetWeather)]);\n```\n\nUse a model that supports tool calling (`llama3.2`, `qwen2.5`, etc.).\n\nRegister the chat client and the agent as services. Prefer a keyed singleton when the agent configuration is static:\n\n``` js\n// Program.cs\nbuilder.Services.AddSingleton<IChatClient>(sp =>\n{\n    var azureClient = new AzureOpenAIClient(\n        new Uri(builder.Configuration[\"AzureOpenAI:Endpoint\"]!),\n        new DefaultAzureCredential());\n\n    return azureClient.GetChatClient(\n        builder.Configuration[\"AzureOpenAI:Deployment\"]!).AsIChatClient();\n});\n\nbuilder.Services.AddKeyedSingleton<AIAgent>(\"WeatherAgent\", (sp, key) =>\n{\n    var chatClient = sp.GetRequiredService<IChatClient>();\n\n    return chatClient.AsAIAgent(\n        name: \"WeatherAgent\",\n        instructions: \"You are a helpful weather assistant. Use tools when appropriate.\",\n        tools: [AIFunctionFactory.Create(GetWeather)]);\n});\n```\n\nInject it where needed:\n\n```\npublic class WeatherController : ControllerBase\n{\n    private readonly AIAgent _agent;\n\n    public WeatherController([FromKeyedServices(\"WeatherAgent\")] AIAgent agent)\n    {\n        _agent = agent;\n    }\n\n    [HttpPost(\"ask\")]\n    public async Task<IActionResult> Ask([FromBody] string question)\n    {\n        var session = await _agent.CreateSessionAsync();\n        var response = await _agent.RunAsync(question, session);\n        return Ok(new { answer = response.Text });\n    }\n}\n```\n\nIf you need per-request state or different tool instances (for example a tool that depends on a scoped `DbContext`), register the agent as scoped instead.\n\nCreate a session once per conversation and reuse it for multi-turn chats. For hosted providers that support conversation deletion you still manage cleanup through the underlying client when required.\n\nStreaming is straightforward:\n\n``` js\nawait foreach (var update in agent.RunStreamingAsync(question, session))\n{\n    if (!string.IsNullOrEmpty(update.Text))\n        Console.Write(update.Text);\n}\n```\n\nToken limits and other inference options move to `ChatClientAgentRunOptions`:\n\n``` js\nvar options = new ChatClientAgentRunOptions(\n    new ChatOptions { MaxOutputTokens = 800 });\nvar response = await agent.RunAsync(question, session, options);\n```\n\n`[KernelFunction]` methods. They usually need only a `[Description]` attribute.`IChatClient.AsAIAgent(...)` and pass the functions via `await agent.CreateSessionAsync()`.` InvokeAsync` / `InvokeStreamingAsync` to `RunAsync` / `RunStreamingAsync`.` AddKernel` + keyed Agent to keyed You can keep non-agent Semantic Kernel usage (prompt templates, pure function calling via Microsoft.Extensions.AI) running in parallel during the transition. The model-access layer is already shared. If you are weighing which AI layer to standardize on for an existing system, this is the kind of decision I cover in my [AI integration work for .NET teams](https://rahmatafridi.com/ai-integration/).\n\nIf the existing SK agent is stable, has no need for new orchestration features, and the team is mid-release, there is no emergency. Semantic Kernel still receives critical fixes and security patches, so check Microsoft's current support statement and plan around it. Plan the migration for the next feature cycle rather than forcing it into a hotfix window.\n\nMigrating a Semantic Kernel agent to Microsoft Agent Framework removes the Kernel as the center of gravity, simplifies tool registration, and puts you on the package that receives all new investment. The surface area is smaller than many teams expect: most of the work is mechanical once the chat client is in place. Start with one agent (a support-reply agent like the one in my open-source [SupportAgent.NET](https://rahmatafridi.com/supportagent-net/) project is a good candidate), keep the old path behind a feature flag if needed, and move the rest when the first migration is proven in production.\n\nRahmat Afridi is an AI Integration Developer & Senior .NET Developer based in Islamabad, Pakistan. He has been building production .NET systems since 2016, focusing on practical AI integration with ASP.NET Core, Azure, and local models.", "url": "https://wpnews.pro/news/migrating-semantic-kernel-agents-to-microsoft-agent-framework-in-asp-net-core", "canonical_source": "https://dev.to/rahmatafridi/migrating-semantic-kernel-agents-to-microsoft-agent-framework-in-aspnet-core-3d59", "published_at": "2026-10-26 05:03:05+00:00", "updated_at": "2026-10-26 05:13:05.908062+00:00", "lang": "en", "topics": ["ai-agents", "ai-tools", "developer-tools", "agent-protocols", "artificial-intelligence"], "entities": ["Microsoft", "Semantic Kernel", "Microsoft Agent Framework", "AutoGen", "ASP.NET Core", "Azure OpenAI", "OllamaSharp"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/migrating-semantic-kernel-agents-to-microsoft-agent-framework-in-asp-net-core", "markdown": "https://wpnews.pro/news/migrating-semantic-kernel-agents-to-microsoft-agent-framework-in-asp-net-core.md", "text": "https://wpnews.pro/news/migrating-semantic-kernel-agents-to-microsoft-agent-framework-in-asp-net-core.txt", "jsonld": "https://wpnews.pro/news/migrating-semantic-kernel-agents-to-microsoft-agent-framework-in-asp-net-core.jsonld"}}