Pular para o conteúdo
Zumkai

Observabilidade de agente: como instrumentar o que não se reproduz

Bug de agente não se reproduz: o rastro precisa existir antes do erro. A árvore de spans, os atributos do OpenTelemetry e o que ainda muda.

  • observabilidade
  • opentelemetry
Card com os nomes de atributo da convenção GenAI do OpenTelemetry e o número de issues abertas na especificação.
Sumário
  1. Por que depurar agente é diferente
  2. A árvore de spans que o OpenTelemetry define
  3. Os atributos, com os nomes certos
  4. O padrão ainda está mudando
  5. O que capturar, e o que não
  6. As quatro métricas que valem painel
  7. Por onde começar numa tarde
  8. O que este blog registra, e o que não registra
  9. O que o trace não captura
  10. Perguntas frequentes
  11. O que levar

O agente falhou ontem. Você rodou de novo hoje, com a mesma entrada, e funcionou.

Não existe bug para investigar. Existe um evento que não volta.

Essa é a diferença entre observar um sistema comum e observar um agente. No primeiro, o log serve para reconstruir o que aconteceu porque você pode repetir a execução e comparar. No segundo, a segunda execução é outra execução.

O registro precisa existir antes do erro. E precisa existir com os nomes certos, porque já existe um padrão que define esses nomes — e ele ainda está mudando.

Por que depurar agente é diferente

A dificuldade não é falta de log. É que a repetição deixou de ser uma ferramenta de investigação.

Num sistema determinístico, você reproduz o erro e observa quantas vezes precisar. Adiciona um log, roda de novo, olha. O registro pode ser incompleto, porque sempre dá para melhorar e repetir.

Com agente, cada execução escolhe um caminho. A ferramenta chamada pode ser outra, a ordem pode mudar, o número de passos varia. Quando algo dá errado, aquela execução específica é a única evidência que existirá.

Daí a inversão prática: em sistema comum, você investiga e depois instrumenta o que faltou. Com agente, você instrumenta antes e investiga com o que guardou.

É por isso que observabilidade aparece por último nas cinco camadas do harness e mesmo assim precisa ser construída cedo. Ela depende das outras quatro para ter o que registrar. E sem ela, nenhuma das quatro tem como melhorar.

A árvore de spans que o OpenTelemetry define

Existe um padrão, e ele é específico. O grupo de interesse em GenAI do OpenTelemetry trabalha nele desde abril de 2024. Ele define nomes de operação, atributos e tipos. Cobre chamada de modelo, passo de agente, uso de ferramenta e contagem de token.

Um trace de agente tem esta forma:

txt
invoke_agent research-assistant   (INTERNAL)
├── chat gpt-4o                   (CLIENT)
├── execute_tool web_search       (INTERNAL)
├── chat gpt-4o                   (CLIENT)
├── execute_tool summarize        (INTERNAL)
└── chat gpt-4o                   (CLIENT)

O span de agente usa kind INTERNAL quando a execução é local e CLIENT quando chama serviço remoto.

As operações nomeadas pela convenção são oito: chat, text_completion, generate_content, embeddings, create_agent, invoke_agent, invoke_workflow e execute_tool (Greptime, 9 de maio de 2026, acesso em 28/08/2026; estrutura também descrita no blog do OpenTelemetry).

A mesma latência, com e sem a árvore de spans Sem a árvore, a tarefa aparece como 40 segundos totais. Com a árvore, fica visível que 31 desses segundos ficaram numa única chamada de ferramenta de busca, e que as chamadas de modelo somam apenas 7 segundos. sem a árvore 40 s com a árvore chat 3 s execute_tool busca 31 s chat 2 s chat 2 s O modelo somou 7 segundos. A ferramenta, 31.
Atribuição de latência por span, o ganho prático da hierarquia.

A hierarquia é o que torna o rastro útil. Um número de latência total não diz nada. A mesma informação, distribuída na árvore, mostra outra coisa. A tarefa levou 40 segundos. Trinta e um ficaram numa busca. O modelo esperou parado esse tempo todo. Sem a árvore, você troca de modelo. Com a árvore, você corrige a ferramenta.

Os atributos, com os nomes certos

Todos os atributos da convenção começam com gen_ai.. Vale copiar esta tabela:

GrupoAtributos
Modelogen_ai.provider.name, gen_ai.request.model, gen_ai.response.model
Tokensgen_ai.usage.input_tokens, gen_ai.usage.output_tokens, gen_ai.usage.cache_read.input_tokens, gen_ai.usage.reasoning.output_tokens
Ferramenta e agentegen_ai.tool.name, gen_ai.tool.call.arguments, gen_ai.tool.call.result, gen_ai.agent.name
Conclusãogen_ai.response.finish_reasons
MCPmcp.method.name, mcp.session.id, mcp.protocol.version

Dois pares existem por um motivo. O primeiro guarda o modelo que você pediu e o modelo que de fato respondeu. Nem sempre são o mesmo, porque o provedor roteia. O segundo separa o token lido de cache do token cobrado cheio. É a diferença entre uma fatura explicável e um susto.

<!-- [UNIQUE INSIGHT] -->

Um aviso que vale mais que a tabela inteira. Parte do material em português cita esses atributos como llm.usage.prompt_tokens e llm.usage.completion_tokens. Esses nomes não são os da convenção GenAI do OpenTelemetry. A origem provável é o OpenInference, que tem esquema próprio, ou nomenclatura de versões antigas de bibliotecas.

Não é preciosismo. Nome de atributo é chave de consulta. Instrumente com um nome fora do padrão e seus painéis deixam de conversar com as ferramentas do ecossistema. A migração depois custa reescrever consulta, alerta e painel.

Há uma recomendação que quase ninguém segue e todo mundo se arrepende. Marque todo span com pelo menos um atributo de negócio desde o primeiro dia. Um user_id, um workflow_id, um identificador de tarefa. Se você acrescentar isso depois de um incidente, o incidente que motivou a mudança é o único sem o campo.

Os atributos de token, aliás, são a ponte entre rastro e fatura. É com eles que se descobre qual padrão de uso está consumindo o orçamento, pelo mesmo raciocínio de quanto custa cada padrão de uso.

O padrão ainda está mudando

Instrumente agora, e conte com renomeação.

A convenção é real e está sendo adotada por plataformas grandes. A Datadog foi uma das primeiras a dar suporte nativo, a partir da versão 1.37 das convenções, e a instrumentação do SDK Python da OpenAI é descrita como a mais madura do conjunto.

E ela continua em obra. Três fatos verificáveis mostram isso melhor que qualquer rótulo:

Em junho de 2026, a especificação ganhou repositório próprio. A página de convenções GenAI no site do OpenTelemetry hoje só redireciona para o repositório semantic-conventions-genai. Separar um documento em obra costuma acontecer quando ele muda em ritmo diferente do resto.

Esse repositório tinha 139 issues abertas e 45 pull requests pendentes quando verifiquei, em 28 de agosto de 2026.

Um atributo já foi renomeado entre versões. Na v1.37, o campo gen_ai.system virou gen_ai.provider.name. Quem instrumentou antes disso teve painel parando de encontrar dado por causa de troca de nome.

A análise da Greptime, de maio de 2026, descreve as convenções de GenAI e MCP como ainda em status de desenvolvimento, sem cronograma público de estabilização. Não consegui confirmar esse rótulo na documentação oficial, que estava em migração de repositório quando verifiquei — mas os três fatos acima sustentam a conclusão sem depender dele.

O que fazer com isso é simples: isole o mapeamento de atributos numa camada própria. Uma função que recebe seus dados e devolve os atributos com os nomes da convenção. Quando o nome mudar, você altera um arquivo em vez de caçar strings pelo código.

Julgamento explícito: quem está esperando o padrão estabilizar para começar a instrumentar vai passar o ano sem rastro. O custo de renomear um atributo é uma tarde. O custo de não ter registro do incidente que aconteceu é o incidente inteiro.

O que capturar, e o que não

A lista do que vale registrar em cada execução:

  • A tarefa como ela chegou, antes de qualquer processamento.
  • Cada chamada de ferramenta, com argumento e retorno.
  • O número de passos até concluir.
  • A versão do modelo que respondeu, e não só a pedida.
  • Tokens de entrada, de saída, de cache e de raciocínio.
  • O motivo de parada, via gen_ai.response.finish_reasons.
  • O ponto em que o agente trocou de estratégia.

O último é o mais informativo e o menos coletado. Ele também é o sinal que antecede a falha em cadeia, uma das ameaças catalogadas em OWASP Top 10 para agentes. Quando o agente abandona um caminho e tenta outro, uma de duas coisas aconteceu: a ferramenta devolveu algo inútil, ou o contexto encheu. As duas são acionáveis, e nenhuma aparece num log que só registra sucesso.

O que não guardar cru

Trace guarda gen_ai.tool.call.result, e o resultado de uma ferramenta frequentemente contém texto escrito por terceiros — a página que o agente abriu, o e-mail que ele leu, o comentário de issue.

Isso tem duas consequências. A primeira é de privacidade: conteúdo de usuário atravessa para uma plataforma de observabilidade, que costuma ter política de retenção diferente da do seu banco. A segunda é que trace é lido por gente e por ferramenta, e texto de terceiro em qualquer superfície é vetor de injeção.

O meio-termo funciona assim. Metadado sempre. Conteúdo por amostragem. Conteúdo sensível nunca. Tamanho da resposta, hash, origem e código de status resolvem a maior parte das investigações sem carregar o texto.

Amostragem

Guardar tudo em fidelidade máxima fica caro e raramente é necessário. Duas abordagens circulam: amostragem por cabeça, que decide no início do trace, e por cauda, que decide no fim e permite ficar com os traces que deram errado.

A prática corrente em produção converge para a segunda, porque erro é raro e é o que interessa. Trato isso como prática de mercado, e não como resultado medido — não encontrei estudo comparando as duas em sistema agêntico.

O custo tem um detalhe que muda a conta. Em várias plataformas, só os spans de LLM entram na fatura. Spans de ferramenta, de recuperação e de agente saem de graça. Se for o caso da sua, um sistema muito agêntico sai mais barato de observar do que o total de spans sugere. Confira na tabela de preço antes de assumir. Isso varia por fornecedor.

As quatro métricas que valem painel

Rastro serve para investigar um caso. Métrica serve para descobrir que existe um caso.

MétricaO que revela quando piora
Chamadas por tarefaalguma ferramenta passou a responder pior, ou a descrição ficou ambígua
Tokens por tarefaalguma resposta cresceu sem teto, ou o cardápio de ferramentas aumentou
Taxa de erro por ferramentaparâmetro mal nomeado, ou validação devolvendo mensagem inútil
Acerto de primeirao agente está escolhendo errado antes de tentar

Chamadas por tarefa é o número que se move primeiro. Ele sobe antes de a taxa de acerto cair, o que dá uma semana de vantagem para quem estiver olhando.

A terceira linha merece o destaque em negrito que está ali. Taxa de erro agregada esconde o caso que você precisa achar: uma ferramenta com 40% de falha no meio de nove saudáveis some na média, e é ela que está gastando os passos. Medir por ferramenta é a diferença entre saber que algo piorou e saber o quê. É também o que transforma o desenho das ferramentas em trabalho guiado por dado.

Vale notar que essas quatro conversam com as quatro métricas da camada de guardrails: aquelas medem atrito e cobertura da trava, e estas medem saúde da execução. Essas quatro respondem "o que quebrou". Elas não respondem "vale continuar investindo", que é outra pergunta, com outras métricas — dólar por entrega, tempo até a conclusão, defeito que escapou — descritas no pilar.

A ordem em que as métricas se movem Quando algo piora, a contagem de chamadas por tarefa sobe primeiro, seguida pelos tokens por tarefa, depois pela taxa de erro por ferramenta, e só então cai o acerto de primeira, que é a métrica que o usuário percebe. antes quando dói chamadas por tarefa tokens por tarefa erro por ferramenta acerto de primeira Quem olha a primeira ganha uma semana sobre quem olha a última.
Ordem observada de degradação. A métrica que o usuário percebe é a que se move por último.

Por onde começar numa tarde

Você não precisa de plataforma nova para começar. Precisa de três decisões.

1. Envolva a chamada de modelo. Uma função sua chama a API. Ela abre um span chat. Ela fecha o span com os tokens e o motivo de parada. Nada além disso no primeiro dia.

2. Envolva a chamada de ferramenta. Mesmo padrão, span execute_tool. Guarde o nome da ferramenta e o tempo. O argumento e o retorno entram depois, quando você decidir a política de conteúdo.

3. Coloque os dois dentro de um invoke_agent. É esse span que dá a árvore. Sem ele você tem eventos soltos, não trace.

Feito isso, três números já saem de graça: chamadas por tarefa, tokens por tarefa e tempo por passo.

Uma escolha para tomar cedo, porque é cara de mudar depois. Decida o identificador de negócio agora. Todo span leva ele. Pode ser o slug do que está sendo produzido, o número da tarefa, o usuário. Sem isso, o rastro responde "o que aconteceu" e não responde "com qual trabalho".

E não espere o painel bonito. Arquivo estruturado, uma linha por span, já permite responder a pergunta que importa no dia do incidente.

O que este blog registra, e o que não registra

<!-- [PERSONAL EXPERIENCE] -->

Aqui a honestidade custa. A operação que publica este blog tem verificação forte e observabilidade fraca.

O que existe é bom e cobre o produto: Lighthouse a cada build, varredura de todas as rotas, análise de legibilidade de cada texto, conferência de schema com relatório de referências órfãs. Se o site regride, eu descubro.

Do agente, quase nada. Não há trace estruturado, não há span nomeado, não há contagem sistemática de passos por tarefa. O que existe é o histórico de sessão. É rastro em prosa. Dá para reler e reconstruir uma tarefa específica. Não dá para agregar, comparar entre semanas nem disparar alerta.

A contradição é minha e vale dizer com todas as letras. Recomendei contagem de passos como indicador antecedente no pilar deste cluster. Não a coleto de forma consistente. Escrever sobre a camada foi o que me fez olhar para a lacuna.

O motivo de ela existir é banal e provavelmente comum. As quatro camadas anteriores dão retorno visível na tarefa seguinte — uma ferramenta melhor economiza passos hoje, um teste no laço pega o erro hoje. Observabilidade só paga na semana em que alguma coisa piora, e até lá parece trabalho sem resultado.

O plano, dito como plano. Envolver as chamadas num wrapper que emita invoke_agent e execute_tool com os atributos da convenção. Começar por três números: chamadas por tarefa, tokens por tarefa e erro por ferramenta. Quando isso rodar por algumas semanas, volto aqui com os dados.

O que o trace não captura

A camada tem um limite, e conhecê-lo evita pedir a ela o que ela não faz.

O trace registra o que aconteceu. Qual ferramenta foi chamada, com que argumento, em quanto tempo, com que retorno. Isso é mecânica.

Ele não registra por que o modelo escolheu aquilo. Não existe campo para intenção. O finish_reasons diz que a geração parou por chamada de ferramenta, e não diz por que aquela ferramenta pareceu a certa.

Também não registra se o resultado ficou bom. Um trace de execução impecável — todos os spans verdes, latência baixa, zero erro — pode terminar numa resposta errada. A ausência de falha técnica não é sinal de qualidade.

Essas duas lacunas têm respostas diferentes. Para a intenção, o que ajuda é registrar o texto do raciocínio quando o modelo o expõe, e aceitar que continua sendo relato, não causa. Para a qualidade, a resposta é outra camada inteira: avaliação, que compara a saída com um critério.

É a diferença entre perguntar "rodou?" e perguntar "prestou?". Observabilidade responde a primeira com precisão. A segunda pede eval, que é o tema do próximo post.

Enquanto isso, um hábito barato ajuda: anexe ao trace o resultado da verificação que já existe. Se o build passou, se o teste passou, se o checklist fechou. Não é medida de qualidade, e é o mais perto disso que a camada de observabilidade chega sozinha.

Perguntas frequentes

O que é observabilidade de LLM?

É a prática de instrumentar aplicações com modelo de linguagem. Cada chamada, uso de ferramenta e passo de raciocínio vira um span rastreável, com atributos padronizados de modelo, token, latência e resultado. A diferença para o monitoramento tradicional está no objetivo. Não se trata só de detectar indisponibilidade. Trata-se de reconstruir uma execução que não pode ser repetida, porque a mesma entrada não produz a mesma saída.

Qual a diferença entre log e trace num agente?

Log registra eventos isolados, com carimbo de tempo e mensagem. Trace registra a estrutura da execução: qual chamada aconteceu dentro de qual, em que ordem, e quanto cada uma demorou. Num agente, a estrutura é a informação principal, porque ela permite atribuir latência e custo ao passo específico em vez de ao total. Um trace bem formado responde onde o tempo foi gasto; um log responde que algo aconteceu.

Vale usar OpenTelemetry se a convenção ainda está mudando?

Vale. A alternativa é ficar sem rastro ou inventar um esquema próprio, que também vai mudar e ainda não conversa com nenhuma ferramenta. O cuidado prático é isolar o mapeamento de atributos numa camada única, de forma que uma renomeação como a de gen_ai.system para gen_ai.provider.name, ocorrida na v1.37, custe alterar um arquivo.

Quais atributos registrar num span de LLM?

No mínimo: gen_ai.provider.name, gen_ai.request.model, gen_ai.response.model, gen_ai.usage.input_tokens, gen_ai.usage.output_tokens e gen_ai.response.finish_reasons. Para spans de ferramenta, acrescente gen_ai.tool.name e o resultado. E marque todo span com ao menos um atributo de negócio, como user_id ou workflow_id, porque acrescentar esse campo depois de um incidente deixa justo o incidente sem ele.

Preciso de uma plataforma paga para começar?

Não. O primeiro passo útil é envolver as chamadas de modelo e de ferramenta em spans e gravar uma linha estruturada por span. Um arquivo já responde as perguntas do dia do incidente. Plataforma resolve agregação, alerta e retenção, que são problemas de escala, e não de começo. Se for contratar, confira como o fornecedor cobra: em vários planos apenas spans de modelo entram na fatura, o que muda bastante a conta de um sistema com muitas chamadas de ferramenta.

Guardar o conteúdo do prompt no trace é seguro?

Depende do que entra nele. O resultado de ferramenta costuma conter texto escrito por terceiros, e a plataforma de observabilidade normalmente tem política de retenção diferente da do seu banco de dados. A prática defensável é guardar metadado sempre — tamanho, origem, código de status, hash —, conteúdo por amostragem, e conteúdo sensível nunca.

O que levar

  • Bug de agente não se reproduz. O rastro precisa existir antes do erro, porque não haverá segunda observação.
  • A árvore é invoke_agent no topo, com chat e execute_tool como filhos. É ela que permite atribuir latência ao passo certo.
  • Os nomes começam com gen_ai.. Atributo com prefixo llm. não é da convenção, e nome errado custa reescrever painel.
  • O padrão está em obra: repositório separado em junho de 2026, 139 issues abertas, um atributo já renomeado. Instrumente mesmo assim, com o mapeamento isolado.
  • Meça erro por ferramenta. A média esconde a ferramenta que está custando os passos.

O próximo post do cluster trata do par natural desta camada: observabilidade diz o que aconteceu, e avaliação diz se o que aconteceu foi bom. O mapa completo continua no pilar sobre harness engineering.

Leia também