Saltar al contenido
cd /blog

Observabilidad de agentes: hooks, Alloy y Grafana

[Observabilidad][Grafana][OpenTelemetry][Arquitectura]

> Conectamos Claude Code y Codex a un único stack de Grafana con OpenTelemetry y Alloy, y luego usamos trazas y registros para encontrar y corregir problemas de comportamiento de los agentes en su origen.

Los sistemas de agentes fallan de formas extrañas.

A veces el modelo es el problema. A veces la herramienta es el problema. A veces tu servidor MCP está bien, pero el agente eligió al especialista equivocado, o pasó la mitad de la sesión haciendo trabajo de shell que no esperabas, o gastó silenciosamente costo en un bucle que desde afuera parecía productivo.

Si no puedes ver la diferencia, en realidad no estás operando un sistema de agentes. Estás adivinando.

Así que construimos un stack de observabilidad para nuestro propio flujo de trabajo: Claude Code, Codex, eventos de hooks de Claude, eventos de notify de Codex, OpenTelemetry nativo, Grafana Alloy y Grafana Cloud del otro lado.

La parte interesante no es «hicimos un dashboard». La parte interesante es que tuvimos que dividir la telemetría en dos flujos distintos porque ninguna fuente única nos daba el panorama completo.

El problema: la telemetría de agentes está fragmentada

Los agentes de codificación modernos ya emiten algo de telemetría. Eso ayuda, pero no es suficiente.

OTEL nativo es bueno para responder preguntas como:

  • ¿Cuántas solicitudes hicimos?
  • ¿Cuánto costó una sesión?
  • ¿Dónde están los spans y las trazas?
  • ¿Hubo un pico de latencia?

Es mucho peor para responder preguntas como:

  • ¿En qué servidor MCP se apoyó el agente?
  • ¿Esta falla ocurrió en Bash, en una herramienta de archivos integrada o en una llamada MCP?
  • ¿Qué skill se activó realmente?
  • ¿Qué tipo de subagente se despachó?
  • ¿La sesión estaba haciendo trabajo útil o solo dando vueltas?

Esa segunda clase de pregunta vive más cerca de los hooks que de las trazas.

Pero lo inverso también es cierto: algunas de las preguntas de rendimiento más importantes viven más cerca de las trazas que de los hooks.

Si quieres saber dónde se acumuló realmente la latencia, qué spans fueron lentos, o si la sesión gastó tiempo en llamadas al modelo o en ejecución de herramientas, necesitas datos de trazas además de eventos semánticos.

La arquitectura a la que llegamos

Ejecutamos dos rutas de telemetría en paralelo.

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

Esa división es deliberada.

También es asimétrica. Claude Code nos da una superficie de hooks de ciclo de vida mucho más rica. Codex nos da OTEL nativo más una superficie de notify, así que normalizamos eventos de finalización de turno más delgados hacia el mismo esquema de logs, en lugar de fingir que ambos runtimes exponen los mismos controles.

OTEL nativo nos da el flujo base: logs y trazas del runtime mismo, además de métricas donde el runtime realmente las emite.

Los eventos de hooks y notify nos dan la capa semántica: cosas como PreToolUse, PostToolUse, PostToolUseFailure, UserPromptSubmit, SubagentStop, SkillActivated y los metadatos clasificados que realmente nos importan al depurar el comportamiento de los agentes. Claude Code aporta aquí el flujo de eventos más rico. Codex aporta un flujo normalizado más delgado, pero igualmente útil.

Por qué existen los hooks en primer lugar

Nuestro pipeline de hooks enriquece los eventos antes de que lleguen a Loki.

En lugar de simplemente decir «se ejecutó una herramienta», clasificamos el evento en campos como:

  • tool_type: builtin, mcp, skill, agent, bash
  • mcp_server: qué backend MCP manejó la llamada
  • bash_cli: la familia de comandos de shell
  • subagent_type: qué tipo de especialista se despachó
  • agent_tool: si el origen fue Claude Code o Codex

Eso significa que podemos hacer preguntas que importan operativamente:

{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"

Esos no son campos decorativos. Son la diferencia entre «el agente se sintió lento» y «el agente pasó los últimos diez minutos en operaciones de git intensivas en shell con una alta tasa de fallos de herramientas».

Un detalle de implementación que parece más raro de lo que es: el flujo compartido de Loki sigue usando service_name="claude-code-hooks" como etiqueta incluso cuando el evento viene de Codex. La verdadera división entre runtimes ocurre en agent_tool.

Por qué Alloy está en el medio

Grafana Alloy no es solo un reenviador en esta configuración. Es el límite de política.

Apuntamos el flujo OTEL nativo de Claude Code y Codex a un proxy local de Alloy en localhost:4318, y luego dejamos que Alloy limpie el payload antes de reenviarlo a Grafana Cloud.

Eso importa porque la telemetría cruda de agentes está llena de campos de alta cardinalidad que son útiles para el análisis, pero terribles como etiquetas indexadas:

  • session_id
  • prompt_id
  • conteos de tokens
  • duraciones
  • blobs de parámetros de herramientas

Si indexas todo, obtienes una explosión de etiquetas y un mal día.

Así que Alloy hace tres cosas por nosotros:

  1. Mantiene indexado un conjunto muy pequeño de etiquetas de baja cardinalidad.
  2. Mueve los campos ruidosos pero útiles a metadatos estructurados.
  3. Descarta por completo el ruido puro.

La idea importante es simple: observar más, indexar menos.

Por qué el flujo de hooks evita a Alloy

El flujo de hooks ya viene formado para Loki.

Para cuando send_event.py envía un evento, ya hemos decidido qué campos merecen tratamiento de etiqueta y cuáles pertenecen al cuerpo JSON estructurado. Ese flujo va directo a la puerta de enlace OTLP de Grafana Cloud en lugar de pasar de nuevo por Alloy.

Así que el sistema tiene una división de trabajo clara:

  • Alloy doma el flujo OTEL nativo en bruto.
  • El enriquecimiento de hooks hace que los eventos semánticos sean consultables.

Eso mantiene la arquitectura más simple que intentar forzar todo por una sola ruta.

Qué muestra realmente el dashboard

La captura de pantalla de abajo es de uno de los dashboards de observabilidad detrás de nuestro flujo de trabajo con agentes. No es un benchmark, y los números son solo una instantánea en el tiempo. Lo importante es la forma de los datos: feed de actividad, llamadas a herramientas, fallos, prompts y desgloses por agente, herramientas integradas, uso de MCP, comandos de shell y skills.

La parte útil es que este dashboard vive en el mismo stack de Grafana que el resto de la telemetría de agentes. Podemos filtrar por agente de origen y familia de herramientas, y mirar entre runtimes sin inventar una historia de observabilidad distinta para cada sistema.

Dashboard de Grafana que muestra un feed de actividad, conteos de llamadas a herramientas, fallos, prompts y desgloses por agentes, herramientas integradas, uso de MCP, comandos de CLI y skills para un flujo de trabajo de agentes.
Uno de los dashboards en vivo detrás de nuestro flujo de trabajo con agentes. Esta captura es solo una porción de un stack de Grafana compartido que también recibe telemetría de nuestros otros runtimes y sistemas de agentes. Haz clic en la imagen para ver la versión en resolución completa.

Por qué las trazas importan más de lo que parece a primera vista

Los logs nos dicen qué categoría de trabajo ocurrió. Las trazas nos dicen cómo se desarrolló el trabajo a lo largo del tiempo.

Esa distinción importa en los sistemas de agentes porque «lento» es demasiado impreciso para ser útil.

Una traza puede decirnos si el problema vino de:

  • la latencia del modelo
  • el tiempo de ejecución de herramientas
  • reintentos repetidos
  • una interacción MCP especialmente costosa
  • una larga cola de operaciones pequeñas que por separado parecían inofensivas

En la práctica usamos juntos el flujo de hooks y las trazas de Tempo.

  • Los logs de hooks responden: ¿qué tipo de cosa ocurrió?
  • Las trazas responden: ¿a dónde se fue el tiempo?

La combinación es lo que convierte la observabilidad de un dashboard en una explicación.

Dónde encaja Codex

Codex es parte del mismo stack, pero no es idéntico a Claude Code.

Para Codex conectamos dos piezas:

  • OTEL nativo de Codex hacia Alloy
  • Un webhook de notify hacia codex_notify.py, que mapea las finalizaciones de turno al mismo esquema de Loki que usamos para los eventos de hooks

Eso nos da un filtro unificado como agent_tool="codex-cli" dentro del mismo flujo de logs.

La salvedad honesta: el payload de notify de Codex es actualmente más delgado que el payload de hooks de Claude Code porque no es el mismo tipo de superficie de integración. En nuestra configuración actual, las finalizaciones de turno de Codex se pueden normalizar hacia el esquema compartido, pero la extracción detallada herramienta por herramienta sigue siendo mejor en el flujo OTEL nativo que en el puente de notify.

Eso no es una razón para evitar esta publicación. Es justamente el punto de la publicación. Los sistemas de observabilidad reales se ensamblan a partir de señales imperfectas.

Grafana sobre MCP cambia el juego

El cambio más grande es que Grafana ya no es solo un lugar que los humanos visitan en un navegador.

En este repositorio también exponemos Grafana a través de MCP. Eso significa que un agente puede consultar Loki, Prometheus y Tempo directamente, en lugar de esperar a que un humano inspeccione manualmente los dashboards primero.

Eso convierte la observabilidad en una entrada activa del flujo de trabajo.

Un agente puede preguntar:

  • ¿Qué familias de herramientas fallaron más en la última hora?
  • ¿Qué servidor MCP dominó una sesión?
  • ¿Los cambios recientes redujeron los fallos de herramientas o solo movieron el trabajo a rutas más intensivas en shell con los mismos errores?
  • ¿Qué trazas muestran la latencia más alta o reintentos repetidos?

Una vez que tienes eso, estás muy cerca de un bucle de autosuperación.

Del dashboard al bucle de retroalimentación

Esta es la parte que encontramos más interesante.

Una vez que el stack de observabilidad es consultable desde la capa de agentes, la telemetría deja de ser una superficie pasiva de reportes y se convierte en una señal de control.

El bucle se ve así:

  1. La actividad de los agentes emite trazas, métricas y logs de hooks enriquecidos.
  2. Grafana almacena la evidencia en Loki, Tempo y Prometheus donde existen métricas.
  3. Los agentes consultan esa evidencia a través de MCP de Grafana.
  4. El sistema identifica una mala mezcla de herramientas, skills frágiles, enrutamiento débil o flujos de trabajo intensivos en shell que siguen produciendo errores evitables.
  5. Los agentes u operadores ajustan prompts, configuraciones de agentes, descripciones de skills, reglas de enrutamiento o acceso a herramientas.
  6. La siguiente sesión produce una nueva forma de telemetría, y el ciclo se repite.

Así es como pasas de un «dashboard interesante» a un «sistema de mejora medible».

El objetivo no es maximizar una sola categoría de herramientas. Es llegar a la mezcla correcta de CLI, herramientas integradas, llamadas MCP y skills para el trabajo que realmente se está haciendo.

Qué nos permite responder esto

Una vez que ambos runtimes aterrizan en el mismo stack de Grafana, podemos responder preguntas operativas mucho más rápido:

  • ¿Los fallos se concentran en una sola familia de herramientas?
  • ¿Los flujos de trabajo intensivos en shell están creando errores evitables donde debería existir una herramienta de más alto nivel?
  • ¿Qué servidores MCP cargan con la mayor parte del trabajo?
  • ¿Estamos pagando por actividad de agentes que no produce avances significativos?
  • ¿Una sesión no está sana por culpa del modelo, de las herramientas o de la capa de orquestación?

Esto es especialmente útil en flujos de trabajo multiagente, donde «el agente estuvo ocupado» no dice casi nada.

Si un especialista sigue siendo despachado y produciendo altas tasas de fallo, eso es un problema de enrutamiento o de diseño de prompts.

Si un servidor MCP domina todas las llamadas, eso puede ser buena arquitectura o una señal de que todo lo demás es peso muerto.

Si los fallos de herramientas se disparan mientras el costo se mantiene alto, tienes un problema operativo, no un problema de calidad.

Si el trabajo de shell sigue fallando de formas predecibles y evitables donde debería existir una herramienta de más alto nivel, esa es una señal de producto.

Si una skill se activa constantemente pero no mejora los resultados, esa es una señal de prompt o de enrutamiento.

La verdadera lección

La lección más profunda aquí es que la observabilidad de agentes necesita tanto telemetría de runtime como telemetría de flujo de trabajo.

La telemetría de runtime te dice qué hizo el sistema.

La telemetría de flujo de trabajo te dice qué creía el agente que estaba haciendo.

Necesitamos ambas.

Si solo conservas trazas y contadores, te pierdes la capa semántica. Si solo conservas eventos de hooks, te pierdes la latencia, los spans y el panorama más amplio del runtime.

Y si conservas ambas pero nunca las retroalimentas hacia la capa de agentes, tienes monitoreo, no adaptación.

La combinación es lo que hace que el sistema sea lo bastante explicable para operarlo y lo bastante ajustable para mejorarlo.

Lo que todavía es imperfecto

Todavía quedan asperezas.

  • No todos los eventos de hooks incluyen los datos de duración y tokens que quisiéramos.
  • Algunas de las mejores vistas de tiempos siguen viniendo de las trazas de Tempo, no de los logs de hooks.
  • Hoy Codex es semánticamente menos rico que Claude Code en el flujo de eventos enriquecido.
  • La captura del dashboard es una superficie de operaciones en vivo, no una pieza de marketing pulida.

Ese último punto es intencional. Preferimos mostrar el panel de instrumentos real antes que fingir que los sistemas de agentes se explican mágicamente por sí solos.

Por qué esto le importa a Maguyva

Maguyva trata de darles a los agentes mejor inteligencia de código. Pero en cuanto los agentes empiezan a hacer trabajo realmente útil, aparece de inmediato un nuevo requisito: necesitas ver cómo se están comportando.

La calidad de la búsqueda, la calidad del enrutamiento, la selección de herramientas y la eficiencia del contexto se convierten todas en problemas observables.

Por eso creemos que vale la pena escribir sobre esto. El stack de agentes del futuro no es solo prompts y herramientas. Es prompts, herramientas y la capa de instrumentación que te dice si todo el conjunto está funcionando.

Si estás construyendo flujos de trabajo de agentes serios, la observabilidad no es infraestructura opcional. Es parte del producto.

Lectura relacionada

Más del registro de build de Maguyva