Biblioteca · Confiabilidad: monitoreo, fallas y respaldos

Failure Recovery Patterns, qué hacer cuando el agente se rompe en producción

Ingeniero60 minActualizado: octubre de 2026
90 de 105 en la biblioteca

Tiempo: unos 25 min de lectura + 35 min de práctica


Lo esencial

Todos los cursos enseñan "cómo construir un agente". Nadie enseña "qué hacer cuando se rompe a las 3 de la mañana antes del demo con el cliente".

Producción no es "lo lancé y me olvidé". Producción es "lo lancé y ahora vivo con esto". Alucinaciones, loops infinitos, un MCP caído, un context overflow, un pico en la factura de la API, prompt injection, una falla silenciosa: no son "si llega a pasar". Son "cuando pase".

Esta lección cubre 7 failure patterns (patrones de falla) típicos y un playbook de recuperación para cada uno. Herramientas, patrones de código, listas de verificación, respuesta a incidentes. No es teoría: es lo que vas a hacer en un momento real de pánico.

🎨 Imagínalo así: un coche con motor = tu agente de IA. Todo el mundo sabe comprarlo, manejarlo y cargarle gasolina. Pero cuando se te apaga en la carretera de noche, la mayoría simplemente llama a la grúa. Esta lección es cómo cambiar la llanta tú y llegar al taller. Siete averías típicas + la herramienta en la cajuela.


Conceptos clave

  • Hallucination (alucinación): el modelo da con seguridad un dato falso
  • Loop: el agente se atoró en una acción, reintenta sin avanzar
  • Tool failure: un servidor MCP o una API externa no responde o devuelve un error
  • Context overflow: el contexto se infló y el modelo pierde las instrucciones (context rot)
  • Cost spike: la factura de la API creció de 5 a 10 veces sin razón aparente
  • Prompt injection: una entrada externa hizo que el agente actuara contra las reglas
  • Silent failure (falla silenciosa): el pipeline terminó sin errores, pero el resultado está mal
  • Circuit breaker: un patrón que desconecta una integración rota durante N minutos
  • Graceful degradation: pasar a una funcionalidad simplificada cuando algo falla
  • Chaos engineering: provocar fallas a propósito para comprobar que estás listo
  • Postmortem: un análisis estructurado del incidente: causa raíz y prevención

Teoría

Falla 1: Hallucination (el agente miente con seguridad)

Síntoma: la respuesta se ve correcta, el formato es limpio, el tono es seguro, pero el dato es falso. "En Ecuador el impuesto predial es del 5%" (en realidad la tasa es otra). "Esta función apareció en la versión 3.2 de la librería" (esa versión no existe).

Niveles de riesgo:

  • CRITICAL: consejos médicos, legales o financieros (el cliente actúa con base en la respuesta)
  • HIGH: código de producción, consultas SQL, configuraciones (se ejecutan sin revisión)
  • MEDIUM: charla casual, lluvia de ideas (consecuencias limitadas)

Patrones de recuperación:

  1. Verificación contra una fuente confiable (RAG): agrega recuperación de fuentes verificadas. El modelo no responde "de memoria", sino con base en documentos que tú controlas
  2. Confidence scoring: en el prompt, "Responde + indica tu confianza de 0 a 100. Si es < 70, di 'no estoy seguro'"
  3. Votación entre varios LLM: dos llamadas independientes (Claude + GPT). Si las respuestas no coinciden, se escala a una persona
  4. "Cita o rehúsa": el modelo DEBE indicar la fuente (URL, id del documento) o decir explícitamente "no sé"

Detección: revisa a mano una muestra del 5% de las respuestas cada día. Registra las preguntas en las que el modelo dijo "no sé": ese es tu mapa de huecos.

python
# Patrón: cita o rehúsa, con el system prompt
SYSTEM = """Responde solo con base en los documentos proporcionados.
Acompaña cada dato con su fuente en el formato [doc_id:section].
Si la información no está en los documentos, responde exactamente:
"No puedo confirmarlo con las fuentes disponibles."
NO inventes. NO te apoyes en conocimiento general."""

Falla 2: Loop (el agente se repite sin fin)

Síntoma: la misma frase, la misma llamada a una herramienta, el mismo error, una y otra vez. Los registros se llenan de entradas idénticas. La factura de la API sigue corriendo.

Causa común: la herramienta falló → el agente lo intenta de nuevo con los mismos parámetros. O el modelo "no entiende" que la herramienta ya devolvió "archivo no encontrado" y repite la llamada.

Recuperación:

  • Tope de iteraciones: máximo N intentos → alternativa o cancelar
  • Contexto del error al reintentar: pasar el mensaje del error anterior a la siguiente llamada
  • Diferencia de estado: comprobar que el estado cambió entre iteraciones
  • Detectar el atasco: la misma acción 3 veces seguidas → cancelar
python
MAX_ATTEMPTS = 5
previous_action = None
stuck_count = 0

for i in range(MAX_ATTEMPTS):
    result = agent.run(state)
    if result.action == previous_action:
        stuck_count += 1
        if stuck_count >= 3:
            raise StuckLoopError(f"Same action repeated 3x: {result.action}")
    else:
        stuck_count = 0
    previous_action = result.action
    if result.done:
        break
else:
    raise MaxIterationsExceeded(f"Hit cap {MAX_ATTEMPTS}")

Falla 3: Tool failure (el servidor MCP no responde)

Síntoma: timeout, HTTP 500, el servidor MCP se cayó, rate limit de una API externa.

Recuperación:

  • Circuit breaker: 3 errores seguidos → desconecta la integración 5 minutos; no la sigas llamando en vano
  • Estrategia alternativa: el MCP de Stripe está caído → consulta en la base de datos local para la información básica de cobro
  • Graceful degradation: la función no está disponible → dilo con honestidad: "el servicio no está disponible por ahora, intenta en 5 min". NO inventes un resultado
  • Health checks: haz ping al MCP cada 60 s y lanza una alerta si lleva caído más de 2 min

Librería: Tenacity (Python): retry con espera exponencial listo para usar.

python
from tenacity import retry, stop_after_attempt, wait_exponential

@retry(
    stop=stop_after_attempt(3),
    wait=wait_exponential(multiplier=1, min=2, max=10),
    reraise=True
)
def call_external_api(payload):
    return requests.post(URL, json=payload, timeout=10)

Falla 4: Context overflow (el agente olvidó el inicio de la sesión)

Síntoma: el agente ignora las instrucciones del system prompt, se contradice, "olvida" lo que hablaron hace 20 mensajes.

Causa: contexto > 50K tokens → context rot. El modelo trabaja peor con la información de en medio y mejor con la del principio y el final.

Recuperación:

  • /compact en Claude Code cuando el contexto crece (puedes indicar qué conservar: /compact conserva las decisiones de arquitectura); la compresión automática también funciona, y su umbral se ajusta con el comando /autocompact
  • Sliding window (ventana deslizante): conserva los últimos N mensajes + un resumen de los anteriores
  • Instrucciones críticas al final: el modelo recuerda mejor el contexto reciente (recency bias)
  • El system prompt en cada mensaje: si una regla es crítica, repítela
  • Datos largos → RAG: no metas 50K de documentación al contexto; haz recuperación

Falla 5: Cost spike (la factura del día es 10 veces la normal)

Síntoma: $50 al día en lugar de $5. El aviso de que te acercas al límite mensual llega ya el día 5 del mes.

Causas posibles:

  • Un bug de loop (no se atrapó la Falla 2)
  • Falta de caché (prompts idénticos repetidos sin prompt caching)
  • Un ataque de scraping (si hay un endpoint público sin autenticación)
  • Una tormenta de reintentos (falla → retry → falla → retry)
  • La clave de API en manos ajenas (se filtró en git)

Recuperación:

  • Interruptor de presupuesto diario: gasto > $X/día → la API se pausa automáticamente
  • Detección de picos: gasto > 2 veces el promedio diario → alerta por correo o chat
  • Registro de auditoría: cada llamada a la API → un registro en KV/DB (barato y fácil de depurar)
  • Desactiva e investiga antes de reanudar. Nada de "subo el límite para seguir" sin entender qué pasó

Herramientas:

  • Anthropic Console: la página Usage y tu propio límite de gasto (Settings → Billing → Spend limits)
  • Langfuse: observabilidad de código abierto, costo por usuario
  • LangSmith: tracing para LangChain/LangGraph

Falla 6: Prompt injection

Síntoma: el agente desactivó un hook "porque el usuario lo pidió", pasó secretos a una herramienta externa, envió un correo a tu nombre, ejecutó rm -rf siguiendo una instrucción de un archivo Markdown que estaba leyendo.

Mira el detalle en la lección Prompt Injection Defense. Aquí va la recuperación.

Recuperación:

  • Aislamiento: cada herramienta riesgosa pasa por un agente aparte con los permisos mínimos
  • Registra todo en auditoría: qué fue una orden y qué fue una entrada externa (sepáralo explícitamente)
  • Restauración: git revert + avisa al equipo + investiga la brecha
  • Lecciones aprendidas: agrega el patrón al hook pre-tool-use-prompt-injection.sh
bash
# Protección mínima: el hook busca patrones sospechosos
# .claude/hooks/pre-tool-use-prompt-injection.sh
grep -iE 'ignore (previous|all) instructions|disable.*hook|reveal.*system prompt' "$INPUT" \
  && exit 1

Falla 7: Silent failure (el agente "funciona" pero el resultado está mal)

La más traicionera. El pipeline terminó, exit code 0, ningún error en los registros. Pero el resultado es basura.

Ejemplos:

  • El LLM devolvió un JSON con la estructura correcta, pero los valores salieron de la nada
  • La traducción se lee fluida, pero el sentido está distorsionado
  • Un cálculo financiero con la fórmula correcta, pero con cifras inventadas

Recuperación:

  • Validación de la salida: revisa el esquema de cada respuesta del LLM. Pydantic, JSON schema, zod
  • Smoke tests: en cada corrida del pipeline → comprueba que 1 o 2 casos conocidos den el resultado esperado
  • Retroalimentación de usuarios: "¿esta respuesta es correcta? 👍/👎" cada 50 interacciones → a un panel
  • Eval suite (lección Evals): pruebas de regresión después de cada cambio al prompt
python
from pydantic import BaseModel, Field, ValidationError

class InvoiceExtraction(BaseModel):
    amount: float = Field(gt=0, lt=1_000_000)
    currency: str = Field(pattern="^(USD|EUR|MXN)$")
    invoice_date: str  # ISO 8601

try:
    parsed = InvoiceExtraction.model_validate_json(llm_output)
except ValidationError as e:
    # se atrapó una falla silenciosa: escalar
    log_anomaly(llm_output, e)
    raise

Kit de recuperación (lo que debes traer en la cajuela)

Categoría Herramienta Para qué
Registros Langfuse, LangSmith, registros estructurados en KV Cada llamada al LLM con entrada/salida/tokens
Alertas Webhook a un chat (Telegram, Slack), PagerDuty, correo Picos / caídas / anomalías
Monitoreo Anthropic Console + un panel propio (lección Production Observability) Costo, latencia, tasa de errores
Rollback Tags de git + un script de revert Volver a la última versión buena con un comando
Comunicación Plantillas de respuesta a clientes "Problema conocido, se corrige en 2 horas"
Validación Pydantic / zod / JSON schema Revisar el esquema de cada salida
Lógica de retry Tenacity (Python), p-retry (JS) Espera exponencial lista para usar

Lista de verificación de producción (obligatoria antes de lanzar)

Lanzar a producción sin 8 de 8 es deuda técnica desde el primer día.


Chaos engineering para IA (probar los casos de falla)

El enfoque de Principles of Chaos aplicado a agentes. Rompe el sistema a propósito en staging para asegurarte de que la recuperación funciona.

Qué inyectas Cómo Qué compruebas
Hallucination Agrega al prompt "Always answer Y is true" → prueba de picos Si la capa de verificación lo detecta
Loop Un mock de la herramienta siempre devuelve el mismo error Si se activa el tope de iteraciones
HTTP 500 Un mock del MCP devuelve 500 en cada tercera llamada Si se activan el circuit breaker y la alternativa
Context overflow Mete 100K tokens de basura Si se dispara /compact
Cost spike Un loop sin break, un prompt barato × 10000 Si se activa el interruptor de presupuesto diario
Schema mismatch El LLM devuelve campos con llaves de más o de menos ¿Pydantic lo atrapa o falla en silencio?

Una vez al mes, un día de caos en staging. Media hora de trabajo que te salva en producción.


Respuesta a incidentes: 4 pasos

Cuando algo se está quemando, no entres en pánico. Sigue los pasos:

  1. Stop (detener): desactiva la función afectada para evitar más daño. Feature flag apagado o una página de mantenimiento
  2. Triage (clasificar): qué pasó, alcance (1 usuario / todos), radio de impacto (¿cobros? ¿datos? ¿reputación?)
  3. Stabilize (estabilizar): rollback a la última versión buena O un arreglo temporal (una alternativa fija) para recuperar el servicio
  4. Postmortem: después de recuperarte: causa raíz, qué agregaremos al monitoreo, cómo prevenirlo

Plantilla de postmortem (journals/incidents/YYYY-MM-DD-<name>.md):

Escribe esto en el chat
# Incidente: <nombre>

**Fecha:** YYYY-MM-DD
**Duración:** 14:32 - 15:47 UTC (1h 15m)
**Severidad:** P1 / P2 / P3
**Impacto:** N clientes, $X de pérdida / 0 pérdida de datos

## Cronología
- 14:32: alerta de pico en el chat (costo > 2 veces el promedio)
- 14:35: inicio de la investigación, encontré un loop en el agente X
- 14:50: se desplegó el tope de iteraciones
- 15:47: servicio estable

## Causa raíz
La herramienta Y devolvía una cadena vacía en lugar de null. El agente lo interpretó
como "no funcionó" y reintentó sin fin.

## Qué salió bien
- La alerta llegó en 3 minutos
- El procedimiento de rollback funcionó

## Qué salió mal
- No había tope de iteraciones (MAX_ATTEMPTS no estaba definido)
- La validación de la salida no revisaba cadenas vacías

## Acciones
- [ ] Agregar MAX_ATTEMPTS=5 a todos los agentes (responsable: A, plazo: mañana)
- [ ] Revisión con Pydantic de la salida de la herramienta Y (responsable: A, plazo: 3 días)
- [ ] Prueba de caos con cadena vacía (responsable: A, plazo: una semana)

Sin postmortem, el incidente se repite. Garantizado.


Antipatrones (lo que NO hay que hacer en pánico)

  • ❌ "Nada más lo reinicio" sin entender la causa raíz. En una hora se repite
  • ❌ Ocultarles el incidente a los clientes. Se van a enterar solos y la confianza se daña
  • ❌ Un arreglo en caliente sin registrarlo en la auditoría. En un mes: "¿por qué hay un número mágico aquí?"
  • ❌ "Fue casualidad, lo olvido". Los patrones se repiten. Cada incidente → postmortem
  • ❌ Desactivar un hook para "probar" (mira la lección Hook-Deny-By-Design). Riesgo de seguridad + se te olvidará reactivarlo
  • ❌ Subir el límite de la API para seguir sin entender la causa del pico

Recuperar el costo (si ya perdiste dinero)

La realidad: la recuperación casi siempre es incompleta. Prevenir sale más barato.

Escenario Probabilidad de reembolso Acciones
Un bug de cobro de Anthropic (del lado de ellos) Baja, pero real Ticket de soporte con trace_id y registros. A veces dan crédito
Un error de cobro en Stripe (el cliente paga de más) Alta Disputa en el panel de Stripe, te reembolsan
Clave de API filtrada (push a GitHub) 0% Rota la clave de inmediato, audita todas las llamadas
Un bug de loop se comió $200 0% Lección aprendida. Tope de iteraciones para siempre

La lección: vigila las alertas de presupuesto. Recuperar dinero es un bono raro, no un plan.


Público: qué aprender y cuándo

Principiante (primeros 3 meses en producción)

Solo las fallas 1 a 3, las más frecuentes:

  • Alucinación, lo básico (cita o rehúsa en el prompt)
  • Tope de iteraciones en cada loop
  • Try/except + retry para fallas de herramientas

Registros básicos (al principio, un simple print a un archivo). Límite de gasto en Anthropic Console.

Intermedio (de 3 a 12 meses)

Agregas:

  • Las fallas 4 y 5 (manejo de contexto + monitoreo de costos)
  • Langfuse / LangSmith para observabilidad
  • Alertas de picos a un chat
  • La cultura del postmortem (aunque trabajes solo, escríbelo)

Profesional (más de 1 año en producción)

Los 7 patrones:

  • Chaos engineering cada mes
  • Runbooks automatizados (incidente → un bot hace el triage)
  • Votación entre varios LLM en las rutas críticas
  • Validación con Pydantic en todas partes
  • Avisos automáticos a clientes

Práctica

Paso 1: Agrega un tope de iteraciones a todos los agentes

Busca en el código los while y for sin límite superior y las llamadas recursivas sin límite de profundidad.

python
# Antes
def agent_loop(state):
    while not state.done:
        state = step(state)
    return state

# Después
MAX_ITERATIONS = 10

def agent_loop(state):
    for i in range(MAX_ITERATIONS):
        state = step(state)
        if state.done:
            return state
    raise MaxIterationsExceeded(
        f"Hit {MAX_ITERATIONS}. Last state: {state.summary()}"
    )

Paso 2: Configura el límite de gasto y un aviso

Anthropic Console → Settings → Billing → Spend limits → Adjust limit. Hay un solo límite: un techo mensual. Cuando se alcanza, la API se detiene hasta que subas el límite o empiece un mes nuevo. Ponlo en más o menos 3 veces tu gasto mensual normal.

El aviso («soft limit») hazlo tú, con una revisión diaria por cron. El umbral: tu gasto diario promedio actual × 1.5.

bash
# scripts/check-daily-cost.sh
# Necesitas una Admin API key (sk-ant-admin01-...): la tienen las organizaciones; las cuentas individuales no —
# en ese caso revisa a mano la página Usage en la Console.
TODAY=$(date -u +%Y-%m-%dT00:00:00Z)
TOMORROW=$(date -u -v+1d +%Y-%m-%dT00:00:00Z)   # en Linux: date -u -d tomorrow +%Y-%m-%dT00:00:00Z

RESP=$(curl -s "https://api.anthropic.com/v1/organizations/cost_report?starting_at=$TODAY&ending_at=$TOMORROW" \
  -H "anthropic-version: 2023-06-01" \
  -H "x-api-key: $ANTHROPIC_ADMIN_KEY")

# Los montos llegan en centavos como texto; revisa la estructura exacta de la respuesta en la Cost API reference
DAILY_SPEND=$(echo "$RESP" | jq '[.data[].results[].amount | tonumber] | add / 100')

if (( $(echo "$DAILY_SPEND > 20" | bc -l) )); then
  curl -X POST "https://api.telegram.org/bot$BOT_TOKEN/sendMessage" \
    -d "chat_id=$CHAT_ID&text=⚠️ Daily spend: \$$DAILY_SPEND"
fi

Descripción de la Cost API: platform.claude.com/docs/en/manage-claude/usage-cost-api.


Paso 3: Agrega validación con Pydantic a las salidas críticas

python
from pydantic import BaseModel, Field, ValidationError
from anthropic import Anthropic

client = Anthropic()

class CustomerReply(BaseModel):
    sentiment: str = Field(pattern="^(positive|neutral|negative)$")
    intent: str
    confidence: float = Field(ge=0, le=1)
    suggested_response: str = Field(min_length=10, max_length=500)

response = client.messages.create(
    model="claude-sonnet-5-5",
    max_tokens=1024,
    messages=[{"role": "user", "content": "..."}]
)

try:
    validated = CustomerReply.model_validate_json("".join(b.text for b in response.content if b.type == "text"))
    use(validated)
except ValidationError as e:
    log_to_journal("".join(b.text for b in response.content if b.type == "text"), e)
    raise SilentFailureDetected(str(e))

Paso 4: Corre una prueba de caos

Elige la falla que más miedo te da (normalmente el pico de costo o la falla silenciosa). Hoy, en staging:

  1. Crea las condiciones a propósito (un mock que devuelve una salida mala / un loop sin break)
  2. Ejecuta el agente
  3. Mide el tiempo hasta la alerta o la cancelación
  4. Si tarda más de 5 minutos, agrega detección. Si no funcionó, corrígelo

Después, anótalo en journals/chaos-tests/YYYY-MM-DD.md:

  • Qué inyectaste
  • Qué esperabas
  • Qué pasó
  • Acciones

Paso 5: Plantilla de aviso a clientes

templates/customer-incident-notification.md:

Escribe esto en el chat
Hola:

En este momento tenemos un problema con <función>: <breve descripción del síntoma>.

**Estado:** estamos trabajando en la corrección
**Tiempo estimado de recuperación:** <X minutos>
**Qué hacer por ahora:** <alternativa o "esperar">

Te avisaremos por correo cuando lo resolvamos. Disculpa las molestias.

— El equipo de <nombre>

Un solo archivo. Lo abres, llenas 3 campos y lo envías. En pleno incidente no tienes que "escribir desde cero".


Herramientas y recursos

  • Tenacity: librería de Python para reintentos con espera exponencial
  • Anthropic Console: seguimiento del uso y tu propio límite de gasto
  • Langfuse: observabilidad de código abierto para apps con LLM, costo por usuario, latencia (Helicone pasó a modo de mantenimiento en marzo de 2026)
  • LangSmith: tracing para agentes de LangChain/LangGraph
  • Pydantic: validación de esquemas en Python (zod es el equivalente en TS)
  • PagerDuty: gestión de incidentes para equipos serios
  • Principles of Chaos Engineering: el enfoque de Netflix para provocar fallas a propósito
  • Lección Prompt Injection Defense: defensa en profundidad contra prompt injection
  • Lección Production Observability: paneles propios para monitorear agentes
  • Lección Evals: suites de evals para pruebas de regresión

Lista de verificación de la lección


Ideas clave

Producción no es "lo lancé y me olvidé". Producción es "lo lancé y vivo con esto". Los 7 failure patterns les van a pasar a todos los que trabajan con agentes en producción. La pregunta no es "si", sino "cuándo" y "si estás listo".

Prevenir es más barato que recuperar. Tope de iteraciones + interruptor de presupuesto + validación de la salida: tres patrones baratísimos que cubren la mayor parte de los incidentes típicos. Sin ellos, tienes deuda técnica desde el primer día en producción.

Un postmortem sin culpables es la única forma de no repetir un incidente. La plantilla toma 10 minutos y te protege por años. Aunque trabajes solo, escríbelo. Tu yo del futuro te lo va a agradecer.


Siguiente lección

→ Backup y Disaster Recovery para el stack de IA: qué hacer cuando se cae el propio proveedor

La marca se guarda solo en este navegador y no se envía a ningún sitio. Mi progreso