Observabilidade de agentes e workflows no Microsoft Agent Framework

A observabilidade no Agent Framework é o conjunto de traces, logs e métricas que mostra o que seus agentes de IA realmente fazem durante a execução. Construir sistemas com agentes exige mais do que conectar modelos e ferramentas, porque você precisa enxergar gargalos, rastrear erros e confirmar que tudo se comporta como esperado em produção.

O Microsoft Agent Framework oferece esse suporte de forma nativa. Ele se integra ao padrão OpenTelemetry e às convenções semânticas GenAI para emitir traces, logs e métricas sem código extra de instrumentação.

Neste artigo, você vai ver como habilitar esses recursos em agentes individuais e em workflows com vários executores. Além disso, vamos explorar o suporte a tracing na DevUI, a interface de desenvolvimento do framework.

Por que a observabilidade no Agent Framework importa

Um agente de IA toma decisões em tempo de execução. Ele escolhe quando chamar o modelo, qual ferramenta usar e quantas iterações fazer até chegar a uma resposta.

Por isso, o comportamento de um agente não fica evidente apenas lendo o código. Sem telemetria, um erro de ferramenta ou uma resposta lenta do modelo vira um mistério difícil de reproduzir.

A observabilidade no Agent Framework resolve esse problema expondo cada etapa como um span. Assim, você consegue medir a latência de cada chamada, contar tokens consumidos e localizar a etapa exata em que algo falhou.

Se você ainda está conhecendo o framework, vale começar pela visão geral do Microsoft Agent Framework antes de seguir com a instrumentação.

Observabilidade de agentes no Agent Framework

O primeiro nível da observabilidade no Agent Framework acontece no agente individual. É ali que ficam as chamadas ao modelo de linguagem e a execução das ferramentas.

Integração da observabilidade no Agent Framework com OpenTelemetry

A observabilidade no Agent Framework usa o OpenTelemetry como base de toda a estratégia. O framework emite traces, logs e métricas seguindo as OpenTelemetry GenAI Semantic Conventions, o que garante compatibilidade com os principais backends de telemetria do mercado.

Na prática, essa escolha facilita a integração com ferramentas como Azure Monitor, Jaeger, Zipkin e Datadog. Você não precisa de adaptações específicas para cada plataforma, porque todas entendem o mesmo protocolo.

Além disso, as convenções GenAI padronizam nomes de atributos como modelo, provedor e uso de tokens. Dessa forma, um painel montado para um agente funciona para qualquer outro que siga o mesmo padrão.

Habilitando a observabilidade em C#

O ponto de entrada para instrumentar um agente em C# começa pelo cliente de chat. Nesse exemplo, o cliente usa Azure OpenAI com suporte a OpenTelemetry:

var instrumentedChatClient = new AzureOpenAIClient(new Uri(endpoint), new DefaultAzureCredential())
    .GetChatClient(deploymentName)
    .AsIChatClient()
    .AsBuilder()
    .UseOpenTelemetry(sourceName: "MyApplication", configure: (cfg) => cfg.EnableSensitiveData = true)
    .Build();

O método AsIChatClient converte o cliente para a abstração IChatClient do Microsoft.Extensions.AI. Em seguida, o UseOpenTelemetry adiciona a camada de instrumentação ao pipeline do cliente.

Com o cliente instrumentado, você cria o agente e ativa a emissão de telemetria com o método WithOpenTelemetry:

var agent = new ChatClientAgent(
    instrumentedChatClient,
    name: "OpenTelemetryDemoAgent",
    instructions: "You are a helpful assistant that provides concise and informative responses.",
    tools: [AIFunctionFactory.Create(GetWeatherAsync)]
).WithOpenTelemetry(sourceName: "MyApplication", enableSensitiveData: true);

Um detalhe importante merece atenção aqui. Quando você instrumenta o cliente de chat e também o agente, os spans podem trazer dados duplicados, principalmente com enableSensitiveData ativo.

Isso acontece porque o contexto de chat aparece nos dois spans. Por isso, dependendo da necessidade, pode ser melhor instrumentar apenas um dos dois e evitar redundância na telemetria.

A documentação oficial também faz um alerta sobre o DefaultAzureCredential. Ele é conveniente no desenvolvimento, mas em produção a recomendação é usar uma credencial específica, como o ManagedIdentityCredential, para evitar latência e tentativas de autenticação inesperadas.

Configuração dos exporters

Depois de instrumentar os componentes, você precisa configurar os exporters que enviam os dados ao backend. Essa configuração acontece no startup da aplicação, separadamente para traces, métricas e logs.

Para exportar traces ao Azure Monitor, o código fica assim:

using var tracerProvider = Sdk.CreateTracerProviderBuilder()
    .SetResourceBuilder(resourceBuilder)
    .AddSource(SourceName)
    .AddSource("*Microsoft.Extensions.AI")
    .AddSource("*Microsoft.Extensions.Agents*")
    .AddAzureMonitorTraceExporter(options => options.ConnectionString = applicationInsightsConnectionString)
    .Build();

O método AddSource define quais fontes o provider vai escutar. Portanto, o nome precisa bater com o sourceName usado na instrumentação, senão nenhum span chega ao exporter.

Quando você não informa um nome de fonte, o framework usa o padrão Experimental.Microsoft.Agents.AI. Nesse caso, registre exatamente esse nome no tracer provider e no meter provider.

Para métricas, o processo é análogo e usa o MeterProviderBuilder:

using var meterProvider = Sdk.CreateMeterProviderBuilder()
    .SetResourceBuilder(resourceBuilder)
    .AddMeter("*Microsoft.Agents.AI")
    .AddAzureMonitorMetricExporter(options => options.ConnectionString = applicationInsightsConnectionString)
    .Build();

Os logs, por sua vez, passam pelo Microsoft.Extensions.Logging, com o provider de OpenTelemetry configurado no LoggerFactory. A propriedade IncludeFormattedMessage = true garante que as mensagens formatadas cheguem aos logs exportados.

using var loggerFactory = LoggerFactory.Create(builder =>
{
    // registra o OpenTelemetry como provider de logs
    builder.AddOpenTelemetry(options =>
    {
        options.SetResourceBuilder(resourceBuilder);
        options.AddAzureMonitorLogExporter(o => o.ConnectionString = applicationInsightsConnectionString);
        options.IncludeFormattedMessage = true;
        options.IncludeScopes = true;
    })
    .SetMinimumLevel(LogLevel.Debug);
});

Com os três sinais configurados, a observabilidade no Agent Framework passa a cobrir o ciclo completo do agente. Assim, traces mostram o caminho, métricas mostram tendências e logs trazem o detalhe textual de cada evento.

Aspire Dashboard para desenvolvimento local

Em ambientes de desenvolvimento sem infraestrutura de nuvem, o Aspire Dashboard é uma alternativa prática. Ele roda localmente via Docker e recebe dados pelo protocolo OTLP.

Para subir o dashboard, a documentação sugere um comando como este:

docker run --rm -it -d \
    -p 18888:18888 \
    -p 4317:18889 \
    --name aspire-dashboard \
    mcr.microsoft.com/dotnet/aspire-dashboard:latest

A interface web fica em http://localhost:18888, enquanto o endpoint OTLP responde em http://localhost:4317. Em seguida, basta apontar o exporter para esse endereço durante o desenvolvimento:

using var tracerProvider = Sdk.CreateTracerProviderBuilder()
    .AddSource("*Microsoft.Extensions.AI")
    .AddSource("*Microsoft.Extensions.Agents*")
    .AddOtlpExporter(options => options.Endpoint = new Uri("http://localhost:4317"))
    .Build();

Com isso, você valida a observabilidade no Agent Framework na própria máquina antes de pagar por qualquer recurso no Azure. Afinal, o mesmo código troca de exporter quando a aplicação vai para produção.

Spans e métricas da observabilidade no Agent Framework

Quando a observabilidade no Agent Framework está habilitada, o framework gera automaticamente três tipos de span:

  • invoke_agent <agent_name>: span de nível superior para cada invocação de agente, que contém todos os outros como filhos.
  • chat <model_name>: criado quando o agente chama o modelo de linguagem; inclui prompt e resposta como atributos se enableSensitiveData estiver ativo.
  • execute_tool <function_name>: criado quando o agente executa uma ferramenta; inclui argumentos e resultado da função.

As métricas geradas também seguem as convenções GenAI:

  • gen_ai.client.operation.duration (histograma): duração de cada operação de chat, em segundos.
  • gen_ai.client.token.usage (histograma): consumo de tokens nas operações de chat.
  • agent_framework.function.invocation.duration (histograma): duração de cada execução de ferramenta, em segundos.

O histograma de tokens é especialmente útil para controlar custos. Por outro lado, a duração das ferramentas ajuda a descobrir se a lentidão vem do modelo ou de uma API externa chamada pelo agente.

Se você quer entender melhor como as ferramentas funcionam, o artigo sobre tools no Microsoft Agent Framework mostra o registro e a execução de funções em detalhes.

Cuidados com dados sensíveis

O parâmetro enableSensitiveData controla se prompts, respostas, argumentos de funções e resultados entram nos traces. Esse recurso ajuda muito na depuração, mas expõe informações potencialmente confidenciais em logs e traces.

Por isso, a recomendação é habilitar dados sensíveis apenas em desenvolvimento e testes, nunca em produção. Em outras palavras, a observabilidade no Agent Framework deve registrar metadados em produção e conteúdo apenas onde a política de retenção permitir.

Uma boa prática é ler essa opção de uma variável de configuração por ambiente. Dessa forma, ninguém precisa alterar código para ligar ou desligar a captura de conteúdo.

Observabilidade de workflows no Agent Framework

Agentes isolados resolvem tarefas simples, mas muitos cenários exigem coordenação entre várias etapas e mais observabilidade no Agent Framework. É aí que entram os workflows, e com eles uma camada extra de telemetria.

Contexto e finalidade

A observabilidade em workflows vai além do que existe para agentes individuais. Afinal, workflows são sistemas de múltiplos executores que processam mensagens, roteiam fluxos e coordenam agentes em etapas sequenciais ou paralelas.

O Agent Framework emite spans, logs e métricas adicionais específicos para a execução de workflows. Assim, essa telemetria complementa os dados GenAI padrão que você já recebe dos agentes.

Caso você ainda não tenha montado um workflow, o artigo sobre como orquestrar agentes com workflows explica executores, arestas e o fluxo de mensagens.

Como habilitar a observabilidade no Agent Framework em workflows

O processo de habilitação é o mesmo descrito para agentes. A instrumentação do cliente de chat e do agente, junto com os exporters, também vale para os workflows.

Ou seja, a observabilidade no Agent Framework não exige configuração adicional exclusiva para esse contexto. Basta garantir que o tracer provider escute as fontes corretas.

Spans específicos de workflows

Além dos spans comuns de agentes, o framework emite spans próprios durante a execução de um workflow:

Span Descrição
workflow.build Criado a cada build de um workflow
workflow.run Criado a cada execução de um workflow
message.send Criado para cada mensagem enviada a um executor
executor.process Criado para cada processamento de mensagem por um executor
edge_group.process Criado para cada processamento de mensagem por um grupo de arestas

Vale um aviso sobre a evolução da documentação. Na versão atual para C#, a execução aparece dividida em workflow.session, que cobre toda a vida da sessão, e workflow_invoke, emitido a cada ciclo de entrada até a parada.

Na documentação de Python, o span workflow.run continua representando cada execução. Portanto, confira os nomes na versão do pacote que você usa antes de montar consultas e painéis.

Os spans também carregam atributos úteis, como executor.id, executor.type, message.source_id e message.target_id. Além disso, qualquer span com erro recebe o atributo error.type com o nome da exceção.

Relacionamento entre spans

O modelo de relacionamento entre spans em workflows merece atenção especial. Quando um executor envia uma mensagem a outro, o span message.send nasce como filho do executor.process do executor de origem.

No entanto, o executor.process do executor de destino não vira filho do message.send. Como a execução não é aninhada, o framework estabelece a relação por meio de um link entre spans.

Esse design cria um caminho rastreável pelo workflow sem inventar hierarquias artificiais. Da mesma forma, os spans edge_group.process recebem links para os message.send de origem, o que cobre cenários de fan-in.

Essa abordagem é especialmente relevante em workflows com executores em paralelo. Nesse caso, a hierarquia tradicional de spans não representaria com fidelidade o fluxo real da execução.

Casos de uso para observabilidade de workflows

Nos workflows, a observabilidade no Agent Framework responde perguntas bem concretas. Por exemplo, quanto tempo cada executor levou para processar uma mensagem e qual caminho a mensagem percorreu.

Também fica fácil descobrir em qual etapa do workflow um erro surgiu. Combinada com o Aspire Dashboard ou o Azure Monitor, essa visibilidade transforma a depuração de workflows complexos em uma atividade sistemática.

Na prática, a observabilidade no Agent Framework permite comparar execuções lado a lado. Assim, uma regressão de latência aparece no gráfico antes de virar reclamação de usuário.

Tracing e observabilidade na DevUI do Agent Framework

A terceira peça da observabilidade no Agent Framework é visual. Nela, a DevUI coloca os mesmos spans em uma linha do tempo navegável durante o desenvolvimento.

O que é a DevUI

A DevUI é uma aplicação de exemplo, leve e independente, incluída no ecossistema do Microsoft Agent Framework. Ela permite executar, testar e depurar agentes e workflows de forma visual.

Além disso, a DevUI captura os spans emitidos pelo framework e os exibe em um painel de depuração dedicado. A documentação deixa claro que ela é uma ferramenta de desenvolvimento e não deve ir para produção.

Um aspecto importante para a observabilidade no Agent Framework: a DevUI não cria spans próprios. Ela apenas coleta os spans que o Agent Framework já emite e os organiza na interface.

Nota: quando este conteúdo foi escrito, a documentação de tracing da DevUI para C# ainda estava marcada como "em breve". Por isso, a seção a seguir usa Python, a linguagem com suporte documentado para essa funcionalidade.

Habilitando o tracing na DevUI

Para habilitar o tracing ao iniciar a DevUI pela linha de comando, use a flag --tracing:

devui ./agents --tracing

Quando a DevUI sobe de forma programática, o tracing fica disponível por um parâmetro da função serve():

from agent_framework.devui import serve

serve(
    entities=[agent],
    tracing_enabled=True
)

Visualizando traces na interface

Com o tracing habilitado, a interface web da DevUI exibe informações de trace em tempo real. O fluxo típico de uso tem três passos:

  1. Executar um agente ou workflow pela interface.
  2. Abrir o painel de depuração, disponível no modo desenvolvedor.
  3. Inspecionar a timeline de trace, com hierarquia de spans, tempos, eventos e chamadas de ferramentas.

O modo desenvolvedor é o padrão da DevUI. Por outro lado, o modo usuário, ativado com --mode user, esconde o painel de depuração e as APIs de desenvolvimento.

Estrutura de traces na DevUI

A estrutura hierárquica dos traces segue as convenções semânticas GenAI do OpenTelemetry. Para um agente simples, a árvore de spans fica semelhante a esta:

Agent Execution
    LLM Call
        Prompt
        Response
    Tool Call
        Tool Execution
        Tool Result
    LLM Call
        Prompt
        Response

Para workflows, a estrutura mostra o caminho de execução pelos executores:

Workflow Execution
    Executor A
        Agent Execution
            ...
    Executor B
        Agent Execution
            ...

Repare que a árvore de agente mostra duas chamadas ao modelo. Isso acontece porque o agente pede uma ferramenta, recebe o resultado e então chama o modelo de novo para compor a resposta final.

Integração com ferramentas externas

Embora a DevUI exiba os traces localmente, os spans são traces OpenTelemetry padrão. Portanto, eles também podem seguir para backends externos como Jaeger, Zipkin, Azure Monitor e Datadog.

Para exportar os traces a um collector externo, configure a variável de ambiente OTLP_ENDPOINT antes de iniciar a DevUI:

export OTLP_ENDPOINT="http://localhost:4317"
devui ./agents --tracing

Quando nenhum endpoint OTLP está configurado, a DevUI captura os traces localmente e os mostra apenas no painel. Ou seja, nada sai da máquina sem uma configuração explícita.

Boas práticas de observabilidade no Agent Framework

Algumas decisões simples evitam dor de cabeça quando a aplicação cresce. A primeira é padronizar o sourceName em uma constante compartilhada entre instrumentação e providers.

Em seguida, escolha onde instrumentar: no cliente de chat, no agente ou nos dois. Lembre que instrumentar os dois duplica o contexto nos spans.

Também vale dar um nome distinto a cada agente. Assim, painéis como a visão de agentes do Application Insights conseguem separar o comportamento de cada um.

Por fim, trate enableSensitiveData como configuração de ambiente, e não como constante no código. Dessa forma, a observabilidade no Agent Framework continua útil em produção sem expor dados de usuários.

Conclusão

A observabilidade no Agent Framework se apoia em padrões abertos e amplamente adotados. Isso garante flexibilidade na escolha de backends e reduz a curva de aprendizado para times que já usam OpenTelemetry.

Em C#, a instrumentação com UseOpenTelemetry e WithOpenTelemetry gera spans e métricas automaticamente para agentes individuais. Para workflows, spans como executor.process e message.send rastreiam o fluxo completo, com links garantindo a rastreabilidade em execuções não aninhadas.

A DevUI completa essa infraestrutura com uma interface visual que coleta os traces emitidos pelo framework. Além disso, a mesma telemetria segue para ferramentas externas, então o que você valida localmente já está pronto para produção.

FAQ

O que é necessário para habilitar observabilidade em um agente C#?

Você instrumenta o cliente de chat com UseOpenTelemetry e o agente com WithOpenTelemetry. Depois, configura os exporters de traces, métricas e logs no startup da aplicação.

Posso usar o Aspire Dashboard sem configurar o Azure Monitor?

Sim. O Aspire Dashboard roda localmente via Docker, aceita dados via OTLP e dispensa qualquer recurso na nuvem.

Porque a execução entre executores não é aninhada. Os links representam o fluxo real sem criar hierarquias artificiais.

O que acontece se eu habilitar enableSensitiveData em produção?

Prompts, respostas, argumentos e resultados de ferramentas entram nos traces e logs. Isso pode expor dados de usuários, por isso a opção deve ficar restrita a desenvolvimento e testes.

A DevUI cria spans próprios?

Não. A DevUI apenas coleta e exibe os spans que o Agent Framework emite durante a execução de agentes e workflows.

É possível exportar os traces da DevUI para Jaeger ou Azure Monitor?

Sim. Basta configurar a variável OTLP_ENDPOINT antes de iniciar a DevUI, já que os traces seguem o padrão OpenTelemetry.

Qual a diferença entre gen_ai.client.operation.duration e agent_framework.function.invocation.duration?

A primeira mede a duração das operações de chat com o modelo. A segunda mede a duração das ferramentas executadas pelo agente.