Monitorización, alertas y recuperación de fallos en AI Agent: diseño práctico del registro de logs a la máquina de estados

Un informe de Gartner de 2024 señala que el 87 % de los proyectos empresariales de AI Agent superan una tasa de fallo del 25 % en los tres primeros meses tras el despliegue. La causa suele estar enterrada en capas de llamadas a herramientas, con logs dispersos imposibles de rastrear.
La raíz no está en la cantidad de alertas, sino en que la arquitectura de monitorización del Agent es incorrecta desde el principio. Un Agent no es un servicio backend convencional: su carácter no determinista hace que la monitorización tradicional no alcance — la ruta de ejecución se genera dinámicamente y la misma tarea puede seguir caminos distintos. Este artículo te ofrece un diseño completo: de logs a métricas y trazas, hasta la arquitectura de máquina de estados, para convertir el Agent de «caja negra incontrolable» en un sistema transparente donde cada fallo es trazable y recuperable.
Capítulo 1: ¿Por qué la monitorización tradicional falla con los Agent?
¿Te ha pasado? Un Agent falla, revisas los logs y solo encuentras fragmentos de salida del LLM sin poder reconstruir la trayectoria completa. Al final vuelves a ejecutarlo y esperas que esta vez funcione.
La lógica de monitorización de un backend tradicional es clara: entra una petición, pasa por los microservicios A, B y C, cada nodo registra estado y timestamp, y si algo falla sigues la cadena. Un Agent no funciona así.
La ruta de ejecución se genera de forma dinámica. En la misma tarea, la primera vez puede llamar a la herramienta A, la segunda a la B y la tercera saltarse las herramientas por completo. Un informe de OpenAI de 2024 indica que la tasa media de finalización de tareas de Agent es solo del 61,8 % — en gran parte porque el Agent toma decisiones durante el razonamiento y esas decisiones son inherentemente inciertas.
Peor aún está el God Prompt: meter toda la lógica del Agent en un prompt gigante. El blog técnico de ArizenAI lo llama «el asesino número uno en producción». ¿Por qué? Tres problemas: no es testeable, no es depurable y no es predecible.
No puedes hacer unit tests de un prompt de 5 000 palabras. No puedes localizar con precisión qué paso del razonamiento falló. Tampoco puedes predecir si cambiar un parámetro provocará un colapso en cadena. En un proyecto vi un God Prompt donde, tras cambiar un ejemplo, la tasa de éxito cayó del 70 % al 30 %. Tardamos una semana en descubrir que el nuevo ejemplo enseñó al Agent a «priorizar la herramienta A», que en ese escenario no debía invocarse.
OpenAI también destaca un dato: el 82 % de los fallos de Agent son errores reparables. No es falta de capacidad del Agent, sino de robustez del diseño. La monitorización no debe limitarse a «detectar problemas»: debe ser el bucle de retroalimentación que mejora el Agent. Necesitas la tasa de éxito por estado, la latencia de cada llamada a herramienta y la frecuencia de cada tipo de error — esos datos te dicen dónde hay que ajustar.
La mentalidad tradicional es «cuando falle, investigamos». Con Agent, la idea es «cada paso deja rastro; el fallo en sí es una oportunidad de aprendizaje». Ese cambio de perspectiva es el punto de partida de todo el sistema.
Capítulo 2: Arquitectura de observabilidad en tres capas para AI Agent
Monitorizar un Agent no depende de una sola técnica, sino de tres capas superpuestas: logs, métricas y trazas. Cada una resuelve una dimensión distinta.
Primera capa: de logs caóticos a registros estructurados
¿Has visto los logs en bruto de un Agent? Fragmentos de texto generados por el LLM mezclados con stack traces, timestamps dispersos. Sirven para «arqueología» a posteriori, no para monitorización en tiempo real.
La clave de los logs estructurados es etiquetar cada entrada: Agent ID, task ID, estado actual, resumen de entrada y salida. Con esos campos puedes agregar por tarea, filtrar por estado y ordenar por tiempo.
# Ejemplo de logs estructurados
import structlog
logger = structlog.get_logger()
def log_agent_step(agent_id: str, task_id: str, state: str, input: dict, output: dict):
logger.info(
"agent_step",
agent_id=agent_id,
task_id=task_id,
state=state,
input_summary=str(input)[:100], # Truncar para evitar inflación de logs
output_summary=str(output)[:100],
timestamp=time.time()
)
Parece sencillo, pero muchos equipos no lo hacen: vuelcan la salida cruda del LLM al log y esperan que grep saque algo útil. No funciona.
Segunda capa: métricas específicas del Agent
Las métricas responden al análisis de tendencias. Un log te dice que una tarea falló; una métrica te dice que la tasa de fallo está subiendo.
Un Agent necesita cuatro tipos de métricas clave:
| Tipo de métrica | Métricas concretas | Umbral de alerta sugerido |
|---|---|---|
| Consumo de tokens | Total, por tarea, por llamada a herramienta | Por tarea > 10 000 tokens |
| Latencia | P50, P99, tiempo de llamada a herramienta | P99 > 30 s |
| Tasa de error | Fallos de tarea, fallos de herramienta, éxito de reintentos | Tasa de fallo > 20 % |
| Costo | Costo por tarea, costo diario total | Aumento diario del 50 % |
El Dashboard de LangSmith es un buen ejemplo: muestra estas métricas agrupadas por Agent y permite bajar al detalle de cada tarea. Los umbrales deben basarse en datos históricos, no en suposiciones. Ejecuta una semana, calcula el rango normal y fija umbrales en torno al 1,5× del límite superior.
Tercera capa: estándar de trazas OpenTelemetry
Las trazas resuelven la reconstrucción de la cadena. Una Trace empieza en la petición del usuario, pasa por reconocimiento de intención, selección de herramienta, ejecución y validación, hasta la salida final. Cada etapa es un Span con timestamp, estado e entrada/salida.
OpenTelemetry se consolida como estándar de la industria. El blog de PredictionGuard señala que unifica el formato de trazas entre frameworks y herramientas. Los principales frameworks de Agent ya lo soportan: Pydantic AI, smolagents, Strands Agents y LangGraph.
# Ejemplo de trazas OpenTelemetry
from opentelemetry import trace
from opentelemetry.sdk.trace.export import ConsoleSpanExporter
tracer = trace.get_tracer("agent_tracer")
async def run_agent_with_trace(task: str):
with tracer.start_as_current_span("agent_task") as span:
span.set_attribute("task_input", task)
# Reconocimiento de intención
with tracer.start_as_current_span("intent_detection") as intent_span:
intent = await detect_intent(task)
intent_span.set_attribute("intent_result", intent)
# Llamada a herramienta
with tracer.start_as_current_span("tool_call") as tool_span:
result = await call_tool(intent)
tool_span.set_attribute("tool_result", str(result)[:200])
span.set_attribute("final_output", result)
return result
Langfuse y LangSmith soportan importación OpenTelemetry. Puedes recoger trazas con una solución open source e importarlas a una plataforma comercial para visualización y análisis, evitando depender de un solo proveedor.
La ventaja de las tres capas: logs para el detalle, métricas para la tendencia, trazas para la visión global. No pierdes ninguna dimensión.
Capítulo 3: Diseño de máquina de estados — el patrón que hace observable el fallo
El problema del God Prompt es, en esencia, «todo en una olla». Toda la lógica mezclada: cuando algo falla, no sabes qué tramo se rompió. La máquina de estados divide esa olla grande en una cadena de ollas pequeñas.
El blog de ArizenAI cifra la reducción de costo de inferencia en un 80 % con máquina de estados. ¿Cómo? Cada estado hace una sola cosa; el LLM no tiene que razonar desde cero en cada paso.
Máquina de estados vs God Prompt: diferencias de fondo
| Dimensión | God Prompt | Máquina de estados |
|---|---|---|
| Testeabilidad | Imposible unit test | Cada estado se prueba por separado |
| Depurabilidad | Localización vaga del fallo | Límites de estado claros |
| Control de costo | Razona todo el prompt cada vez | Solo la parte necesaria del estado actual |
| Manejo de errores | Oculto en el prompt | Typed transitions con rutas explícitas |
Estructura típica de máquina de estados para Agent:
[Inicialización] → [Reconocimiento de intención] → [Selección de herramienta] → [Ejecución] → [Validación] → [Completado]
↘ ↗
[Manejo de errores]
ArizenAI recomienda entre 5 y 12 estados. Menos, y vuelves al God Prompt; más, y las transiciones se complican demasiado. Cada estado debe tener tipos de entrada y salida bien definidos — eso son las Typed transitions.
# Ejemplo de definición de estados (pseudocódigo)
from typing import TypedDict, Literal
class IntentState(TypedDict):
task_input: str
intent_type: Literal["query", "action", "clarify"]
class ToolState(TypedDict):
intent: IntentState
selected_tool: str
tool_params: dict
class ErrorState(TypedDict):
failed_state: str
error_type: str
retry_count: int
# Transición de estado: ruta de error explícita
def transition_from_intent(intent: IntentState) -> ToolState | ErrorState:
try:
tool = select_tool(intent)
return {"intent": intent, "selected_tool": tool, "tool_params": {}}
except IntentError as e:
return {"failed_state": "intent", "error_type": "ambiguous", "retry_count": 0}
Puntos de monitorización por estado
La máquina de estados convierte cada estado en una unidad natural de monitorización. No hace falta bucear en logs caóticos: miras las métricas por estado.
- Estado de inicialización: hora de inicio de tarea, resultado de comprobación de integridad de entrada
- Estado de reconocimiento de intención: distribución de tipos de intención, tiempo de reconocimiento, tasa de ambigüedad
- Estado de selección de herramienta: frecuencia de llamadas, tiempo de selección, tasa sin herramienta coincidente
- Estado de ejecución: tiempo de ejecución, tasa de éxito, distribución de tipos de fallo
- Estado de validación: tasa de aprobación, intentos de corrección
- Estado de manejo de errores: distribución de tipos de error, éxito de reintentos, activaciones de degradación
Con estas métricas ves de un vistazo qué tramo falla. ¿El reconocimiento de intención pasa de 2 s a 10 s? Puede que el prompt sea demasiado largo. ¿La tasa de fallo de herramientas sube del 5 % al 30 %? Quizá un API externo esté caído.
La máquina de estados afina la granularidad de la monitorización: de «toda la tarea» a «cada paso». Eso es más efectivo que cualquier regla de alerta, porque localizar el problema forma parte de la monitorización.
Capítulo 4: Práctica de ingeniería para recuperación de fallos
La monitorización detecta; la recuperación resuelve. Pero recuperar no es solo «reintentar»: un reintento ciego puede empeorar las cosas.
Clasificación de errores: no todos los fallos son iguales
En los proyectos que he visto, los errores se reparten en tres categorías:
| Tipo | Proporción | Características | Tratamiento |
|---|---|---|---|
| Transitorios | ~60 % | Timeout de API, inestabilidad del servicio, rate limit | Reintento con backoff exponencial (máx. 5 veces) |
| Lógicos | ~30 % | Formato de parámetros incorrecto, herramienta inexistente, intención ambigua | Autorreflexión + ajuste de estrategia |
| En cascada | ~10 % | Caída de servicio core, error de configuración | Bloqueo + degradación |
Datos de Alibaba Cloud indican que un mecanismo de reintento bien diseñado puede subir la tasa de éxito de API del 85 % al 99,5 %. Pero tiene que ser «bien diseñado».
Trampa del reintento: Context Contamination
Un artículo de Arxiv de mayo de 2026 describe un fenómeno contraintuitivo: reintentar a ciegas suele bajar la tasa de éxito.
¿Por qué? La información del fallo «contamina» el razonamiento posterior.
Imagina: el Agent llama a la herramienta A y falla; el error se añade al historial. El Agent ve el error e infiere «la herramienta A falla, pruebo la B». La B también falla. Con dos fallos en el historial, puede concluir «la tarea es demasiado compleja, la abandono».
Eso es Context Contamination: el fallo altera la ruta de razonamiento y empuja intentos posteriores hacia abandonar o elegir estrategias erróneas.
La solución es el aislamiento de estado. Cada reintento no debe heredar todo el historial de fallos, sino reiniciar desde un «estado limpio». O bien comprimir el fallo en un resumen estructurado antes del reintento, en lugar del stack trace crudo.
# Ejemplo de reintento con aislamiento de estado
async def retry_with_clean_state(task: str, error: AgentError, max_retries: int = 3):
for attempt in range(max_retries):
# No pasar el historial completo de fallos, solo un resumen estructurado
error_summary = {
"type": error.type,
"failed_step": error.step,
"hint": get_recovery_hint(error)
}
result = await run_agent_state(
start_state="error_recovery",
context={"original_task": task, "error_summary": error_summary}
)
if result.success:
return result
return {"status": "failed", "reason": "max_retries_exceeded"}
Degradación: admitir el fallo y salir con elegancia
Algunos errores no se recuperan solos. Tras 3-5 fallos consecutivos, toca degradar.
Estrategias según el escenario:
- Simplificar la tarea: dividir en una versión más simple y devolver resultado parcial
- Solicitar intervención humana: pausar la tarea y avisar a operaciones o al usuario
- Respuesta de respaldo: devolver una respuesta genérica predefinida para no cortar la experiencia
NIST SP 800-61 Rev. 3 (actualización de 2025) define seis funciones de respuesta a incidentes: Govern (gobernanza), Identify (identificación), Protect (protección), Detect (detección), Respond (respuesta) y Recover (recuperación). Nació como marco de ciberseguridad, pero encaja en la operación de sistemas Agent.
Mapeo al Agent:
- Govern: umbrales de fallo, estrategias de degradación, responsabilidades
- Identify: clasificar tipos de error, rastrear cadenas de fallo
- Protect: estrategias de degradación predefinidas, circuit breaker
- Detect: monitorización en tiempo real, detección de anomalías
- Respond: activar reintento o degradación, registrar el incidente
- Recover: restaurar servicio normal, retrospectiva y mejora
La ventaja del marco: trata la recuperación como un flujo completo, no como un parche de última hora.
Capítulo 5: Casos prácticos y herramientas recomendadas
La teoría está clara; lo difícil es llevarlo a producción. Aquí van integraciones concretas.
Monitorización LangGraph + Langfuse
LangGraph soporta OpenTelemetry de forma nativa; conectar Langfuse requiere pocas líneas:
from langfuse import Langfuse
from langfuse.callback import CallbackHandler
langfuse_handler = CallbackHandler(
public_key="pk-xxx",
secret_key="sk-xxx",
host="https://cloud.langfuse.com"
)
# Inyectar callback al compilar LangGraph
agent = graph.compile()
result = agent.invoke(
{"input": task},
config={"callbacks": [langfuse_handler]}
)
Langfuse recoge automáticamente trazas de cada nodo: entrada, salida, latencia y consumo de tokens. En el Dashboard puedes ver la cadena completa por task ID.
Endpoint de health check en CrewAI
CrewAI no trae monitorización integrada; conviene diseñar un endpoint de health check:
from fastapi import FastAPI
from crewai import Crew
app = FastAPI()
@app.get("/health")
async def health_check():
# Comprobar tasa de éxito de las últimas 100 tareas
recent_tasks = get_recent_tasks(limit=100)
success_rate = sum(1 for t in recent_tasks if t.status == "success") / len(recent_tasks)
return {
"status": "healthy" if success_rate > 0.8 else "degraded",
"success_rate": success_rate,
"last_error": recent_tasks[-1].error_summary if recent_tasks[-1].status == "failed" else None
}
Este endpoint puede integrarse con los health checks de Kubernetes o alimentar el sistema de alertas.
Matriz de herramientas recomendadas
| Escenario | Herramienta | Características | Equipo ideal |
|---|---|---|---|
| Trazas | Langfuse | OpenTelemetry nativo, open source, self-host opcional | Equipos que necesitan despliegue personalizado |
| Monitorización | LangSmith | Oficial de LangChain, alertas maduras | Equipos en LangChain/LangGraph |
| Logs | Loki + Grafana | Bajo costo, amigable con K8s, infra existente | Despliegues grandes, presupuesto ajustado |
| Detección de anomalías | Luna-2 (modelo pequeño) | Patrones de fallo específicos de Agent, buen filtrado de ruido | Equipos ahogados en alertas ruidosas |
El blog de PredictionGuard señala que modelos pequeños como Luna-2 entienden patrones de fallo propios de Agent mejor que umbrales fijos. Si tu panel dispara decenas de alertas al día y el 90 % es ruido, merece la pena probarlos.
Conclusión
¿Cuánto cambia un sistema completo de monitorización para Agent?
| Dimensión | Sin monitorización | Con monitorización |
|---|---|---|
| Localización | Revisar logs, mucho tiempo | Por estado, respuesta en segundos |
| Recuperación | Reintento ciego, baja tasa de éxito | Tratamiento por categoría, recuperación dirigida |
| Calidad de alertas | Ruido masivo, causa raíz enterrada | Agregación con filtrado, señal clara |
| Mejora del Agent | Ajustar parámetros a ojo | Optimización basada en datos |
Del God Prompt a la máquina de estados, de logs caóticos a trazas OpenTelemetry, del reintento ciego al aislamiento de estado — este cambio no es un «extra», es el camino obligatorio para llevar un Agent a producción.
Si aún sostienes todo el Agent con un prompt gigante, empieza hoy a dividir estados: 5-12 discretos, una responsabilidad cada uno, rutas de fallo explícitas.
Si aún no tienes OpenTelemetry, el momento es ahora. Los frameworks principales ya lo soportan; Langfuse y LangSmith importan trazas directamente.
Reintentar no es la panacea. Context Contamination hunde más a quien solo reintenta. Diseña aislamiento de estado: esa es la vía correcta.
La industrialización del Agent nunca fue «escribir un buen prompt y listo». Monitorización y recuperación son el paso que lo hace realmente controlable.
Construir un sistema de observabilidad para AI Agent
Montaje completo del sistema de monitorización, del registro de logs a la máquina de estados
⏱️ Estimated time: 45 min
- 1
Step 1: Diseñar un formato de logs estructurados
Etiqueta cada log con Agent ID, task ID, estado actual y resumen de entrada/salida. Usa bibliotecas como structlog para unificar el formato y trunca textos largos para evitar la inflación de logs. - 2
Step 2: Configurar las métricas clave del Agent
Monitoriza consumo de tokens (umbral por tarea: 10 000), latencia (P99: 30 s), tasa de error (umbral de fallos: 20 %) y costo (aumento diario del 50 %). - 3
Step 3: Integrar trazas OpenTelemetry
Define un Span en cada etapa, desde la petición del usuario hasta la salida final. Frameworks como LangGraph y Pydantic AI ya lo soportan de forma nativa; importa los datos a Langfuse o LangSmith para visualizarlos. - 4
Step 4: Dividir la arquitectura en máquina de estados
Divide el God Prompt en 5-12 estados discretos, cada uno con una sola responsabilidad, y define rutas de error explícitas con Typed transitions. - 5
Step 5: Implementar clasificación y recuperación de errores
Errores transitorios: reintento con backoff exponencial (máx. 5 veces). Errores lógicos: autorreflexión. Errores en cascada: bloqueo y degradación. Cada reintento usa aislamiento de estado para evitar Context Contamination.
FAQ
¿Por qué la monitorización tradicional falla con los Agent?
¿Cómo reduce el patrón de máquina de estados el costo de inferencia?
¿Qué es Context Contamination?
¿Cómo diseñar umbrales de alerta para Agent?
¿OpenTelemetry o LangSmith?
¿Qué hacer cuando el reintento también falla?
13 min de lectura · Publicado el: 27 may 2026 · Actualizado el: 21 ago 2026
Guía de ingeniería de AI Agents
Si llegaste desde búsqueda, lo más rápido es ir al artículo anterior o siguiente de esta misma serie.
Anterior
¿Cómo evaluar la planificación de un Agent? Guía práctica de profundidad de razonamiento, descomposición de tareas y autocorrección
¿Cómo evaluar la planificación de un Agent? Este artículo detalla metodologías de evaluación para profundidad de razonamiento, descomposición de tareas y autocorrección, compara benchmarks como AgentBench, ToolBench y ACPBench, y ofrece una guía práctica de evaluación.
Parte 14 de 16
Siguiente
Arquitectura DeepAgents: herramientas de planificación, subagentes y sistema de archivos
Análisis en profundidad de los cuatro pilares de DeepAgents: Planning Tools, Sub-agents, File System y System Prompts. Comparación con LangGraph, AutoGen y otros frameworks, con ejemplos de código y buenas prácticas.
Parte 16 de 16



Comentarios
Inicia sesión con GitHub para dejar un comentario