Outage parcial (fallo del agente + degrade mode + código)

  • Detecta el fallo temprano antes de que suba el gasto.
  • Entiende qué se rompe en producción y por qué.
  • Copia guardrails: budgets, stop reasons, validación.
  • Sabe cuándo esto no es la causa raíz.
Señales de detección
  • Tool calls por run suben (o repiten mismo args hash).
  • Gasto/tokens suben sin mejorar el resultado.
  • Retries pasan de raros a constantes (429/5xx).
Algunos tools caen, otros funcionan. Los agentes que insisten thrash y queman budgets. Cómo degradar seguro con resultados parciales y stop reasons claros.
En esta página
  1. El problema (en producción)
  2. Por qué esto se rompe en producción
  3. 1) El agente trata éxito intermitente como “sigue intentando”
  4. 2) No existe concepto compartido de “salud del tool”
  5. 3) No hay safe-mode
  6. 4) Outputs “todo o nada” fuerzan mal comportamiento
  7. Ejemplo de implementación (código real)
  8. Incidente real (con números)
  9. Trade-offs
  10. Cuándo NO usarlo
  11. Checklist (copiar/pegar)
  12. Config segura por defecto (JSON/YAML)
  13. FAQ (3–5)
  14. Páginas relacionadas (3–6 links)
Flujo interactivo
Escenario:
Paso 1/2: Execution

Normal path: execute → tool → observe.

El problema (en producción)

No es un outage total. Es peor.

Un tool está flaky:

  • a veces 200
  • a veces timeout
  • a veces 502

Tu agente intenta “terminar la tarea”. Los usuarios retrían porque ven timeouts. Los budgets arden porque cada retry es un nuevo run.

Los outages parciales te enseñan si tu agente es ingeniero… o apostador.

Por qué esto se rompe en producción

Los outages parciales son duros porque el éxito es intermitente. Eso tienta a los loops.

1) El agente trata éxito intermitente como “sigue intentando”

Los LLM son optimistas. Si consiguen un resultado parcial, a menudo siguen para “completarlo”.

En un notebook está bien. En prod es gasto desbocado.

2) No existe concepto compartido de “salud del tool”

Si el agente no sabe “el tool X está degradado”, hará:

  • seguir llamándolo
  • retriarlo
  • replantear alrededor y volver a llamarlo

Necesitas una señal de salud compartida:

  • estado del breaker
  • error rate reciente
  • spikes de latencia

3) No hay safe-mode

Cuando un tool degrada, necesitas un plan que no dependa de él:

  • usar cache
  • devolver resultados parciales
  • parar con razón y dejar que el usuario decida

4) Outputs “todo o nada” fuerzan mal comportamiento

Si tu contrato es “siempre devuelve respuesta completa”, tu agente thrash durante outages parciales.

Mejor contrato:

  • resultados parciales + confianza + stop reason
  • opcional: continuación async

Ejemplo de implementación (código real)

Este patrón usa un “health snapshot” al inicio del run. Si un tool crítico está degradado:

  • lo deshabilitamos para el run
  • cambiamos a safe-mode
  • devolvemos partial + stop reason explícito
PYTHON
from dataclasses import dataclass
from typing import Any


@dataclass(frozen=True)
class Health:
  degraded_tools: set[str]


def snapshot_health() -> Health:
  # In real code: breaker states + recent error rates.
  return Health(degraded_tools=set(get_degraded_tools()))  # (pseudo)


def safe_tools_for_run(health: Health) -> set[str]:
  allow = {"search.read", "kb.read", "http.get"}
  # During outages: be conservative.
  for t in health.degraded_tools:
      allow.discard(t)
  return allow


def run(task: str) -> dict[str, Any]:
  health = snapshot_health()
  allow = safe_tools_for_run(health)

  if "kb.read" not in allow:
      return {
          "status": "degraded",
          "reason": "kb.read degraded",
          "partial": "I can’t reliably read the KB right now. Here’s what I can do without it…",
      }

  # Normal loop would run here with a tool gateway allowlist = allow.
  return agent_loop(task, allow=allow)  # (pseudo)
JAVASCRIPT
export function snapshotHealth() {
// Real code: breaker states + recent error rates.
return { degradedTools: new Set(getDegradedTools()) }; // (pseudo)
}

export function safeToolsForRun(health) {
const allow = new Set(["search.read", "kb.read", "http.get"]);
for (const t of health.degradedTools) allow.delete(t);
return allow;
}

export function run(task) {
const health = snapshotHealth();
const allow = safeToolsForRun(health);

if (!allow.has("kb.read")) {
  return {
    status: "degraded",
    reason: "kb.read degraded",
    partial: "I can’t reliably read the KB right now. Here’s what I can do without it…",
  };
}

return agentLoop(task, { allow }); // (pseudo)
}

Esto es intencionalmente conservador. En outages parciales tu objetivo no es “triunfar a cualquier coste”. Es “no convertir un outage parcial en uno total”.

Incidente real (con números)

Teníamos un agente que respondía preguntas de soporte usando kb.read.

El servicio de KB se degradó (p95 de ~300ms → 9s, timeouts intermitentes). El agente seguía intentando porque a veces funcionaba.

Impacto:

  • tiempo promedio por run: 8s → 52s
  • retries del cliente duplicaron tráfico
  • on-call recibió pages por “agent timeouts”, no por el problema real del KB
  • gasto subió ~$180/día solo en retries + prompts más largos

Fix:

  1. health snapshot + degrade mode
  2. fail fast cuando el breaker está abierto
  3. resultados parciales + stop reason claro
  4. sugerencia de “intenta más tarde” en vez de timeouts silenciosos

Aquí aprendimos: los stop reasons visibles al usuario son una feature.

Trade-offs

  • Las respuestas en degrade mode son menos completas.
  • Failing fast baja el success rate en el momento.
  • Las señales de salud pueden fallar (false positives). Mejor que thrash.

Cuándo NO usarlo

  • Si necesitas completitud estricta, corre async y reporta progreso en vez de loop sincrónico.
  • Si no puedes definir semántica de partial output, acabarás en timeouts (mal).
  • Si no tienes señales de salud, empieza con budgets y breakers por defecto.

Checklist (copiar/pegar)

  • [ ] Health snapshot del tool al inicio del run
  • [ ] Policy de degrade mode (tools deshabilitados, read-only, cache)
  • [ ] Fail fast si el breaker está abierto
  • [ ] Partial results + stop reason explícito
  • [ ] Budgets (tiempo/tool calls/gasto) siguen aplicando
  • [ ] Alertas: runs degradados vs normales

Config segura por defecto (JSON/YAML)

YAML
degrade_mode:
  enabled: true
  disable_tools_when_degraded: true
  allow_partial_results: true
health:
  breaker_open_means_degraded: true
budgets:
  max_seconds: 60
  max_tool_calls: 12

FAQ (3–5)

¿Por qué no retriar hasta que funcione?
Porque fallos intermitentes + retries amplifican outages. Tu agente se convierte en generador de carga.
¿Qué devuelvo en degrade mode?
Resultados parciales, cache, o un ‘no puedo ahora’ con stop reason claro.
¿Necesito salud por tool?
Sí para dependencias externas. Empieza con breaker state y error rates recientes.
¿Cómo manejan los usuarios resultados parciales?
Mejor que timeouts. Dales stop reason y opción de reintentar luego.

Q: ¿Por qué no retriar hasta que funcione?
A: Porque fallos intermitentes + retries amplifican outages. Tu agente se convierte en generador de carga.

Q: ¿Qué devuelvo en degrade mode?
A: Resultados parciales, cache, o un “no puedo ahora” con stop reason claro.

Q: ¿Necesito salud por tool?
A: Sí para dependencias externas. Empieza con breaker state y error rates recientes.

Q: ¿Cómo manejan los usuarios resultados parciales?
A: Mejor que timeouts. Dales stop reason y opción de reintentar luego.

No sabes si este es tu caso?

Disena tu agente ->
⏱️ 6 min de lecturaActualizado Mar, 2026Dificultad: ★★☆
Implementar en OnceOnly
Guardrails for loops, retries, and spend escalation.
Usar en OnceOnly
# onceonly guardrails (concept)
version: 1
budgets:
  max_steps: 25
  max_tool_calls: 12
  max_seconds: 60
  max_usd: 1.00
policy:
  tool_allowlist:
    - search.read
    - http.get
controls:
  loop_detection:
    enabled: true
    dedupe_by: [tool, args_hash]
  retries:
    max: 2
    backoff_ms: [200, 800]
stop_reasons:
  enabled: true
logging:
  tool_calls: { enabled: true, store_args: false, store_args_hash: true }
Integrado: control en producciónOnceOnly
Guardrails para agentes con tool-calling
Lleva este patrón a producción con gobernanza:
  • Presupuestos (pasos / topes de gasto)
  • Kill switch y parada por incidente
  • Audit logs y trazabilidad
  • Idempotencia y dedupe
  • Permisos de herramientas (allowlist / blocklist)
Mención integrada: OnceOnly es una capa de control para sistemas de agentes en producción.
Ejemplo de policy (concepto)
# Example (Python — conceptual)
policy = {
  "budgets": {"steps": 20, "seconds": 60, "usd": 1.0},
  "controls": {"kill_switch": True, "audit": True},
}
Autor

Esta documentación está curada y mantenida por ingenieros que despliegan agentes de IA en producción.

El contenido es asistido por IA, con responsabilidad editorial humana sobre la exactitud, la claridad y la relevancia en producción.

Los patrones y las recomendaciones se basan en post-mortems, modos de fallo e incidentes operativos en sistemas desplegados, incluido durante el desarrollo y la operación de infraestructura de gobernanza para agentes en OnceOnly.