Semantic Kernel'den Microsoft Agent Framework'e: Tarihçe, Destek Durumu ve Eski Kodu Taşımak
Semantic Kernel kritik hata ve güvenlik düzeltmesi almaya devam ediyor, ama yeni özellikler Microsoft Agent Framework'e gidiyor; resmi taahhüt MAF GA'den (3 Nisan 2026) sonra en az bir yıl. Tarihçeyi NuGet ve GitHub tarihleriyle kuruyor, eski bir SK agent'ını yerel modelle çalıştırıp MAF'a taşıyor ve eşleme tablosunu çıkarıyoruz.
Sürüm notu: Bu yazıdaki kodlar .NET 10 ile derlenip denenmiştir; Microsoft.SemanticKernel 1.82.0, Microsoft.SemanticKernel.Agents.Core 1.82.0, Microsoft.Agents.AI 1.28.0, Microsoft.Extensions.AI 10.11.0, OllamaSharp 5.5.2 ve Ollama 0.34.4 (qwen3:4b) kullanılmıştır.
Önce Tahmin Et
Ekibe yeni katıldın ve Bookstore'un 2024'te yazılmış sipariş asistanını devraldın. Kod Semantic Kernel (SK) ile yazılmış: bir Kernel, [KernelFunction] işaretli bir plugin, bir ChatCompletionAgent. Yöneticin üç şey soruyor: Bu kod hâlâ destekleniyor mu? Taşımamız gerekiyor mu? Taşırsak ne kadar iş çıkar?
İlk soruya bir blog yazısından ya da forumdan cevap vermek cazip gelebilir. Bu yazıda tarihleri NuGet, GitHub ve Microsoft'un kendi blog yazılarından okuyacağız. Sonra eski asistanı aynı yerel modelle çalıştırıp Microsoft Agent Framework'e (MAF) taşıyacağız. Taşıma, beklediğinden daha kısa sürecek. Ama eski kodu çalıştırırken bir sürprizle karşılaşacağız.
2023'ten 2026'ya: Kim, Ne Zaman, Neden?

Semantic Kernel'in GitHub reposu 27 Şubat 2023'te açıldı. ChatGPT'nin API'si (Application Programming Interface) yeni çıkmıştı. LLM (Large Language Model) çağrısını bir .NET uygulamasına bağlamanın standart bir yolu da yoktu. SK bu boşluğu bir Kernel nesnesiyle doldurdu: servisler (model bağlantıları), plugin'ler ([KernelFunction] işaretli method'lar) ve prompt template'leri aynı yerde toplanıyordu. Modelin bir hedefi adımlara bölmesini sağlayan planner'lar da bu ilk dönemin en çok konuşulan özelliğiydi. .NET paketi 18 Aralık 2023'te 1.0.1 ile stabil oldu.
Aynı yıl Microsoft Research'ten AutoGen çıktı (repo: Ağustos 2023). AutoGen birden fazla agent'ın birbiriyle konuşarak bir işi çözdüğü multi-agent senaryolarını deniyordu. Böylece Microsoft'un elinde iki ayrı ekosistem oluştu. SK kurumsal tarafı (Dependency Injection, telemetry, filter'lar, tip güvenliği) temsil ediyordu, AutoGen ise agent orkestrasyonu deneylerini.
Üçüncü parça .NET ekibinden geldi. Microsoft.Extensions.AI (MEAI) 8 Ekim 2024'te preview olarak NuGet'e çıktı ve 16 Mayıs 2025'te 9.5.0 ile stabil oldu. MEAI bir framework değil, ortak tipler katmanıdır: IChatClient, ChatMessage, AIFunction, IEmbeddingGenerator. Bu serinin bütün yazıları bu katmanın üstünde durdu. SK de zamanla kendi tiplerinin yanında bu tipleri kullanmaya başladı.
Microsoft Agent Framework (MAF) bu üç çizginin birleştiği yer. İlk preview paketleri 1 Ekim 2025'te NuGet'e çıktı. Release Candidate Şubat 2026'da geldi ve 3 Nisan 2026'da 1.0 ile GA (General Availability) oldu. MAF dokümantasyonu çerçeveyi açıkça "SK ve AutoGen'in doğrudan devamı, aynı ekipler tarafından" diye tanımlıyor. SK'nın GitHub README'si de bugün "Semantic Kernel is now Microsoft Agent Framework" cümlesiyle açılıyor. AutoGen'in README'si ise projenin arşivlendiğini, hata ve güvenlik düzeltmesi almadığını yazıyor.
Bu süreçte SK'nın bazı parçaları da ayrıldı. Planner'lar (Handlebars ve OpenAI planner) Mayıs 2025'te function calling lehine deprecated oldu. Vector store connector'ları Semantic Kernel'e bağımlı olmadıkları için Temmuz 2026'da CommunityToolkit.VectorData.* adıyla v1 oldu. Bu serinin "Microsoft.Extensions.VectorData" yazısında bu paketleri kullandık.
Eski Kod: Bir Semantic Kernel Agent'ı
Devraldığımız asistanın plugin'i ve filter'ı tipik bir SK kodu. Paketler: Microsoft.SemanticKernel ve Microsoft.SemanticKernel.Agents.Core 1.82.0.
public sealed class OrderPlugin
{
[KernelFunction, Description("Returns the shipping status of a Bookstore order.")]
public string GetOrderStatus([Description("The order number")] int orderId) =>
orderId == 1042 ? "Shipped on 2026-11-06, 2 items, tracking BKS-1042." : "Order not found.";
}
public sealed class LoggingFilter : IFunctionInvocationFilter
{
public async Task OnFunctionInvocationAsync(FunctionInvocationContext context, Func<FunctionInvocationContext, Task> next)
{
Console.WriteLine($"[filter] {context.Function.PluginName}.{context.Function.Name}({string.Join(", ", context.Arguments.Select(a => $"{a.Key}={a.Value}"))})");
await next(context);
}
}
Orijinal proje modele SK'nın bulut connector'ıyla bağlanıyordu. Bu yazıda bulut sağlayıcısıyla çalışmadığımız için model bağlantısını yerel Ollama'ya çevirmemiz gerekti. Bunun için SK'nın MEAI köprüsünü kullandık: OllamaSharp'ın IChatClient'ını AsChatCompletionService() ile SK'nın IChatCompletionService'ine çevirdik. İlk deneme şöyleydi:
IKernelBuilder kernelBuilder = Kernel.CreateBuilder();
kernelBuilder.Services.AddSingleton<IChatCompletionService>(
new OllamaApiClient(
new HttpClient { BaseAddress = new Uri("http://localhost:11434"), Timeout = TimeSpan.FromMinutes(10) },
"qwen3:4b").AsChatCompletionService());
kernelBuilder.Services.AddSingleton<IFunctionInvocationFilter, LoggingFilter>();
kernelBuilder.Plugins.AddFromType<OrderPlugin>("Orders");
Kernel kernel = kernelBuilder.Build();
> Where is my order 1042?
> How many items were in it?
İşte açılışta bahsettiğimiz sürpriz. Program hata vermeden çalıştı ama iki cevap da boş ve [filter] satırı hiç yazılmadı. Boş cevap ve hiç tetiklenmeyen filter, modelin bir tool isteği ürettiğini ama kimsenin onu çalıştırmadığını gösteriyor: agent'ın elinde metinsiz bir mesaj kaldı. Aşağıdaki düzeltmeden sonra aynı soruda filter tetikleniyor. SK'nın kendi connector'larında function calling döngüsü connector'ın içindeydi. Bir IChatClient köprüden geçtiğinde ise döngüyü pipeline'a senin eklemen gerekiyor. SK bunun için UseKernelFunctionInvocation() extension'ını sunuyor. XML (Extensible Markup Language) dokümantasyonuna göre bu, FunctionInvokingChatClient'ın KernelFunction'ları ve SK filter'larını tanıyan bir türevini (KernelFunctionInvokingChatClient) pipeline'a ekliyor:
using Bookstore.Assistant;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents;
using Microsoft.SemanticKernel.ChatCompletion;
using OllamaSharp;
IKernelBuilder kernelBuilder = Kernel.CreateBuilder();
IChatClient ollama = new ChatClientBuilder(new OllamaApiClient(
new HttpClient { BaseAddress = new Uri("http://localhost:11434"), Timeout = TimeSpan.FromMinutes(10) },
"qwen3:4b"))
.UseKernelFunctionInvocation()
.Build();
kernelBuilder.Services.AddSingleton<IChatCompletionService>(ollama.AsChatCompletionService());
kernelBuilder.Services.AddSingleton<IFunctionInvocationFilter, LoggingFilter>();
kernelBuilder.Plugins.AddFromType<OrderPlugin>("Orders");
Kernel kernel = kernelBuilder.Build();
ChatCompletionAgent agent = new()
{
Name = "BookstoreAssistant",
Instructions = "You are the Bookstore assistant. Use tools for order questions. Answer in one short sentence.",
Kernel = kernel,
Arguments = new KernelArguments(new PromptExecutionSettings
{
FunctionChoiceBehavior = FunctionChoiceBehavior.Auto(),
}),
};
AgentThread thread = new ChatHistoryAgentThread();
foreach (string question in new[] { "Where is my order 1042?", "How many items were in it?" })
{
Console.WriteLine($"> {question}");
await foreach (AgentResponseItem<ChatMessageContent> item in agent.InvokeAsync(question, thread))
{
Console.WriteLine(item.Message.Content);
thread = item.Thread;
}
}
> Where is my order 1042?
[filter] Orders.GetOrderStatus(orderId=1042)
Your order 1042 was shipped on November 6, 2026, with 2 items and tracking number BKS-1042.
> How many items were in it?
Your order 1042 contained 2 items.
Şimdi tool çalışıyor, filter tetikleniyor ve ikinci soru ilk sorunun bağlamıyla cevaplanıyor. Bu, taşımanın başlangıç noktası. Koddaki SK'ya özgü parçalar: Kernel ve builder'ı, plugin kaydı, [KernelFunction], KernelArguments + FunctionChoiceBehavior, ChatHistoryAgentThread ve InvokeAsync'in her mesaj için bir AgentResponseItem döndüren akışı.
Aynı Agent, Agent Framework ile
Aynı davranışı MAF ile yazalım. Paket: Microsoft.Agents.AI 1.28.0. Tool class'ından [KernelFunction] kalkıyor, method gövdesi aynı kalıyor:
public sealed class OrderTools
{
[Description("Returns the shipping status of a Bookstore order.")]
public string GetOrderStatus([Description("The order number")] int orderId) =>
orderId == 1042 ? "Shipped on 2026-11-06, 2 items, tracking BKS-1042." : "Order not found.";
}
using Bookstore.Assistant;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using OllamaSharp;
IChatClient chatClient = new OllamaApiClient(
new HttpClient { BaseAddress = new Uri("http://localhost:11434"), Timeout = TimeSpan.FromMinutes(10) },
"qwen3:4b");
OrderTools tools = new();
AIAgent agent = chatClient
.AsAIAgent(
instructions: "You are the Bookstore assistant. Use tools for order questions. Answer in one short sentence.",
name: "BookstoreAssistant",
tools: [AIFunctionFactory.Create(tools.GetOrderStatus)])
.AsBuilder()
.Use(async (agent, context, next, cancellationToken) =>
{
// Eski IFunctionInvocationFilter'ın karşılığı: function invocation middleware
Console.WriteLine($"[middleware] {context.Function.Name}({string.Join(", ", context.Arguments.Select(a => $"{a.Key}={a.Value}"))})");
return await next(context, cancellationToken);
})
.Build();
AgentSession session = await agent.CreateSessionAsync();
foreach (string question in new[] { "Where is my order 1042?", "How many items were in it?" })
{
Console.WriteLine($"> {question}");
AgentResponse response = await agent.RunAsync(question, session);
Console.WriteLine(response.Text);
}
> Where is my order 1042?
[middleware] GetOrderStatus(orderId=1042)
Your order #1042 is shipped on 2026-11-06 with 2 items and tracking number BKS-1042.
> How many items were in it?
Your order #1042 contained 2 items.
Davranış aynı, cümleler küçük farklarla değişiyor; aynı model, ama artık farklı bir framework'ün ürettiği prompt'la çalışıyor. Kod ise belirgin biçimde kısaldı. Kernel yok, plugin kaydı yok, FunctionChoiceBehavior yok: ChatClientAgent, client'ta bir FunctionInvokingChatClient yoksa kendisi ekliyor. Yukarıdaki SK sürümünde yaşadığımız "tool hiç çalışmadı" sorunu bu yüzden burada oluşmuyor. Filter middleware oldu. Thread'i biz oluşturmak yerine agent'a CreateSessionAsync ile oluşturtuyoruz. InvokeAsync'in mesaj mesaj akışı yerine RunAsync tek bir AgentResponse döndürüyor. Tool çağrısı mesajları da içinde, metni Text'ten okuyoruz.
Eşleme Tablosu
Microsoft Learn'deki "Semantic Kernel to Microsoft Agent Framework Migration Guide" sayfası farkları on bir başlıkta topluyor. Bookstore asistanında karşılaştığımız eşleşmeler şunlar:
| Semantic Kernel | Agent Framework | Not |
|---|---|---|
Microsoft.SemanticKernel, .Agents | Microsoft.Agents.AI, Microsoft.Extensions.AI | Mesaj ve content tipleri MEAI'den gelir |
Kernel + Plugins.AddFromType<T>() | Yok; tool'lar agent'a doğrudan verilir | Kernel nesnesi tamamen kalkar |
[KernelFunction] | AIFunctionFactory.Create(...) + [Description] | Attribute zorunlu değil |
ChatCompletionAgent, OpenAIAssistantAgent, AzureAIAgent | ChatClientAgent (AsAIAgent) | Tek agent tipi, provider IChatClient ile seçilir |
AgentThread, ChatHistoryAgentThread | AgentSession (CreateSessionAsync) | Session'ı agent üretir |
InvokeAsync / InvokeStreamingAsync | RunAsync / RunStreamingAsync | Non-streaming tek AgentResponse döner |
KernelArguments + PromptExecutionSettings | ChatOptions, ChatClientAgentRunOptions | MEAI options tipleri |
FunctionChoiceBehavior.Auto() | Varsayılan davranış | ChatClientAgent gerekirse function invocation ekler |
IFunctionInvocationFilter, IAutoFunctionInvocationFilter | Function invocation middleware | AsBuilder().Use(...) |
services.AddKernel() + keyed Agent | AddKeyedSingleton<AIAgent> ya da AddAIAgent | Hosting için bu serinin bir önceki yazısı |
Microsoft.SemanticKernel.Connectors.* (vector store) | CommunityToolkit.VectorData.* | Microsoft.Extensions.VectorData abstraction'ı |
Adım Adım Taşıma
Gerçek bir projede taşıma tek commit'te bitmez. Bookstore asistanı için işe yarayan sıra şöyle:
Birinci adım, model bağlantısını IChatClient'a çekmek. SK projesi hâlâ AddOpenAIChatCompletion gibi SK connector'larıyla model bağlıyorsa önce bunu MEAI provider'ına çevir ve SK'ya AsChatCompletionService() ile ver. SK hâlâ çalışır, ama model tarafı artık MAF'ın da kullanacağı tiptedir. Yukarıda gördüğümüz gibi bu adımda UseKernelFunctionInvocation()'ı unutma ve tool'ların gerçekten çalıştığını bir testle doğrula.
İkinci adım, plugin'leri sade class'lara çevirmek. [KernelFunction] attribute'u kalkar, [Description] kalır. Method'ların gövdesi değişmez; değişen tek şey kaydın yeri. Bu serinin "IChatClient Kullanan Kodu Test Etmek" yazısındaki gibi tool'ları modelden bağımsız birim testleriyle koru.
Üçüncü adım, filter'ları middleware'e taşımak. IFunctionInvocationFilter function invocation middleware'ine karşılık gelir. IPromptRenderFilter'ın birebir karşılığı yok, çünkü MAF'ta prompt template render adımı yok; benzer kontroller agent run ya da IChatClient middleware'inde yapılır. Bu serinin "Agent Framework'te Middleware, Context Provider ve Session Saklama" yazısındaki GuardRun ve AuthorizeOrders örnekleri bu adımın şablonu.
Dördüncü adım, agent'ı ve thread'i değiştirmek. ChatCompletionAgent yerine AsAIAgent, ChatHistoryAgentThread yerine CreateSessionAsync. Thread'leri veritabanında saklıyorsan saklama biçimi değişir. MAF session'ı SerializeSessionAsync ile JSON (JavaScript Object Notation) olarak verir, eski thread kayıtlarını ise bir kerelik bir dönüşüm script'iyle ya da "eski sohbetler salt okunur" kararıyla ele alman gerekir.
Beşinci adım, DI (Dependency Injection) kaydını ve hosting'i değiştirmek ve SK paketlerini projeden çıkarmak. Paketler gittiğinde derleyici sana kalan son referansları gösterir.
Destek Durumu: Resmi Kaynaktan Oku
Şimdi açılıştaki ilk soruya, yani "SK hâlâ destekleniyor mu?" sorusuna dönelim. Bu sorunun cevabını üçüncü taraf bir blogdan almak cazip ama yanlış olur. Birincil kaynak, Microsoft'un Semantic Kernel blogunda 7 Ekim 2025'te yayımlanan "Semantic Kernel and Microsoft Agent Framework" yazısı. Yazıya göre ekip kritik hataları ve güvenlik sorunlarını düzeltmeye devam edecek. Yeni özelliklerin büyük çoğunluğu ise MAF için geliştirilecek. Destek süresi iki koşula bağlanıyor: SK'yı kullanan önemli sayıda geliştirici olduğu sürece ve MAF GA olduktan sonra en az bir yıl.
MAF 3 Nisan 2026'da GA olduğuna göre bu taahhüdün alt sınırı Nisan 2027 civarına düşüyor. Bu tarih Microsoft'un ilan ettiği bir "son destek günü" değil, iki resmi tarihten yapılmış bir çıkarım; blogda yazan şey "en az bir yıl". Aynı yazı mevcut projeler için SK kullanmaya devam etmenin "tamamen uygun" olduğunu, yeni projeler için ise MAF ile başlanmasını öneriyor.
Pratik sonuç şu: SK'daki bir uygulama yarın bozulmaz, ama yeni özellik de almaz. .NET'in sürüm desteğinde olduğu gibi bir takvim tablosu da yok. Bu yüzden taşıma kararını "ne zaman zorunda kalırız" yerine "bir sonraki büyük değişiklikte" diye planlamak daha sağlıklı. Destek durumunu da her çeyrekte SK reposunun README'sinden ve Microsoft DevBlogs'tan yeniden kontrol et.
Üretimde Dikkat
- Taşımadan önce davranışı sabitle. Eski ve yeni kodun aynı soruya aynı tool çağrılarını yaptığını, modelden bağımsız testlerle ve küçük bir evaluation setiyle doğrula. Bu yazıda bile iki sürüm aynı tool'u aynı argümanla çağırdı, ama cümleler farklıydı.
- Telemetry adları değişir. SK'nın kendi activity source'ları ve log kategorileri, MAF'ta MEAI'nin GenAI span'lerine dönüşür. Dashboard ve alarmlarını taşımanın bir parçası olarak güncelle.
- Saklanan thread'ler en riskli kısım. Bir SK
ChatHistory'si ile bir MAF session JSON'u aynı biçimde değil. Geçiş döneminde iki biçimi de okuyabilen bir katman ya da eski konuşmaları kapatma kararı gerekir. - MAF neredeyse her hafta bir minor sürüm çıkarıyor (Ekim ve Kasım 2026'da 1.24'ten 1.28'e). Taşıdıktan sonra da paket güncellemelerini planlı yap, sürümleri sabitle ve her güncellemede testleri çalıştır.
Sık Düşülen Tuzaklar
Birinci tuzak, SK'nın destek süresini bir blogdan ya da forum cevabından okumak. Yukarıda gördüğümüz gibi resmi taahhüt "en az bir yıl" ve bir koşula bağlı. "SK 2026'da bitiyor" ya da "SK hiç bitmeyecek" gibi kesin cümleler birincil kaynakta yok.
İkincisi, planner tabanlı kodu birebir taşımaya çalışmak. SK'nın Handlebars ve OpenAI planner'ları Mayıs 2025'te deprecated oldu. MAF'ta bunların karşılığı olan bir "planner" API'si yok. Modelin kendisi tool çağırarak adım adım ilerliyor. Akış gerçekten belirli adımlardan oluşuyorsa da bu iş workflow'ların. Planner kodunu taşımak yerine önce "bu iş bir agent mı, bir workflow mu, yoksa düz bir fonksiyon mu?" sorusunu sor.
Üçüncüsü, bu yazıdaki sürprizin kendisi: SK'yı bir IChatClient köprüsüyle kullanırken function invocation'ı eklemeyi unutmak. Program hata vermez, tool çalışmaz, cevap boş döner. Taşımanın ilk adımında bu köprüyü kurduğunda, tool'un gerçekten çalıştığını doğrulayan bir test yaz.
Dördüncüsü, iki framework'ü uzun süre yan yana tutmak. Geçiş döneminde aynı uygulamada hem SK hem MAF olabilir. Ama iki ayrı telemetry, iki ayrı tool kaydı ve iki ayrı session biçimi bakım yükünü ikiye katlar. Taşımayı modül modül yap, her modülü tamamen bitir.
Son olarak, AutoGen'den gelen kodu SK koduyla aynı kefeye koymak. AutoGen'in README'si projenin arşivlendiğini ve güvenlik düzeltmesi bile almadığını söylüyor; SK'nın aksine bir destek taahhüdü yok. AutoGen kullanan bir projen varsa taşıma önceliği daha yüksek. MAF'ın AutoGen için ayrı bir migration rehberi var.
Küçük Bir Deneme
★☆☆ Legacy projede UseKernelFunctionInvocation() yerine MEAI'nin UseFunctionInvocation()'ını kullan. Tool çalışıyor mu, [filter] satırı yazılıyor mu? Neden?
★★☆ LoggingFilter'ı IAutoFunctionInvocationFilter olarak yeniden yaz ve context.Terminate = true ile ilk tool çağrısından sonra döngüyü durdur. Aynı davranışı MAF middleware'iyle nasıl kurarsın, ve dokümantasyonun bu konudaki uyarısı neden önemli?
★★★ Legacy projeye ChatHistoryAgentThread'in içeriğini JSON'a yazan bir adım ekle. Sonra bu JSON'u okuyup bir MAF AgentSession'a aktaran bir dönüştürücü yaz: SK'nın ChatMessageContent'lerini MEAI ChatMessage'larına çevir ve agent.RunAsync ile konuşmaya devam et. Hangi bilgi kayboluyor?
Bu yazıyla .NET ile Yapay Zeka serisi bitiyor. On dört yazıda bir IChatClient çağrısından başlayıp middleware pipeline'ına, ASP.NET Core entegrasyonuna, streaming'e, sohbet geçmişine, tool calling'e, maliyete, telemetry'ye, vector store'a, teste ve evaluation'a, oradan da Microsoft Agent Framework ile agent'lara ve onları host etmeye geldik. Bütün örnekler yerel bir modelle, gerçek çıktılarıyla koşuldu; küçük modelin hataları da dahil. Sıradaki adım bu temelin üstüne kurulacak iki seri: dokümanlarla cevap veren sistemleri kuracağımız RAG (Retrieval-Augmented Generation) serisi ve agent pattern'lerini, multi-agent workflow'ları ve MCP'yi (Model Context Protocol) işleyeceğimiz AI (Artificial Intelligence) Agent'ları ve MCP serisi.