Novo Cadastre-se grátis, 10 chamadas por nossa conta. Até US$ 1, sem cartão.

Observabilidade de agentes LLM: traces, sessões e 10 problemas

Conteúdo
  1. O que são traces, spans e sessões em um agente LLM?
  2. Qual visualização responde a cada pergunta?
  3. Por que um agente LLM fica lento?
  4. Por que um agente LLM custa caro?
  5. Como depurar um agente LLM a partir da reclamação de um usuário?
  6. É possível rastrear um agente de programação que você não escreveu?
  7. Um modelo pode ler os traces por você?
  8. O que todo agente deve registrar?
  9. O que o tracing no gateway não cobre?
  10. Perguntas frequentes
  11. O que é observabilidade de agentes LLM?
  12. Leituras relacionadas

A observabilidade de um agente LLM começa com duas formas de agrupar suas chamadas ao modelo: um trace, que mostra uma execução do agente em uma linha do tempo, e uma sessão, que reúne uma conversa e seu custo total. Com três cabeçalhos em cada chamada, um gateway LLM (um proxy entre seu código e os provedores de modelos que registra todas as requisições) monta os dois a partir do log de requisições, sem SDK de tracing. Usamos essa configuração em um pequeno agente de suporte e no Claude Code para reproduzir dez problemas comuns: três que deixam o agente lento, quatro que aumentam o custo e três que causam falhas.

TL;DR

  • Três cabeçalhos (X-Trace-Id, X-Span-Id, X-Session-Id) transformam o log de requisições do gateway Synthorai em traces e sessões, sem SDK de tracing.
  • Executar juntas três verificações independentes de subagentes reduziu o tempo mediano de 3.7 s para 1.8 s, sem alterar o custo.
  • Tirar um timestamp da primeira linha do prompt no GPT-6 Luna elevou a taxa de acertos no cache de 0% para 73%, partindo de um cache vazio.
  • Uma execução do Claude Code custou $0.1728, e a primeira chamada de cada um dos três agentes representou 72% desse valor.

Este artigo apresenta uma série de sete guias. Cada seção abaixo resume um guia, traz os números obtidos e inclui um link para o código e as capturas de tela. Todas as execuções são de 10 e 11 de outubro de 2026. Os valores de latência são medianas de cinco execuções; todos os demais vêm de uma única execução. O código está em github.com/synthorai-io/use-cases.

O que são traces, spans e sessões em um agente LLM?

Um trace reúne tudo o que o agente faz para atender a uma mensagem do usuário ou executar uma tarefa. Um span é uma etapa desse trace. Uma sessão é a conversa inteira, composta por vários traces. No nosso agente de suporte, uma conversa com um cliente em dois turnos corresponde a uma sessão com dois traces, cada um com cinco ou seis chamadas ao modelo. Algumas dessas chamadas vêm de um subagente: um segundo agente que o principal inicia para executar parte da tarefa, com seu próprio prompt e, muitas vezes, um modelo mais barato.

TermoO que abrangeCabeçalhoOnde enviar o mesmo valor
Traceuma execução do agenteX-Trace-Idem todas as chamadas da execução
Spanuma chamada ao modelo na execuçãoX-Span-Idapenas nessa chamada
Sessãouma conversaX-Session-Idem todas as chamadas da conversa
Agentequal subagente fez uma chamadaX-Agent-Idem todas as chamadas desse subagente
Rótulosusuário, funcionalidade, versãoX-Synthorai-Metadataem qualquer chamada que você queira agrupar ou filtrar

Os IDs são strings definidas por você, cada uma com até 128 caracteres ASCII imprimíveis. Os rótulos formam um objeto JSON sem aninhamento, com valores do tipo string: no máximo 10 por requisição, com até 128 bytes por valor. O gateway devolve os IDs na resposta e não encaminha nenhum desses cabeçalhos ao provedor do modelo. No SDK Python da OpenAI, os cabeçalhos de cada requisição entram em extra_headers:

resp = client.chat.completions.create(
    model="gpt-6-luna",
    messages=messages,
    extra_headers={
        "X-Session-Id": session_id,   # one per conversation
        "X-Trace-Id": trace_id,       # one per user message
        "X-Span-Id": "plan",          # one per call
        "X-Synthorai-Metadata": '{"feature":"support-agent","_user":"u_1002"}',
    },
)

Se o agente já envia IDs de trace por outra ferramenta, talvez não seja preciso acrescentar nada. Para cada um dos três IDs ausentes na requisição, o gateway lê o cabeçalho equivalente de OpenTelemetry (o padrão aberto de tracing, cujo cabeçalho traceparent contém um ID de trace), LiteLLM, Langfuse, Open WebUI, Claude Code ou OpenAI Codex CLI. O guia Rastreie um agente LLM com 3 cabeçalhos HTTP constrói o agente de demonstração passo a passo: uma chamada de planejamento no GPT-6 Luna, duas ferramentas locais, três verificações paralelas no DeepSeek V4.1 Flash e uma chamada para gerar a resposta. A execução de demonstração fez 21 chamadas ao modelo por $0.0017.

Qual visualização responde a cada pergunta?

Cada pergunta da série pode ser respondida em uma área do console ou por uma forma de consultar o log fora dele. O console exibe cada trace em um gráfico de cascata, com uma barra por chamada ao modelo em um eixo de tempo comum. Assim, chamadas paralelas se sobrepõem, enquanto chamadas que dependem umas das outras formam uma escada.

PerguntaOnde consultarGuia
Por que esta execução levou 8 segundos?o resumo do trace: tempo no gateway comparado ao tempo na aplicaçãoLatência de agentes
Qual turno desta conversa custou mais?a página da sessão, com uma linha por traceCusto de agentes
Por que a taxa de acertos no cache está em 0%?a coluna de acertos no cache na página da sessãoCusto de agentes
O que aconteceu com a requisição deste usuário ontem?uma busca por rótulo na lista de tracesDepuração de agentes
Qual subagente do Claude Code foi responsável pelo gasto?a tabela de agentes na página da sessãoCusto do Claude Code por subagente
Posso fazer essas perguntas em uma janela de chat?um conector MCP no ClaudeConsulte seus logs de LLM com o Claude
Meu próprio programa pode investigar o log?ferramentas MCP ou a API RESTDê ao seu agente ferramentas para consultar logs

Toda página de trace também tem um botão de comparação. Ele coloca dois traces na mesma página, associa as chamadas pelo nome e exibe os dois gráficos de cascata no mesmo eixo de tempo. Todas as correções da série foram verificadas dessa forma, comparando a execução anterior à correção com a posterior.

Por que um agente LLM fica lento?

Comece pela divisão no topo do trace. Ela separa o tempo total decorrido (o que o usuário esperou, da primeira requisição à última resposta) em tempo no gateway, quando havia ao menos uma requisição ao modelo em andamento, e tempo na aplicação, quando apenas seu código estava rodando. No trace de demonstração, os 8.5 s totais se dividiram em 7.0 s no gateway e 1.6 s na aplicação. O ponto a investigar, portanto, eram as chamadas ao modelo. O guia de latência reproduziu três causas e executou cada caso cinco vezes:

CausaO que o trace mostraCorreçãoMediana antesMediana depois
Chamadas independentes enviadas uma por vezbarras em escadaenviá-las juntas com asyncio.gather, o recurso do Python para aguardar várias chamadas ao mesmo tempo3.7 s1.8 s
Código lento entre chamadasuma linha longa de your appexecutar as quatro consultas juntas11.0 s9.2 s
Raciocínio em respostas de uma linhauma contagem de saída muito maior que a respostareasoning_effort="none"25.6 s para cinco respostas10.2 s

No caso do código lento, as chamadas ao modelo levaram praticamente o mesmo tempo nas duas execuções. O que mudou foi o tempo na aplicação: no par de execuções mostrado no guia, a linha your app caiu de 4.6 s para 1.3 s. Trocar o modelo não reduz esse trecho; a investigação começa no profiler da aplicação ou nos spans do OpenTelemetry. O terceiro caso usou o GPT-6 Luna. O parâmetro de requisição reasoning_effort define quanto o modelo raciocina antes de responder. Com o valor none, os tokens de saída das cinco respostas caíram de 1,150 para 190. O guia Por que meu agente LLM está lento? traz o código e os traces lado a lado para os três casos.

Por que um agente LLM custa caro?

Comece pela lista de traces ordenada por custo. Abra a sessão mais cara e examine as colunas de acertos no cache e de entrada, turno a turno. A taxa de acertos no cache é a proporção de tokens de entrada lidos do cache de prompts do provedor, que cobra uma fração do preço de entrada por um prefixo de prompt já visto. O guia de custos reproduziu quatro causas. Os valores são frações de centavo porque a demonstração é pequena; são as proporções que se aplicam a outras escalas:

CausaOnde apareceAntesDepois
Um timestamp na primeira linha do prompta taxa de acertos no cache permanece em 0%0% em cache73% em cache, custo de entrada 66% menor
Histórico que reenvia todos os resultados de ferramentasa entrada cresce a cada turno24,546 tokens de entrada8,053 tokens de entrada
Um loop de tentativasum trace com chamadas demais, todas com status 20010 chamadas2 chamadas
Um modelo caro em uma etapa simplesa tabela de agentes na página da sessão$0.0012$0.0003

A primeira linha usou o GPT-6 Luna, partindo de um cache vazio. O guia mostra outra forma de perder o cache: acrescentar uma instrução a cada mensagem do usuário no envio, mas não ao salvá-la. Assim, cada turno reconstrói um prompt que o turno anterior nunca enviou. Salvar a mensagem exatamente como foi enviada elevou a taxa de acertos daquela conversa de 0% para 76%. No caso do histórico, triplicar os tokens de entrada aumentou o custo de entrada em apenas 21%, pois 71% deles foram lidos do cache. Na última linha, três verificações de subagentes no GPT-6.1 Sol representaram 81% do custo da sessão. As mesmas verificações no DeepSeek V4.1 Flash custaram um décimo desse valor. O guia Por que meu agente LLM custa caro? detalha cada caso.

Como depurar um agente LLM a partir da reclamação de um usuário?

Localize as execuções do usuário por um rótulo e examine o trace para encontrar a chamada que falhou, muitas vezes com status 200. Com um rótulo _user em cada requisição, a busca metadata._user = u_1002 na lista de traces retorna as sessões e os traces desse usuário. O guia de depuração reproduziu três falhas:

  • Um 404 seguido de nova tentativa. Uma chamada a um ID de modelo inexistente falhou em 95 ms, com custo de $0. Como a nova tentativa manteve o ID do trace e recebeu outro nome de span (policy-check.retry), a falha e a tentativa seguinte aparecem lado a lado no gráfico de cascata.
  • Respostas cortadas com status 200. Com max_tokens=40 e o raciocínio ativado, três chamadas seguidas ao DeepSeek V4.1 Flash retornaram status 200, exatamente 40 tokens de saída e uma resposta vazia: o raciocínio consumiu todo o limite. O trace mostra o mesmo span três vezes, com a contagem de saída igual ao limite. Aumentar o limite para 2,000 e desativar o raciocínio resultou em uma única chamada, que respondeu com 49 tokens. Apenas aumentar o limite também funcionou, mas essa chamada usou 1,876 tokens de raciocínio e levou 22 s.
  • Um 400 no segundo turno. Um histórico salvo que perdeu uma chamada de ferramenta fez o GPT-6 Luna rejeitar o segundo turno em 0.5 s, sem cobrança, embora o primeiro turno tivesse funcionado.

A segunda falha mostra por que toda chamada deve registrar finish_reason, o campo da resposta que informa por que o modelo parou. O valor length significa que a resposta atingiu o limite de max_tokens e deve contar como falha, mesmo com status 200. O guia Depure um agente LLM lista os cinco campos que todo agente deve registrar, retomados perto do fim deste artigo.

É possível rastrear um agente de programação que você não escreveu?

É possível rastrear o Claude Code sem alterá-lo, pois ele já envia um ID de sessão e um ID de agente em cada requisição. Duas variáveis de ambiente bastam para direcioná-lo ao gateway; uma terceira acrescenta o tipo de cada subagente:

export ANTHROPIC_BASE_URL="https://synthorai.io"   # no /v1: Claude Code adds /v1/messages itself
export ANTHROPIC_API_KEY="<your gateway key>"
export CLAUDE_CODE_GATEWAY_HINT_HEADERS=1          # optional: names sub-agent types such as Explore

Uma execução do Claude Code com Claude Sonnet 5.5, usando dois subagentes para corrigir um teste que falhava, fez 11 requisições por $0.1728. A página da sessão separou o custo por agente: os dois subagentes responderam por 39% do total, as gravações no cache por 77%, e a primeira chamada de cada um dos três agentes por 72%. A mesma execução, repetida meio minuto depois com o cache aquecido, custou $0.0812. O guia Custo do Claude Code por subagente também separa os gastos de uma equipe por desenvolvedor e repositório.

Um modelo pode ler os traces por você?

Um modelo pode lê-los via MCP (Model Context Protocol, o padrão para disponibilizar ferramentas a modelos), pois o gateway expõe seu log de requisições como um servidor MCP. A forma de consultar o log depende de quem faz a pergunta:

Quem perguntaO que usarTokens do modeloResultado medido
Uma pessoa com uma dúvidaClaude com o gateway adicionado como conectorincluídos no plano de chat3 perguntas em 14 chamadas de ferramenta, todos os valores conferiram com os registros de cobrança
Um programa com uma consulta fixaa API RESTnenhumas 3 sessões de maior custo por $0
Seu próprio agente, que decide o que investigarferramentas MCP no programacobrados de vocêuma investigação de custo por $0.0015

No caso do chat, o Claude Fable 5.1 se conectou por OAuth, com login pelo navegador em vez de colar uma chave de API, e recebeu acesso apenas de leitura ao log de requisições. Isso lhe deu quatro ferramentas somente de leitura e uma chave que expira em 7 dias. As ferramentas retornam custo, tokens e status, sem o texto dos prompts ou das respostas. No caso do programa, o GPT-6 Luna encontrou as sessões com problemas de cache, modelo inadequado e loop de tentativas entre 26 sessões, em uma chamada de ferramenta por $0.0015. O Claude Sonnet 5.5 encontrou as mesmas sessões em três chamadas de ferramenta por $0.0631, após consultar os preços. Os guias Consulte seus logs de LLM com o Claude e Dê ao seu agente ferramentas para consultar logs cobrem as duas configurações.

O que todo agente deve registrar?

Cinco campos cobrem todos os problemas da série:

  • Um ID de trace por execução e um ID de sessão por conversa, enviados como cabeçalhos e registrados também nos seus próprios logs.
  • Um nome de span por chamada que identifique a etapa e a tentativa, como plan-2 ou policy-check.retry.
  • Rótulos de usuário, funcionalidade e versão, para localizar as execuções por trás de uma reclamação ou cobrança.
  • O cabeçalho de resposta x-request-id de cada chamada, para consultar depois o custo cobrado por ela.
  • O finish_reason e a contagem de tokens de saída de cada chamada, tratando length como falha.

Defina também um timeout no cliente e um valor de max_tokens em cada chamada, ambos com folga. Um limite dimensionado apenas para a resposta visível causou as respostas 200 vazias descritas acima. Além disso, uma única chamada longa a um modelo de raciocínio pode levar minutos.

O que o tracing no gateway não cobre?

O tracing baseado no log de requisições cobre as chamadas ao modelo, não o que acontece dentro do seu código. O gateway deduz o tempo de execução do código pelos intervalos entre requisições, como mostrou o caso do código lento. Spans de ferramentas, recuperação de dados e filas precisam de um SDK OpenTelemetry. As duas visualizações podem compartilhar um ID de trace, pois o gateway lê traceparent quando X-Trace-Id está ausente. Os traces também não incluem os corpos dos prompts e das respostas e só informam o custo após a execução: para controlar um orçamento em tempo real, o loop do agente precisa calcular o preço do usage de cada resposta assim que ela chega.

Perguntas frequentes

O que é observabilidade de agentes LLM?

Observabilidade de agentes LLM é a capacidade de ver o que um agente fez em cada execução: quais chamadas ao modelo realizou, em que ordem, quanto tempo cada uma levou, quanto custou e quais falharam. Na prática, isso significa agrupar chamadas em traces (uma execução) e sessões (uma conversa), com rótulos de usuário e funcionalidade.

Leituras relacionadas

← Voltar ao blog