Observabilidade de Agentes: Hooks, Alloy e Grafana
> Conectamos o Claude Code e o Codex a uma única stack do Grafana com OpenTelemetry e Alloy, e depois usamos traces e logs para encontrar e corrigir problemas de comportamento dos agentes na origem.
Sistemas de agentes falham de formas estranhas.
Às vezes o modelo é o problema. Às vezes a ferramenta é o problema. Às vezes o seu servidor MCP está bem, mas o agente escolheu o especialista errado, ou passou metade da sessão fazendo trabalho de shell que você não esperava, ou queimou custo silenciosamente em um loop que parecia produtivo visto de fora.
Se você não consegue ver a diferença, não está realmente operando um sistema de agentes. Está apenas chutando.
Então construímos uma stack de observabilidade para o nosso próprio workflow: Claude Code, Codex, eventos de hook do Claude, eventos de notify do Codex, OpenTelemetry nativo, Grafana Alloy e Grafana Cloud do outro lado.
A parte interessante não é “fizemos um dashboard”. A parte interessante é que tivemos que dividir a telemetria em dois streams diferentes porque nenhum feed único nos dava o quadro completo.
O Problema: a Telemetria de Agentes É Fragmentada
Agentes de codificação modernos já emitem alguma telemetria. Isso ajuda, mas não é suficiente.
O OTEL nativo é bom em responder perguntas como:
- Quantas requisições fizemos?
- Quanto custou uma sessão?
- Onde estão os spans e traces?
- A latência teve um pico?
Ele é muito pior em responder perguntas como:
- Em qual servidor MCP o agente se apoiou?
- Essa falha foi em
Bash, em uma ferramenta de arquivo nativa ou em uma chamada MCP? - Qual skill realmente ativou?
- Que tipo de subagente foi despachado?
- A sessão estava fazendo trabalho útil ou apenas se debatendo?
Essa segunda classe de pergunta vive mais perto dos hooks do que dos traces.
Mas o inverso também é verdadeiro: algumas das perguntas de performance mais importantes vivem mais perto dos traces do que dos hooks.
Se você quer saber onde a latência realmente se acumulou, quais spans estavam lentos, ou se a sessão queimou tempo em chamadas de modelo versus execução de ferramentas, você precisa de dados de trace tanto quanto de eventos semânticos.
A Arquitetura em Que Chegamos
Rodamos dois caminhos de telemetria lado a lado.
Claude Code
native OTEL -> Alloy -> Grafana Cloud
hooks -> send_event.py -> Grafana Cloud Loki
Codex
native OTEL -> Alloy -> Grafana Cloud
notify hook -> codex_notify.py -> shared Loki schema
Essa divisão é deliberada.
Ela também é assimétrica. O Claude Code nos dá uma superfície de hooks de ciclo de vida muito mais rica. O Codex nos dá OTEL nativo mais uma superfície de notify, então normalizamos eventos de conclusão de turno mais rasos no mesmo schema de log, em vez de fingir que os dois runtimes expõem os mesmos controles.
O OTEL nativo nos dá o stream de base: logs e traces do próprio runtime, mais métricas onde o runtime realmente as emite.
Eventos de hook e notify nos dão a camada semântica: coisas como PreToolUse, PostToolUse, PostToolUseFailure, UserPromptSubmit, SubagentStop, SkillActivated, e os metadados classificados com os quais realmente nos importamos ao depurar o comportamento dos agentes. O Claude Code contribui aqui com o stream de eventos mais rico. O Codex contribui com um stream normalizado mais raso, mas ainda útil.
Por Que os Hooks Existem
Nosso pipeline de hooks enriquece eventos antes de chegarem ao Loki.
Em vez de apenas dizer “uma ferramenta rodou”, classificamos o evento em campos como:
tool_type: builtin, mcp, skill, agent, bashmcp_server: qual backend MCP tratou a chamadabash_cli: a família do comando de shellsubagent_type: que tipo de especialista foi despachadoagent_tool: se a origem foi o Claude Code ou o Codex
Isso significa que podemos fazer perguntas que importam operacionalmente:
{service_name="claude-code-hooks"} | agent_tool="codex-cli"
{service_name="claude-code-hooks"} | tool_type="mcp"
{service_name="claude-code-hooks"} | json | bash_cli="git"
Esses não são campos de vaidade. Eles são a diferença entre “o agente pareceu lento” e “o agente passou os últimos dez minutos em operações de git pesadas em shell com alta taxa de falha de ferramentas”.
Um detalhe de implementação que parece mais estranho do que é: o stream compartilhado do Loki ainda usa service_name="claude-code-hooks" como label mesmo quando o evento vem do Codex. A divisão real entre runtimes acontece em agent_tool.
Por Que o Alloy Fica no Meio
O Grafana Alloy não é apenas um encaminhador nesta configuração. Ele é a fronteira de política.
Apontamos o stream de OTEL nativo do Claude Code e do Codex para um proxy Alloy local em localhost:4318, e então deixamos o Alloy limpar o payload antes de encaminhá-lo para o Grafana Cloud.
Isso importa porque a telemetria bruta de agentes está cheia de campos de alta cardinalidade que são úteis para análise, mas terríveis como labels indexados:
session_idprompt_id- contagens de tokens
- durações
- blobs de parâmetros de ferramentas
Se você indexar tudo, você tem uma explosão de labels e um dia ruim.
Então o Alloy faz três coisas por nós:
- Mantém indexado um conjunto muito pequeno de labels de baixa cardinalidade.
- Move campos ruidosos, mas úteis, para metadados estruturados.
- Descarta ruído puro por completo.
A ideia importante é simples: observe mais, indexe menos.
Por Que o Stream de Hooks Contorna o Alloy
O stream de hooks já vem formatado para o Loki.
No momento em que send_event.py envia um evento, já decidimos quais campos merecem tratamento de label e quais pertencem ao corpo JSON estruturado. Esse stream vai direto para o gateway OTLP do Grafana Cloud, em vez de passar novamente pelo Alloy.
Então o sistema tem uma divisão de trabalho clara:
- O Alloy doma o stream bruto de OTEL nativo.
- O enriquecimento de hooks torna os eventos semânticos consultáveis.
Isso mantém a arquitetura mais simples do que tentar forçar tudo por um único caminho.
O Que o Dashboard Realmente Mostra
A captura de tela abaixo é de um dos dashboards de observabilidade por trás do nosso workflow de agentes. Não é um benchmark, e os números são apenas um recorte de um momento específico. O ponto é o formato dos dados: feed de atividade, chamadas de ferramentas, falhas, prompts, e detalhamentos por agente, ferramentas nativas, uso de MCP, comandos de shell e skills.
A parte útil é que esse dashboard vive na mesma stack do Grafana que o restante da telemetria de agentes. Podemos filtrar por agente de origem e família de ferramenta, e olhar entre runtimes sem inventar uma história de observabilidade diferente para cada sistema.
Por Que os Traces Importam Mais do que Parecem à Primeira Vista
Logs nos dizem que categoria de trabalho aconteceu. Traces nos dizem como o trabalho se desenrolou ao longo do tempo.
Essa distinção importa em sistemas de agentes porque “lento” é grosseiro demais para ser útil.
Um trace pode nos dizer se a dor veio de:
- latência do modelo
- tempo de execução de ferramentas
- retries repetidos
- uma interação MCP especialmente cara
- uma longa cauda de pequenas operações que pareciam inofensivas isoladamente
Na prática, usamos o stream de hooks e os traces do Tempo juntos.
- Os logs de hook respondem: que tipo de coisa aconteceu?
- Os traces respondem: para onde foi o tempo?
A combinação é o que transforma a observabilidade de um dashboard em uma explicação.
Onde o Codex se Encaixa
O Codex faz parte da mesma stack, mas não é idêntico ao Claude Code.
Para o Codex, conectamos duas peças:
- OTEL nativo do Codex para o Alloy
- Um webhook de notify para
codex_notify.py, que mapeia conclusões de turno para o mesmo schema do Loki que usamos para eventos de hook
Isso nos dá um filtro unificado como agent_tool="codex-cli" dentro do mesmo stream de logs.
A ressalva honesta: o payload de notify do Codex hoje é mais raso do que o payload de hook do Claude Code, porque não é o mesmo tipo de superfície de integração. Na nossa configuração atual, as conclusões de turno do Codex podem ser normalizadas para o schema compartilhado, mas a extração rica ferramenta por ferramenta ainda é melhor no stream de OTEL nativo do que na ponte de notify.
Isso não é motivo para evitar o post. É o ponto do post. Sistemas de observabilidade reais são montados a partir de sinais imperfeitos.
O Grafana Sobre MCP Muda o Jogo
A mudança maior é que o Grafana não é apenas um lugar que humanos visitam em um navegador.
Neste repositório, também expomos o Grafana via MCP. Isso significa que um agente pode consultar o Loki, o Prometheus e o Tempo diretamente, em vez de esperar que um humano inspecione manualmente os dashboards primeiro.
Isso transforma a observabilidade em uma entrada ativa do workflow.
Um agente pode perguntar:
- Quais famílias de ferramentas falharam mais na última hora?
- Qual servidor MCP dominou uma sessão?
- As mudanças recentes reduziram as falhas de ferramentas ou apenas moveram o trabalho para caminhos mais pesados em shell com os mesmos erros?
- Quais traces mostram a maior latência ou retries repetidos?
Quando você tem isso, está muito perto de um loop de autoaperfeiçoamento.
Do Dashboard ao Loop de Feedback
Esta é a parte que achamos mais interessante.
Assim que a stack de observabilidade se torna consultável a partir da camada de agentes, a telemetria deixa de ser uma superfície de relatório passiva e se torna um sinal de controle.
O loop funciona assim:
- A atividade dos agentes emite traces, métricas e logs de hook enriquecidos.
- O Grafana armazena a evidência no Loki, no Tempo e no Prometheus, onde existem métricas.
- Os agentes consultam essa evidência através do Grafana MCP.
- O sistema identifica mix ruim de ferramentas, skills frágeis, roteamento fraco ou workflows pesados em shell que continuam produzindo erros evitáveis.
- Agentes ou operadores ajustam prompts, configurações de agente, descrições de skills, regras de roteamento ou acesso a ferramentas.
- A próxima sessão produz um novo formato de telemetria, e o ciclo se repete.
É assim que você passa de “dashboard interessante” para “sistema de melhoria mensurável”.
O objetivo não é maximizar uma categoria de ferramenta. É chegar à combinação certa de CLI, ferramentas nativas, chamadas MCP e skills para o trabalho que está realmente sendo feito.
O Que Isso Nos Permite Responder
Assim que os dois runtimes chegam à mesma stack do Grafana, conseguimos responder perguntas operacionais muito mais rápido:
- As falhas estão concentradas em uma família de ferramentas?
- Workflows pesados em shell estão criando erros evitáveis onde deveria existir uma ferramenta de nível mais alto?
- Quais servidores MCP estão carregando a maior parte do trabalho?
- Estamos pagando por atividade de agente que não está produzindo progresso significativo?
- Uma sessão está insalubre por causa do modelo, das ferramentas ou da camada de orquestração?
Isso é especialmente útil em workflows multiagente, em que “o agente estava ocupado” não diz quase nada.
Se um especialista continua sendo despachado e produzindo altas taxas de falha, isso é um problema de roteamento ou de moldagem de prompt.
Se um servidor MCP domina todas as chamadas, isso pode ser boa arquitetura ou um sinal de que todo o resto é peso morto.
Se as falhas de ferramentas disparam enquanto o custo permanece alto, você tem um problema operacional, não um problema de qualidade.
Se o trabalho de shell continua falhando de formas previsíveis e evitáveis onde deveria existir uma ferramenta de nível mais alto, isso é um sinal de produto.
Se uma skill ativa constantemente, mas não melhora os resultados, isso é um sinal de prompt ou de roteamento.
A Lição Real
A lição mais profunda aqui é que a observabilidade de agentes precisa tanto de telemetria de runtime quanto de telemetria de workflow.
A telemetria de runtime diz o que o sistema fez.
A telemetria de workflow diz o que o agente achava que estava fazendo.
Precisamos das duas.
Se você mantém apenas traces e contadores, perde a camada semântica. Se você mantém apenas eventos de hook, perde latência, spans e o panorama mais amplo do runtime.
E se você mantém os dois, mas nunca os realimenta na camada de agentes, você tem monitoramento, não adaptação.
A combinação é o que torna o sistema explicável o suficiente para operar e ajustável o suficiente para melhorar.
O Que Ainda É Imperfeito
Ainda há arestas a aparar.
- Nem todo evento de hook inclui os dados de duração e de tokens que gostaríamos.
- Algumas das melhores visões de tempo ainda vêm dos traces do Tempo, não dos logs de hook.
- O Codex hoje é semanticamente menos rico do que o Claude Code no stream de eventos enriquecido.
- A captura de tela do dashboard é uma superfície de operações ao vivo, não uma peça de marketing polida.
Esse último ponto é intencional. Preferimos mostrar o painel de instrumentos real a fingir que sistemas de agentes se explicam magicamente.
Por Que Isso Importa Para o Maguyva
O Maguyva é sobre dar aos agentes uma inteligência de código melhor. Mas assim que os agentes realmente começam a fazer trabalho útil, um novo requisito aparece imediatamente: você precisa ver como eles estão se comportando.
Qualidade de busca, qualidade de roteamento, seleção de ferramentas e eficiência de contexto, tudo isso se torna um problema observável.
É por isso que achamos que vale a pena escrever sobre isso. A pilha de agentes do futuro não é só prompts e ferramentas. É prompts, ferramentas e a camada de instrumentação que diz se tudo isso está funcionando.
Se você está construindo workflows de agentes sérios, observabilidade não é infraestrutura opcional. É parte do produto.
Leituras relacionadas
Mais do log de build do Maguyva
Por Que Atualizamos a Busca de Código para o voyage-4-large_
Migramos nossos embeddings de código para o voyage-4-large — atualmente no topo do ranking público RTEB de retrieval de código. A versão honesta: o trade-off que fazemos, o que realmente indexamos, e por que pagamos por embeddings premium.
Autoaperfeiçoamento Recursivo de Linguagens: Aprimorando a Inteligência de Código em ~280 Linguagens_
Damos suporte a inteligência de código para ~280 linguagens. Nenhum humano consegue auditar isso manualmente. Por isso construímos um loop de autoaperfeiçoamento recursivo de linguagens — verificação pontual, LLM como juiz, corrigir uma coisa, revalidar — e o rodamos com uma frota de agentes isolados até que a extração esteja realmente correta, não apenas verde.
Busca com Fusão Multimodal: Escolhendo o Retriever Certo Para Cada Consulta_
Uma consulta como 'onde parseConfig é definido' quer um tipo de busca diferente de 'como funciona a autenticação'. O Maguyva classifica a intenção, pondera quatro modalidades de retrieval de acordo, e funde os resultados com Reciprocal Rank Fusion ponderada.