Um detalhe do OpenTelemetry para quem instrumenta agentes de IA

OpenTelemetry funciona pra agentes de IA até você bater no limite de 64KB por atributo. Aí seus traces perdem dados silenciosamente. Aqui está o fix.

Se você adicionou OpenTelemetry num agente de IA esse ano, provavelmente seguiu o mesmo caminho que todo mundo segue. Adicionar o ADOT distro. Rodar o entrypoint através do opentelemetry-instrument. Apontar o exporter pro CloudWatch. Deploy. E funciona. Traces aparecem, contagem de tokens aparece, latência aparece. Nada quebrado.

Mas tem uma pergunta sutil escondida nesse setup que a maioria das pessoas nunca faz, e errar essa pergunta é um bug de segurança de verdade. Um que acabou de custar um CVE pra AWS Bedrock AgentCore Python SDK essa semana.

A decisão de design que quase todo mundo ignora

O OpenTelemetry tem convenções semânticas pra IA generativa (o namespace gen_ai.*). A versão 1.41 da spec faz uma decisão de design deliberada que é fácil de perder: ela divide os atributos que um span de agente pode carregar em duas categorias diferentes.

Atributos estruturais são metadados sobre a chamada. Qual modelo. Qual provider. Quantos tokens de input, quantos de output, quanto tempo levou, qual guardrail se aplicou. Esses são seguros pra emitir em todo span por padrão. Eles te contam sobre performance e custo sem expor no que o agente estava trabalhando.

Atributos de conteúdo são os corpos das mensagens em si. gen_ai.input.messages (o prompt). gen_ai.output.messages (a resposta). gen_ai.system_instructions (o system prompt). A spec diz que esses não devem ser emitidos por padrão. Eles têm que ser um opt-in explícito.

A razão pra divisão não é paranoia. Se seu agente é um chatbot de atendimento, o prompt é o que seu cliente escreveu na janela do chat. Se é um agente de análise financeira, o prompt pode ter os números sendo analisados. Se é um agente de resumo médico, o prompt pode ter dado identificável de paciente. Seja qual for o domínio, os corpos das mensagens são dado do cliente. Contagem de tokens e latência não são.

O que aconteceu essa semana

A AWS Bedrock AgentCore Python SDK, que é a biblioteca que você usa pra construir agentes no runtime de agentes do Amazon Bedrock, teve duas versões (1.4.8 e 1.5.0) cuja instrumentação de OpenTelemetry escrevia o prompt completo do usuário e a resposta completa do agente nos atributos de span em toda invocação, sem checar a flag de opt-in. Esses spans depois exportavam pro log group aws/spans do CloudWatch do cliente.

A exposição era local: você precisava de acesso IAM na conta e logs:GetLogEvents no log group de span pra ler qualquer coisa. Nada na internet aberta. Mas uma vez dentro, você via prompts em plaintext e respostas em plaintext. Isso é o CVE-2026-15737, divulgado em 16 de julho, com uma release de fix (bedrock-agentcore 1.5.1) disponível no mesmo dia.

Quero deixar claro por que estou escrevendo esse post. Não é pra cutucar o time do AgentCore. A AWS publicou um advisory claro no mesmo dia que o fix foi liberado, disse pros usuários exatamente o que purgar do CloudWatch, deixou tudo consumível através de um GitHub Security Advisory público, e colocou o fix no pip em poucas horas. Isso é o que um pipeline maduro de disclosure responsável parece. Poder escrever um post assim, de fontes públicas, no mesmo dia que o CVE cai, só é possível porque a transparência tá lá.

A razão de eu estar escrevendo é que a mesma classe de erro é fácil de cometer em qualquer projeto que instrumenta um agente com OpenTelemetry, e o fix é uma escolha de config, não uma escolha de código.

A checagem que eu quero te deixar

Duas perguntas.

Pergunta 1: Seus log groups do CloudWatch contêm atributos de conteúdo?

Roda isso no CloudWatch Logs Insights contra seus grupos /aws/spans/*, ou onde quer que o exporter OTel do seu agente esteja caindo:

1
2
3
4
fields @timestamp, @message
| filter @message like /gen_ai\.input\.messages|gen_ai\.output\.messages|gen_ai\.prompt|gen_ai\.completion/
| sort @timestamp desc
| limit 100

Se retornar linhas, corpos de mensagem estão caindo nos seus logs. Isso é ou intencional (você fez opt-in) ou um escape de design (alguma coisa na sua stack tá com captura de conteúdo ligada por padrão). De qualquer forma, vale saber.

Pergunta 2: Se corpos de conteúdo estão sendo capturados, quem consegue ler?

A managed policy CloudWatchLogsReadOnlyAccess padrão dá leitura em todo log group da conta. Se você tem engenheiros ou terceirizados com acesso amplo de leitura no lado de observabilidade, eles também conseguem ler toda conversa que seu agente teve. Essa é uma decisão pra tomar deliberadamente, não por acidente.

Pra maioria dos agentes em produção, o pattern certo é:

  1. Manter captura de conteúdo desligada por padrão.
  2. Rotear spans estruturais (contagem de tokens, latência, model id) pro seu pipeline geral de observabilidade.
  3. Se precisar de conteúdo pra debug, rotear pra um log group separado com uma chave KMS mais estrita, IAM mais apertado e retenção mais curta.

O switch do lado da instrumentação é uma variável de ambiente. AGENT_OBSERVABILITY_ENABLED=true te dá cobertura estrutural. Captura de conteúdo só acontece se uma biblioteca fizer opt-in explícito através da própria flag dela. O Traceloop chama de TRACELOOP_TRACE_CONTENT. Outros variam. Se você nunca setar a flag de conteúdo, e sua SDK seguir o default de opt-in do v1.41, você tá seguro por design.

Checklist de fix e auditoria

Se você tá construindo no Bedrock AgentCore:

  1. Faça upgrade pra bedrock-agentcore>=1.5.1. A stable atual é 1.15.1 (25 de junho de 2026), então você tá 10 minor bumps atrás se estiver nas releases afetadas.
  2. Roda a query do CWL Insights acima nos seus log groups aws/spans.
  3. Purga o que vazou (deleta os log streams afetados, ou deleta os log groups e deixa o AgentCore recriar).
  4. Audita quem tem logs:GetLogEvents nesses grupos.
  5. Se você tem versões forkadas ou vendorizadas da SDK, aplica o patch nelas também.

Se você tá construindo em qualquer outro framework de agente (LangChain com OTel, Strands Agents, LlamaIndex com observabilidade, sua própria coisa customizada), checa o que sua instrumentação faz com conteúdo por padrão. Nem toda biblioteca respeita o sinal de opt-in do v1.41. A checagem leva dez minutos.

A decisão de design leva dez segundos. Mas é bem mais fácil tomar a escolha certa no dia um do que purgar meses de spans do CloudWatch depois.

Até mais, Leo

Brewed with ☕ since 2017
Criado com Hugo
Tema Stack desenvolvido por Jimmy