Introdução ao Kernel Semântico: Orquestração de IA em C#
Se você está construindo aplicativos .NET e observando a evolução do cenário de IA, provavelmente já se perguntou: qual é a melhor maneira de integrar grandes modelos de linguagem em meus projetos C# sem transformar minha base de código em espaguete? Esse é exatamente o problema que o Kernel Semântico da Microsoft resolve, e depois de passar o último ano construindo aplicativos de produção com ele, posso dizer que ele se tornou uma das ferramentas mais importantes em meu kit de ferramentas para desenvolvedores.
Nesta postagem, explicarei tudo o que você precisa para começar a usar o Kernel Semântico – desde a compreensão dos conceitos básicos até a construção de um assistente de IA do mundo real. Esteja você apenas mergulhando no desenvolvimento de IA ou procurando uma maneira estruturada de orquestrar chamadas LLM em seus aplicativos .NET existentes, este guia tem o que você precisa.
O que é Kernel Semântico?
O Kernel Semântico (SK) é um SDK de código aberto da Microsoft que atua como uma camada de orquestração entre o código do seu aplicativo e grandes modelos de linguagem como GPT-4o, Azure OpenAI ou outros serviços de IA. Pense nele como um middleware leve que permite combinar código C# tradicional com recursos de IA de uma forma limpa e combinável.
Mas por que não chamar diretamente a API OpenAI? É absolutamente possível – e para casos de uso simples, tudo bem. Mas o momento em que você precisa:
- Deixe a IA decidir quais funções chamar com base na entrada do usuário
- Combine várias chamadas de IA com código tradicional em um pipeline
- Adicione memória e contexto para que a IA se lembre de interações anteriores
- Crie agentes de várias etapas que raciocinam em tarefas complexas
…você se verá reinventando a roda. O Kernel Semântico oferece tudo isso pronto para uso, com suporte .NET de primeira classe, integração de injeção de dependência e uma arquitetura de plug-in que parece natural para qualquer desenvolvedor C#.
O projeto está no GitHub no repositório microsoft/semantic-kernel e possui SDKs para C#, Python e Java. O SDK C# é o mais maduro e é nele que nos concentraremos aqui.
Conceitos Básicos
Antes de escrevermos qualquer código, vamos entender os blocos de construção.
O Núcleo
O Kernel é o objeto central no Kernel Semântico. É o orquestrador – aquilo que une seus serviços, plug-ins e configuração de IA. Você cria um, registra seus serviços e plug-ins nele e depois o usa para executar prompts ou invocar funções. Se você estiver familiarizado com injeção de dependência no ASP.NET Core, o Kernel parecerá muito familiar — é essencialmente um contêiner de serviço com superpoderes de IA.
Plug-ins e funções
Um plugin é uma coleção de funções relacionadas que o Kernel pode invocar. As funções vêm em dois sabores:
- Funções de prompt — definidas como modelos de linguagem natural que são enviados ao LLM
- Funções nativas — métodos C# regulares decorados com atributos que o Kernel pode descobrir e chamar
Por exemplo, você pode ter um WeatherPlugin com uma função nativa GetCurrentWeather(string city) e uma função de prompt que resume os dados meteorológicos de maneira amigável.### Conectores AI
Os conectores são a forma como o Kernel Semântico se comunica com os serviços de IA. Os mais comuns são:
AzureOpenAIChatCompletion— para serviço Azure OpenAIOpenAIChatCompletion— para API da OpenAI diretamente- Incorporação de conectores para pesquisa de vetores e memória
Você os registra no Kernel na inicialização e todo o resto funciona.
Configurando seu projeto
Vamos sujar as mãos. Comece criando um novo aplicativo de console:
dotnet new console -n SemanticKernelDemo
cd SemanticKernelDemo
Agora adicione os pacotes NuGet do Kernel Semântico:
dotnet add package Microsoft.SemanticKernel
dotnet add package Microsoft.SemanticKernel.Connectors.AzureOpenAI
Se você estiver usando o OpenAI diretamente em vez do Azure OpenAI:
dotnet add package Microsoft.SemanticKernel.Connectors.OpenAI
Para suporte de memória e incorporações (usaremos isso mais tarde):
dotnet add package Microsoft.SemanticKernel.Plugins.Memory
dotnet add package Microsoft.Extensions.VectorData.Abstractions
Seu .csproj deve ser direcionado ao .NET 8 ou posterior. As versões mais recentes do Semantic Kernel aproveitam ao máximo os recursos modernos do .NET.
Seu primeiro kernel
Vamos começar com o exemplo mais simples possível: criar um Kernel, conectá-lo a um serviço de IA e fazer uma pergunta.
using Microsoft.SemanticKernel;
// Build the kernel with Azure OpenAI
var builder = Kernel.CreateBuilder();
builder.AddAzureOpenAIChatCompletion(
deploymentName: "gpt-4o",
endpoint: "https://your-resource.openai.azure.com/",
apiKey: "your-api-key"
);
var kernel = builder.Build();
// Invoke a simple prompt
var result = await kernel.InvokePromptAsync(
"Explain dependency injection in C# in three sentences."
);
Console.WriteLine(result);
Se você estiver usando o OpenAI diretamente, troque o registro do serviço:
builder.AddOpenAIChatCompletion(
modelId: "gpt-4o",
apiKey: "your-openai-api-key"
);
É isso. Execute-o e você obterá uma explicação concisa sobre injeção de dependência. Mas isso está apenas arranhando a superfície.
Usando modelos de prompt
Os modelos de prompt permitem parametrizar seus prompts com variáveis usando sintaxe no estilo Handlebars:
var prompt = """
You are a technical writer. Write a brief summary of {{$topic}}
aimed at developers with {{$experienceLevel}} experience.
Keep it under 200 words.
""";
var function = kernel.CreateFunctionFromPrompt(prompt);
var arguments = new KernelArguments
{
["topic"] = "gRPC in .NET",
["experienceLevel"] = "intermediate"
};
var result = await kernel.InvokeAsync(function, arguments);
Console.WriteLine(result);
É aqui que o Kernel Semântico começa a brilhar – você pode definir modelos de prompt reutilizáveis, versioná-los e compô-los em fluxos de trabalho maiores.
Plugins e funções nativas
Os plug-ins são onde o Kernel Semântico preenche a lacuna entre a IA e seu código C# existente. Uma função nativa é apenas um método regular que você expõe ao Kernel.
using Microsoft.SemanticKernel;
using System.ComponentModel;
public class TimePlugin
{
[KernelFunction("get_current_time")]
[Description("Gets the current date and time in UTC")]
public string GetCurrentTime()
{
return DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss UTC");
}
[KernelFunction("get_time_in_timezone")]
[Description("Gets the current time in a specific timezone")]
public string GetTimeInTimezone(
[Description("The IANA timezone identifier, e.g. 'America/New_York'")] string timezone)
{
var tz = TimeZoneInfo.FindSystemTimeZoneById(timezone);
var time = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, tz);
return time.ToString("yyyy-MM-dd HH:mm:ss");
}
}
Observe os atributos [KernelFunction] e [Description]. Eles são críticos – as descrições são o que a IA lê para entender quando e como chamar suas funções. Boas descrições fazem a diferença entre uma IA que usa suas ferramentas de maneira eficaz e outra que é confusa.
Registre o plugin em seu kernel:
var builder = Kernel.CreateBuilder();
builder.AddAzureOpenAIChatCompletion(
deploymentName: "gpt-4o",
endpoint: "https://your-resource.openai.azure.com/",
apiKey: "your-api-key"
);
builder.Plugins.AddFromType<TimePlugin>();
var kernel = builder.Build();
Você também pode construir plugins mais complexos que injetam serviços. Como o Kernel Semântico se integra ao Microsoft.Extensions.DependencyInjection, seus plug-ins podem receber dependências de construtor como qualquer outro serviço:
public class OrderPlugin
{
private readonly IOrderRepository _repository;
public OrderPlugin(IOrderRepository repository)
{
_repository = repository;
}
[KernelFunction("get_order_status")]
[Description("Retrieves the status of an order by its ID")]
public async Task<string> GetOrderStatus(
[Description("The order ID to look up")] string orderId)
{
var order = await _repository.GetByIdAsync(orderId);
return order is null
? $"No order found with ID {orderId}"
: $"Order {orderId}: {order.Status}, placed on {order.CreatedAt:d}";
}
}
Chamada de função e invocação automática
É aqui que as coisas ficam realmente interessantes. Com a chamada de função (também conhecida como chamada de ferramenta), você permite que o modelo de IA decida quais das funções registradas chamar com base no contexto da conversa. O modelo não executa código — ele retorna uma solicitação estruturada dizendo “Quero chamar a função X com esses argumentos” e o Kernel trata da invocação real.
Veja como ativar a chamada automática de função:
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Connectors.OpenAI;
var builder = Kernel.CreateBuilder();
builder.AddAzureOpenAIChatCompletion(
deploymentName: "gpt-4o",
endpoint: "https://your-resource.openai.azure.com/",
apiKey: "your-api-key"
);
builder.Plugins.AddFromType<TimePlugin>();
builder.Plugins.AddFromType<WeatherPlugin>();
var kernel = builder.Build();
// Enable automatic function calling
var settings = new OpenAIPromptExecutionSettings
{
FunctionChoiceBehavior = FunctionChoiceBehavior.Auto()
};
var result = await kernel.InvokePromptAsync(
"What time is it in Tokyo and what's the weather like there?",
new KernelArguments(settings)
);
Console.WriteLine(result);
Com FunctionChoiceBehavior.Auto(), o Kernel irá:
- Envie seu prompt para a IA junto com descrições de todas as funções disponíveis
- A IA decide que precisa ligar para
get_time_in_timezoneeget_weather - O Kernel executa automaticamente essas funções
- Os resultados são enviados de volta para a IA
- A IA compõe uma resposta em linguagem natural usando os resultados da funçãoEsse loop pode acontecer várias vezes em uma única invocação — a IA pode chamar várias funções em sequência para reunir todas as informações necessárias. Você também pode usar
FunctionChoiceBehavior.Required()para forçar a IA a chamar pelo menos uma função ou fornecer uma lista específica de funções que ela pode usar.
Conclusão do bate-papo com histórico
Para aplicativos de conversação, você desejará usar o ChatCompletionService diretamente com um objeto ChatHistory:
using Microsoft.SemanticKernel.ChatCompletion;
var chatService = kernel.GetRequiredService<IChatCompletionService>();
var history = new ChatHistory();
history.AddSystemMessage("""
You are a helpful developer assistant. You have access to tools
for checking the time and weather. Be concise and friendly.
""");
while (true)
{
Console.Write("You: ");
var input = Console.ReadLine();
if (string.IsNullOrWhiteSpace(input)) break;
history.AddUserMessage(input);
var response = await chatService.GetChatMessageContentAsync(
history,
executionSettings: settings,
kernel: kernel
);
history.AddAssistantMessage(response.Content ?? "");
Console.WriteLine($"Assistant: {response.Content}");
}
Isso fornece um chatbot totalmente interativo que mantém o histórico de conversas e pode chamar seus plug-ins conforme necessário.
Memória e incorporações
Um dos padrões mais poderosos em aplicativos de IA é Retrieval-Augmented Generation (RAG) — dando à IA acesso aos seus próprios dados, incorporando-os no espaço vetorial e recuperando pedaços relevantes no momento da consulta.
O Kernel Semântico fornece abstrações para trabalhar com armazenamentos e embeddings de vetores. Veja como configurar um armazenamento de vetores na memória para desenvolvimento:
using Microsoft.Extensions.VectorData;
using Microsoft.SemanticKernel.Connectors.AzureOpenAI;
using Microsoft.SemanticKernel.Embeddings;
#pragma warning disable SKEXP0010
// Create an embedding generation service
var builder = Kernel.CreateBuilder();
builder.AddAzureOpenAITextEmbeddingGeneration(
deploymentName: "text-embedding-ada-002",
endpoint: "https://your-resource.openai.azure.com/",
apiKey: "your-api-key"
);
var kernel = builder.Build();
var embeddingService = kernel.GetRequiredService<ITextEmbeddingGenerationService>();
// Generate embeddings for your documents
var documents = new[]
{
"Semantic Kernel is an open-source SDK for AI orchestration.",
"Azure OpenAI provides enterprise-grade AI models.",
"Plugins in SK allow you to expose C# methods to AI models."
};
var embeddings = await embeddingService.GenerateEmbeddingsAsync(documents);
Para cenários de produção, você armazenaria essas incorporações em um banco de dados vetorial dedicado, como Azure AI Search, Qdrant ou Pinecone. O Kernel Semântico possui conectores para tudo isso através das abstrações Microsoft.Extensions.VectorData.
Um fluxo RAG típico é assim:
- Ingestão: fragmente seus documentos, gere embeddings e armazene-os em um banco de dados vetorial
- Recuperar: quando um usuário fizer uma pergunta, incorpore a consulta e encontre os documentos mais semelhantes
- Gerar: Passe os documentos recuperados como contexto para o LLM junto com a pergunta do usuário
[KernelFunction("search_knowledge_base")]
[Description("Searches the internal knowledge base for relevant information")]
public async Task<string> SearchKnowledgeBase(
[Description("The search query")] string query)
{
var queryEmbedding = await _embeddingService.GenerateEmbeddingAsync(query);
var results = await _vectorStore.SearchAsync(queryEmbedding, limit: 3);
return string.Join("\n\n", results.Select(r => r.Text));
}
Ao expor seu pipeline RAG como uma função de kernel, a IA pode decidir automaticamente quando precisa pesquisar sua base de conhecimento – mantendo a orquestração limpa e deixando o modelo fazer o que faz de melhor.
Planejadores e Agentes
À medida que seus aplicativos de IA se tornam mais complexos, você precisará da IA para planejar e executar tarefas de várias etapas. É aqui que entra a estrutura de agente do Semantic Kernel.
O básico: agente de conclusão de bate-papo
O tipo de agente mais simples envolve um modelo de conclusão de chat com instruções e plug-ins:
using Microsoft.SemanticKernel.Agents;
#pragma warning disable SKEXP0110
var agent = new ChatCompletionAgent
{
Name = "DevAssistant",
Instructions = """
You are a senior .NET developer assistant. Help users with code
reviews, architecture decisions, and debugging. Always provide
code examples when relevant. Use your available tools to look up
current information when needed.
""",
Kernel = kernel,
Arguments = new KernelArguments(settings)
};
var history = new ChatHistory();
history.AddUserMessage("How should I structure a clean architecture project in .NET 8?");
await foreach (var message in agent.InvokeAsync(history))
{
Console.WriteLine(message.Content);
history.Add(message);
}
Colaboração multiagente
As coisas ficam realmente poderosas quando você tem vários agentes trabalhando juntos. O Kernel Semântico oferece suporte a padrões de chat em grupo onde agentes com diferentes especializações colaboram:
#pragma warning disable SKEXP0110
var codeReviewer = new ChatCompletionAgent
{
Name = "CodeReviewer",
Instructions = """
You review C# code for bugs, performance issues, and best practices.
Be specific about what you find and suggest concrete fixes.
""",
Kernel = kernel
};
var securityAuditor = new ChatCompletionAgent
{
Name = "SecurityAuditor",
Instructions = """
You focus exclusively on security vulnerabilities in code.
Look for injection attacks, authentication issues, data exposure,
and OWASP Top 10 violations.
""",
Kernel = kernel
};
var groupChat = new AgentGroupChat(codeReviewer, securityAuditor)
{
ExecutionSettings = new AgentGroupChatSettings
{
TerminationStrategy = new MaximumIterationTerminationStrategy(4)
}
};
groupChat.AddChatMessage(
new ChatMessageContent(AuthorRole.User, "Review this code: ...")
);
await foreach (var message in groupChat.InvokeAsync())
{
Console.WriteLine($"[{message.AuthorName}]: {message.Content}");
}
Esse padrão é extremamente útil para tarefas complexas onde diferentes perspectivas ou áreas de especialização precisam ser consideradas. Cada agente opera com seu próprio prompt de sistema e pode ter seu próprio conjunto de plug-ins.
Exemplo do mundo real: construindo um assistente de documentação de projeto
Vamos unir tudo com um exemplo prático: um assistente de IA que ajuda os desenvolvedores a entender uma base de código lendo arquivos e respondendo perguntas.
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.ChatCompletion;
using Microsoft.SemanticKernel.Connectors.OpenAI;
using System.ComponentModel;
// Define our plugins
public class FileSystemPlugin
{
private readonly string _rootPath;
public FileSystemPlugin(string rootPath)
{
_rootPath = rootPath;
}
[KernelFunction("read_file")]
[Description("Reads the contents of a file from the project directory")]
public async Task<string> ReadFile(
[Description("Relative path to the file")] string path)
{
var fullPath = Path.Combine(_rootPath, path);
if (!File.Exists(fullPath))
return $"File not found: {path}";
var content = await File.ReadAllTextAsync(fullPath);
// Truncate very large files
if (content.Length > 8000)
content = content[..8000] + "\n... [truncated]";
return content;
}
[KernelFunction("list_files")]
[Description("Lists files in a directory, optionally filtered by extension")]
public string ListFiles(
[Description("Relative directory path")] string directory,
[Description("File extension filter like '.cs' or '.json'")] string? extension = null)
{
var fullPath = Path.Combine(_rootPath, directory);
if (!Directory.Exists(fullPath))
return $"Directory not found: {directory}";
var files = Directory.GetFiles(fullPath, "*.*", SearchOption.AllDirectories)
.Select(f => Path.GetRelativePath(_rootPath, f))
.Where(f => extension is null || f.EndsWith(extension))
.Take(50);
return string.Join("\n", files);
}
}
public class DocumentationPlugin
{
[KernelFunction("generate_summary")]
[Description("Generates a structured markdown summary for documentation")]
public string GenerateSummaryTemplate(
[Description("Name of the component")] string componentName,
[Description("Brief description")] string description,
[Description("Key responsibilities as comma-separated values")] string responsibilities)
{
var items = responsibilities.Split(',', StringSplitOptions.TrimEntries);
var bullets = string.Join("\n", items.Select(r => $"- {r}"));
return $"""
## {componentName}
{description}
### Responsibilities
{bullets}
---
*Generated documentation — review and expand as needed.*
""";
}
}
// Wire it all up
var builder = Kernel.CreateBuilder();
builder.AddAzureOpenAIChatCompletion(
deploymentName: "gpt-4o",
endpoint: "https://your-resource.openai.azure.com/",
apiKey: "your-api-key"
);
builder.Plugins.AddFromObject(new FileSystemPlugin("./src"));
builder.Plugins.AddFromType<DocumentationPlugin>();
var kernel = builder.Build();
var chatService = kernel.GetRequiredService<IChatCompletionService>();
var history = new ChatHistory();
history.AddSystemMessage("""
You are a codebase documentation assistant. You help developers understand
projects by reading source files and explaining architecture, patterns,
and design decisions.
When asked about code, use your tools to read the actual files rather
than guessing. Be specific and reference actual code when possible.
Generate documentation artifacts when asked.
""");
var settings = new OpenAIPromptExecutionSettings
{
FunctionChoiceBehavior = FunctionChoiceBehavior.Auto()
};
Console.WriteLine("Documentation Assistant ready. Ask me about your codebase!");
Console.WriteLine("Type 'exit' to quit.\n");
while (true)
{
Console.Write("You: ");
var input = Console.ReadLine();
if (string.IsNullOrWhiteSpace(input) || input.Equals("exit", StringComparison.OrdinalIgnoreCase))
break;
history.AddUserMessage(input);
var response = await chatService.GetChatMessageContentAsync(
history,
executionSettings: settings,
kernel: kernel
);
Console.WriteLine($"\nAssistant: {response.Content}\n");
history.AddAssistantMessage(response.Content ?? "");
}
Este assistente pode:- Liste e leia arquivos do diretório do seu projeto
- Responda a perguntas sobre a base de código lendo arquivos de origem reais
- Gerar documentação em formato markdown
- Mantenha o contexto da conversa para que as perguntas de acompanhamento funcionem naturalmente
A IA decide automaticamente quando ligar para read_file, list_files ou generate_summary com base no que você pergunta. Pergunte “O que o OrderService faz?” e ele lerá o arquivo, analisará e explicará. Peça para “Gerar documentação para o módulo de autenticação” e ele explorará os arquivos, entenderá a estrutura e produzirá um resumo formatado.
Dicas para Produção
Antes de enviar seu aplicativo de Kernel Semântico, aprendi algumas coisas da maneira mais difícil:
Use a injeção de dependência corretamente. Em aplicativos ASP.NET Core, registre o Kernel e os serviços em seu contêiner DI em vez de criá-los in-line:
builder.Services.AddKernel()
.AddAzureOpenAIChatCompletion(
deploymentName: "gpt-4o",
endpoint: configuration["AzureOpenAI:Endpoint"]!,
apiKey: configuration["AzureOpenAI:ApiKey"]!
)
.Plugins.AddFromType<TimePlugin>()
.AddFromType<OrderPlugin>();
Trate de erros normalmente. As chamadas LLM podem falhar, atingir o tempo limite ou retornar resultados inesperados. Envolva suas invocações em blocos try-catch e implemente políticas de repetição com Polly ou os recursos de resiliência integrados.
Monitore o uso de tokens. Cada prompt, cada descrição de função e cada parte do histórico de bate-papo consome tokens. Use filtros para registrar e rastrear o uso:
kernel.FunctionInvocationFilters.Add(new LoggingFilter());
Mantenha as descrições de suas funções precisas. Descrições vagas levam a IA a chamar funções incorretamente. Teste suas descrições perguntando: “Se eu apenas lesse a descrição, saberia exatamente quando e como usar esta função?”
Conclusão
O Kernel Semântico é uma daquelas bibliotecas que muda fundamentalmente a forma como você pensa sobre a construção de aplicativos. Não é apenas um wrapper de API: é uma estrutura de orquestração que permite compor recursos de IA com código tradicional de uma forma que seja sustentável, testável e pronta para produção.
O que mais adoro nele é que respeita o ecossistema .NET. Ele usa padrões que você já conhece – injeção de dependência, atributos, assíncrono/espera, interfaces – e os estende ao mundo da IA. Você não precisa aprender um paradigma completamente novo; você acabou de adicionar IA como outro recurso em seu kit de ferramentas.
Se você está criando aplicativos .NET e ainda não explorou o Kernel Semântico, agora é a hora. O SDK é estável, a comunidade é ativa e os padrões que ele permite — desde a simples orquestração imediata até a colaboração multiagente — estão se tornando habilidades essenciais para os desenvolvedores modernos.
Comece pequeno. Crie um Kernel, registre um plugin e observe a IA chamar seu código. Depois que isso acontecer, você começará a ver oportunidades para adicionar inteligência em todos os lugares dos seus aplicativos.
A documentação oficial e o repositório GitHub são excelentes recursos para continuar sua jornada. Feliz edifício!