Microsoft Agent Framework: construindo agentes de IA no .NET

Construindo agentes de IA com o Microsoft Agent Framework no .NET

Nos últimos anos, a maioria das integrações com IA em aplicações corporativas se resumiu a enviar um prompt para um modelo e exibir a resposta. Isso resolve parte do problema, mas não entrega o que o negócio realmente precisa: uma IA capaz de consultar dados reais, executar ações e manter o contexto de uma conversa de forma segura e monitorada.

É exatamente esse o papel dos agentes de IA. E no ecossistema .NET, a Microsoft consolidou suas iniciativas nessa área em uma única ferramenta: o Microsoft Agent Framework.

Neste artigo, vamos construir um agente de atendimento para uma empresa de logística, capaz de consultar pedidos, calcular prazos de entrega e manter o histórico da conversa, com observabilidade via OpenTelemetry. Tudo com exemplos práticos e explicações detalhadas.

O que é o Microsoft Agent Framework?

O Microsoft Agent Framework é um SDK open source (licença MIT) para criar agentes de IA e fluxos com múltiplos agentes em .NET e Python. Ele é o sucessor do Semantic Kernel e do AutoGen, unindo a base corporativa do primeiro com as orquestrações do segundo.

A versão 1.0 foi lançada em abril de 2026, com APIs estáveis e compromisso de suporte de longo prazo. Por ser construído sobre o Microsoft.Extensions.AI, ele segue os padrões que já conhecemos no .NET: injeção de dependência, middleware e configuração.

Com o Agent Framework, é possível:

  • Criar agentes conectados a diferentes provedores: Microsoft Foundry, Azure OpenAI, OpenAI, Anthropic Claude, Amazon Bedrock, Google Gemini e Ollama.
  • Expor métodos C# como ferramentas que o agente decide quando chamar.
  • Manter o histórico de conversas com sessões.
  • Orquestrar múltiplos agentes (sequencial, concorrente, handoff e group chat).
  • Consumir ferramentas via MCP e conversar com agentes de outros frameworks via A2A.
  • Monitorar tudo com OpenTelemetry.

Se você já usa o Semantic Kernel, a Microsoft disponibiliza um guia de migração. Para projetos novos, o Agent Framework é o caminho recomendado.

Instalando o Agent Framework

Para este exemplo, você vai precisar de um projeto no Microsoft Foundry com um modelo publicado (por exemplo, gpt-4o-mini) e do Azure CLI autenticado com az login.

Crie um novo projeto .NET 10 (Console Application) e adicione os pacotes:

dotnet new console -n Logistica.Agente
cd Logistica.Agente

dotnet add package Microsoft.Agents.AI.Foundry --prerelease
dotnet add package Azure.Identity
dotnet add package OpenTelemetry.Exporter.Console

O pacote Microsoft.Agents.AI (núcleo do framework) já está em versão estável, mas o conector do Foundry ainda é publicado como prerelease, por isso o parâmetro --prerelease.

Em seguida, configure as variáveis de ambiente com o endpoint do seu projeto e o nome do modelo:

export AZURE_OPENAI_ENDPOINT="https://seu-projeto.services.ai.azure.com"
export AZURE_OPENAI_DEPLOYMENT_NAME="gpt-4o-mini"

Criando o primeiro agente

Na classe Program.cs, crie o agente com o código abaixo:

using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;

var endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT")
    ?? throw new InvalidOperationException("Configure a variável AZURE_OPENAI_ENDPOINT");
var deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-4o-mini";

AIAgent agent = new AIProjectClient(new Uri(endpoint), new DefaultAzureCredential())
    .AsAIAgent(
        model: deploymentName,
        name: "AgenteLogistica",
        instructions: "Você é um assistente de atendimento de uma empresa de logística. Responda de forma breve e objetiva.");

Console.WriteLine(await agent.RunAsync("Quais informações você precisa para rastrear um pedido?"));

O método AsAIAgent transforma o cliente do Foundry em um AIAgent, a abstração central do framework. As instructions funcionam como o system prompt: definem o papel e os limites do agente.

Para uma experiência de chat mais fluida, você também pode receber a resposta em streaming:

await foreach (var update in agent.RunStreamingAsync("Explique em uma frase o que é logística reversa."))
{
    Console.Write(update);
}

Até aqui, temos apenas um chatbot. O que transforma isso em um agente é a capacidade de agir, e é isso que vamos fazer a seguir.

Adicionando ferramentas ao agente

Ferramentas (function tools) são métodos C# que o agente pode chamar quando julgar necessário. O modelo não executa código: ele decide qual ferramenta chamar e com quais parâmetros, e o framework faz a invocação e devolve o resultado para o modelo.

Vamos considerar o seguinte cenário para o nosso agente de logística:

  • ConsultarPedido: retorna o status de um pedido.
  • CalcularPrazoEntrega: estima o prazo de entrega para um CEP de destino.

Crie a classe PedidoTools.cs:

using System.ComponentModel;

public class PedidoTools
{
    private static readonly Dictionary<string, (string Status, string Destino)> _pedidos = new()
    {
        ["PED-1001"] = ("Em trânsito", "Vitória/ES"),
        ["PED-1002"] = ("Entregue", "São Paulo/SP"),
        ["PED-1003"] = ("Aguardando coleta", "Belo Horizonte/MG")
    };

    [Description("Consulta o status atual de um pedido pelo número.")]
    public string ConsultarPedido(
        [Description("Número do pedido no formato PED-0000.")] string numeroPedido)
    {
        return _pedidos.TryGetValue(numeroPedido.ToUpperInvariant(), out var pedido)
            ? $"Pedido {numeroPedido}: {pedido.Status}, destino {pedido.Destino}."
            : $"Pedido {numeroPedido} não encontrado.";
    }

    [Description("Calcula o prazo estimado de entrega em dias úteis para um CEP de destino.")]
    public int CalcularPrazoEntrega(
        [Description("CEP de destino, somente números.")] string cep)
    {
        // Regra simplificada: CEPs da região Sudeste (0 a 3) têm prazo menor
        return cep.Length > 0 && cep[0] is >= '0' and <= '3' ? 2 : 5;
    }
}

O atributo [Description] é fundamental: é a partir dele que o modelo entende para que serve cada ferramenta e cada parâmetro. Descrições vagas geram chamadas erradas.

Agora registre as ferramentas no agente com o AIFunctionFactory:

using Microsoft.Extensions.AI;

var tools = new PedidoTools();

AIAgent agent = new AIProjectClient(new Uri(endpoint), new DefaultAzureCredential())
    .AsAIAgent(
        model: deploymentName,
        name: "AgenteLogistica",
        instructions: """
            Você é um assistente de atendimento de uma empresa de logística.
            Use as ferramentas disponíveis para consultar pedidos e prazos.
            Nunca invente informações sobre pedidos.
            """,
        tools:
        [
            AIFunctionFactory.Create(tools.ConsultarPedido),
            AIFunctionFactory.Create(tools.CalcularPrazoEntrega)
        ]);

Console.WriteLine(await agent.RunAsync("Qual o status do pedido PED-1001? E qual o prazo para o CEP 29100000?"));

Neste exemplo, o agente identifica que precisa de duas informações, chama as duas ferramentas e monta uma resposta única com o resultado. Em um projeto real, a classe PedidoTools consultaria seu repositório ou sua API via injeção de dependência.

Mantendo o contexto da conversa

Por padrão, cada chamada ao RunAsync é independente. Para que o agente lembre o que foi dito anteriormente, utilizamos uma AgentSession:

AgentSession session = await agent.CreateSessionAsync();

Console.WriteLine("Agente de logística iniciado. Digite 'sair' para encerrar.");

while (true)
{
    Console.Write("\nVocê: ");
    var mensagem = Console.ReadLine();

    if (string.IsNullOrWhiteSpace(mensagem) || mensagem.Equals("sair", StringComparison.OrdinalIgnoreCase))
        break;

    Console.Write("Agente: ");
    await foreach (var update in agent.RunStreamingAsync(mensagem, session))
    {
        Console.Write(update);
    }
    Console.WriteLine();
}

Com a sessão, um diálogo como este passa a funcionar naturalmente:

Você: Qual o status do pedido PED-1003?
Agente: O pedido PED-1003 está aguardando coleta, com destino a Belo Horizonte/MG.

Você: E qual o prazo de entrega para o CEP 30110000?
Agente: Para o CEP 30110000, o prazo estimado é de 2 dias úteis após a coleta.

Na segunda pergunta, o agente sabe que ainda estamos falando do mesmo pedido. Em aplicações web, a sessão pode ser serializada e persistida (por exemplo, no Redis ou no Cosmos DB) para manter o histórico entre requisições. Os detalhes estão na documentação de sessões.

Monitoramento e Observabilidade

Um agente em produção sem observabilidade é uma caixa preta: você não sabe quais ferramentas foram chamadas, quantos tokens foram consumidos nem por que uma resposta saiu errada. O Agent Framework emite traces, logs e métricas seguindo as convenções semânticas de GenAI do OpenTelemetry.

Para habilitar, envolva o agente com o UseOpenTelemetry e configure o tracer provider:

using OpenTelemetry;
using OpenTelemetry.Trace;

const string SourceName = "Logistica.Agente";

using var tracerProvider = Sdk.CreateTracerProviderBuilder()
    .AddSource(SourceName)
    .AddSource("*Microsoft.Extensions.Agents*")
    .AddConsoleExporter() // Em produção: AddOtlpExporter() ou Azure Monitor
    .Build();

AIAgent agentMonitorado = agent
    .AsBuilder()
    .UseOpenTelemetry(sourceName: SourceName, configure: cfg => cfg.EnableSensitiveData = false)
    .Build();

Com isso:

  • Cada execução do agente gera um trace com a duração e o modelo utilizado.
  • As chamadas de ferramentas aparecem como spans filhos, facilitando identificar gargalos.
  • O consumo de tokens fica disponível para acompanhar custos.
  • Os dados podem ser enviados para o Application Insights, Jaeger, Grafana ou para o próprio painel de observabilidade do Foundry.

Atenção ao EnableSensitiveData: quando true, os prompts e as respostas completas são registrados no trace. Isso ajuda no desenvolvimento, mas em produção pode expor dados pessoais de clientes e gerar problemas com a LGPD. Mantenha false fora do ambiente local.

Cuidados para levar o agente para produção

O exemplo acima funciona bem localmente, mas alguns pontos merecem atenção antes do deploy:

  • Credenciais: o DefaultAzureCredential é prático no desenvolvimento, mas em produção prefira o ManagedIdentityCredential, evitando latência e tentativas desnecessárias de autenticação.
  • Ferramentas de escrita: ferramentas que alteram dados (cancelar pedido, emitir reembolso) devem exigir aprovação humana. O framework oferece suporte nativo a aprovação de ferramentas.
  • Menos é mais: quanto mais ferramentas o agente tem, maior a chance de escolher a errada. Prefira agentes especializados com poucas ferramentas bem descritas.
  • Valide os parâmetros: trate tudo que vem do modelo como entrada de usuário. Valide formatos, permissões e limites dentro da própria ferramenta.
  • Dados antes da IA: um agente só é tão bom quanto as APIs e os dados que ele consulta. Se o processo ou a base estiverem desorganizados, o agente vai apenas automatizar o problema.

Vantagens de usar o Microsoft Agent Framework

  • Totalmente integrado ao ecossistema .NET, com os mesmos padrões do ASP.NET Core.
  • Independente de provedor: troque o modelo sem reescrever o agente.
  • APIs estáveis desde a versão 1.0, com suporte de longo prazo.
  • Observabilidade nativa com OpenTelemetry.
  • Suporte a MCP, A2A e orquestração de múltiplos agentes.
  • Open source e com suporte ativo da Microsoft.

Conclusão

O Microsoft Agent Framework simplifica a construção de agentes de IA no .NET. Com poucas linhas de código, conseguimos um agente que consulta dados reais, mantém o contexto da conversa e pode ser monitorado em produção.

Se você ainda está usando o Semantic Kernel ou integrando modelos de IA “na mão” com chamadas HTTP, vale a pena dar uma chance ao Agent Framework. Nos próximos artigos, vamos evoluir este exemplo com orquestração de múltiplos agentes e integração com servidores MCP.

Os detalhes completos deste exemplo você encontra no meu GitHub: https://github.com/hgmauri/sample-agent-framework

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *