Saltar al contenido principal

16 · Agentes y AI Engineering

Observabilidad, auditoría y confiabilidad

Trazas, logs de auditoría encadenados por hash, reintentos, timeouts y cancelación: evidencia que sobrevive al final del turno.

13 minCaso de estudio: docket (se abre en una ventana nueva) · Tack (se abre en una ventana nueva)

En un servicio web, una línea como POST /orders 201 34ms basta para entender qué pasó, porque el código es la explicación. En un , el código del loop es el mismo en cada ejecución; lo que cambia es lo que el modelo decidió. Una línea como agent turn finished ok=false 212s no explica nada: para saber por qué un agente falló, borró un archivo o gastó 80 000 hay que reconstruir su trayectoria.

Esta lección cubre tres disciplinas que suelen confundirse: la (entender qué pasó), la auditoría (probar quién autorizó qué) y la confiabilidad (que las fallas, los reintentos y las paradas dejen el sistema en un estado consistente).

Trazas de un agente

El vocabulario viene del tracing distribuido. Una traza agrupa todo lo que ocurrió en una operación; un span es una operación con inicio, fin y padre. En un agente, la jerarquía natural es tarea → turno → llamada al modelo / tool call:

run 123  "arreglar test_login"               tokens   latencia
├─ model call #1 → grep("def test_login")     3 100    2.1 s
├─ tool grep     decision=allow  ok                    0.1 s
├─ model call #2 → bash("pytest")             4 900    2.8 s
├─ tool bash     decision=ask   aprobado tras 38 s
├─ tool bash     executed  ok=false                    9.4 s
├─ model call #3 → edit("src/auth.py")        7 400    3.5 s
└─ result ok  stop=final_message  duration=81 s

Esta vista responde lo que un log plano no: por qué tardó (38 s esperando una aprobación), por qué costó lo que costó y qué archivos tocó para que el test pasara.

Qué registrar

Registrar siempre Con cuidado Evitar o redactar
ids de ejecución, tarea, rol prompts y respuestas secretos, tokens de acceso
cada tool call, argumentos y decisión contenido de archivos leídos datos personales innecesarios
tokens medidos, latencia, modelo servido salidas de comandos cuerpos completos de APIs externas
transiciones de estado, motivo de parada

Registrar el modelo servido, no solo el pedido, es la defensa más barata contra la degradación silenciosa: el proveedor o un gateway cambia el modelo detrás del mismo nombre y el agente empieza a elegir peor sus herramientas.

El trade-off: un formato propio basta para una persona con grep y se queda corto cuando un programa necesita consumir la historia.

Auditoría no es observabilidad

Concepto Pregunta Propiedad clave
Observabilidad ¿por qué se comportó así? riqueza, consultabilidad
Audit trail ¿quién hizo o autorizó qué, bajo qué regla? completitud, atribución
Tamper-evident ¿alguien alteró el registro? detectar cambios
Inmutable ¿es posible alterarlo? impedir cambios

Una traza puede muestrearse; un audit trail no, porque la acción que falta es justo la que alguien va a preguntar. En un agente, "¿quién hizo esto?" es una cadena: un modelo, un , una tarea encolada, una política y quizá una aprobación humana. Si falta un eslabón, la responsabilidad se diluye.

Cadenas de hashes

Una hash chain hace que cada entrada incluya el hash de la anterior. Editar o borrar una entrada intermedia rompe el vínculo con la siguiente.

Hay que ser preciso con lo que eso garantiza. Una cadena SHA-256 sin clave ni ancla externa detecta la alteración torpe o accidental, pero no a quien tiene acceso de escritura y conoce el algoritmo: puede recalcular toda la cadena o truncar las últimas líneas sin que nada lo delate. Los niveles siguientes son HMAC con una clave fuera del host, anclar periódicamente el hash de cabeza en otro sistema, almacenamiento WORM en otra cuenta y, al final, separación de funciones: quien opera los agentes no administra el almacén de auditoría.

Sobre completitud: docket audita las decisiones que no son un allow simple (tool.deny, tool.ask, aprobaciones, runs.cancel); las ejecuciones permitidas quedan en la traza, que no está encadenada y expira a los 30 días. Hay que saber dónde vive cada evidencia.

Reintentos, timeouts e idempotencia

Un agente suma las fallas de un sistema distribuido, las de un componente probabilístico y las de actuar sobre el mundo real. No todo error merece reintento:

Error ¿Reintentar?
timeout, 429, 502, 503, 504 sí, con espera creciente
400, 401, 403 no, va a fallar igual
JSON del modelo inválido devolverle el error al modelo
la herramienta corrió y falló (test rojo) no es un reintento: es información para el modelo

La receta estándar es exponential backoff con jitter, respetando Retry-After, y un circuit breaker que deja de llamar a un proveedor que falla en serie. Y como tanto el sistema como el modelo van a repetir llamadas, toda herramienta con efectos externos debería ser idempotente o aceptar una clave de .

Cancelación cooperativa

Detener un agente no es matar un proceso. Un kill -9 puede dejar un tool call sin respuesta en el historial, procesos hijos vivos, efectos en vuelo sin revertir y ninguna evidencia de quién paró qué.

Tack llega a lo mismo desde fuera: como las CLIs que ejecuta lanzan sus comandos en sesiones propias, register_probe (crates/tack-runner/src/harness/mod.rs) rechaza cualquier adaptador que declare cancel: supported.

Para CTOs

  • Decide qué adversario cubre tu audit trail antes de elegir el mecanismo: un bug, un operador descuidado o un administrador malicioso piden niveles distintos.
  • Decide dónde terminan los antes de adoptar una plataforma de trazas.
  • Pide el número de "tiempo real de parada" antes de confiar en un botón de cancelar.
  • Exige que cada herramienta con efectos externos declare si es idempotente.

Para llevar

  • Un agente se depura por su trayectoria, no por sus logs: trazas con modelo servido, tokens medidos, decisiones y motivo de parada.
  • Observabilidad, audit trail, tamper-evident e inmutable son requisitos distintos; nómbralos con precisión.
  • Una hash chain local detecta alteraciones torpes, no a un atacante con acceso de escritura que conoce el algoritmo.
  • Reintenta solo lo transitorio, con backoff, y haz idempotentes las herramientas con efectos.
  • Cancelar es cooperativo: pedido durable, puntos seguros y evidencia de cuándo se detuvo.

Comprueba lo aprendido

¿Por qué un audit trail no puede muestrearse y una traza sí?

Una traza sirve para entender comportamientos y sigue siendo útil con una muestra. El audit trail debe responder por cada acción concreta, y la acción que no se registró es justo la que alguien va a preguntar.

¿Qué ataque no detecta una hash chain SHA-256 local sin clave?

Quien tiene acceso de escritura puede reescribir una entrada y recalcular todos los hashes siguientes, o truncar las últimas líneas. Detectarlo exige una clave fuera del host, un ancla externa o almacenamiento que el escritor no controle.

¿Por qué `kill -9` no es una buena forma de detener un agente?

Puede dejar el historial inconsistente, procesos hijos vivos y efectos a medio hacer, sin registro de quién canceló ni qué alcanzó a ejecutarse. La cancelación cooperativa registra el pedido y se detiene en puntos seguros.