Caída parcial: cuando falla parte del sistema de agentes

Una caída parcial ocurre cuando solo una parte del sistema de agentes deja de funcionar mientras el resto sigue disponible. Qué la causa y cómo detectarla.
En esta página
  1. El problema
  2. Por qué pasa
  3. Fallos más frecuentes
  4. Trampa de éxito intermitente (Intermittent success trap)
  5. Retry amplification entre capas
  6. La cola se bloquea por runs "ruidosos" (Queue starvation)
  7. Esperar respuesta "perfecta" sin degrade path
  8. Cómo detectar estos problemas
  9. Cómo distinguir partial outage de full outage
  10. Cómo frenar estos fallos
  11. Dónde se implementa en la arquitectura
  12. Autoevaluación
  13. FAQ
  14. Páginas relacionadas

El problema

La solicitud parece simple: verificar estado de pago y dar una respuesta breve al cliente.

En trazas se ve otra cosa: en 11 minutos un run hizo 33 llamadas, 10 devolvieron 200, 14 devolvieron timeout, y 9 devolvieron 502/503. Para una tarea de esta clase puede ser alrededor de ~$1.90 en lugar de ~$0.14 habitual.

El servicio está formalmente "vivo": parte de las llamadas funciona, no hay caída total. Pero la cola de runs crece, la latency salta y los usuarios reciben resultados inestables.

El sistema no cae.

Solo se atasca lentamente entre éxitos raros y fallos repetidos.

Analogía: imagina una caja donde el terminal a veces acepta tarjeta y a veces se cuelga. La tienda no está cerrada, pero la fila crece cada minuto. Una caída parcial en sistemas de agentes funciona igual: la infraestructura parece disponible, pero ya no existe un camino estable hacia la respuesta.

Por qué pasa

En producción normalmente sucede así:

  1. una dependencia empieza a comportarse de forma inestable (timeout, 5xx, a veces 200);
  2. retries arrancan en varias capas a la vez;
  3. el run retiene workers más tiempo, la cola crece;
  4. otros workflows también se ralentizan por recursos compartidos;
  5. sin fail-fast y safe-mode, el sistema multiplica costo en vez de aislar el fallo.

En trace esto aparece como patrón mixto: tool_2xx_rate todavía existe, pero al mismo tiempo suben timeout_rate, retry_attempts_per_run y queue_backlog.

El problema no es un solo timeout.

Runtime no pasa la dependencia inestable a degraded mode mientras el fallo todavía es local.

Fallos más frecuentes

En producción se ven cuatro patrones de partial outage con más frecuencia.

Trampa de éxito intermitente (Intermittent success trap)

El tool a veces devuelve 200, y eso enmascara la degradación. El agente sigue insistiendo por el mismo canal en vez de cambiar de forma controlada.

Causa típica: no hay umbral de "salud" de dependencia a nivel run.

Retry amplification entre capas

Cliente HTTP, gateway y runtime ejecutan retries por separado. Incluso un pico pequeño de errores se vuelve rápido una ola de llamadas innecesarias.

Causa típica: retry policy no centralizada.

La cola se bloquea por runs "ruidosos" (Queue starvation)

Los runs problemáticos quedan colgados mucho tiempo, ocupan worker pool y desplazan tareas sanas.

Causa típica: faltan límites de duración de run y budget-gates.

Esperar respuesta "perfecta" sin degrade path

El sistema intenta esperar un resultado "ideal", aunque la dependencia está claramente degradada.

Causa típica: no existe contrato partial/fallback para usuario.

Cómo detectar estos problemas

La caída parcial se ve bien con combinación de métricas de health, runtime y queue.

MétricaSeñal de partial outageQué hacer
degraded_dependency_rateuna dependencia da timeout/5xx con frecuenciaactivar degraded mode y reducir fan-out
tool_2xx_with_high_timeout_rateaparecen juntos 200 y alta tasa de timeoutagregar umbral de health, no mirar solo 200
retry_attempts_per_rundemasiados reintentos para un runcentralizar retries y limitar retry budget
run_duration_p95runs largos "colgados"introducir fail-fast timeout y stop reasons
queue_backlogla cola crece con tráfico normalaislar ruta degradada y activar fallback

Cómo distinguir partial outage de full outage

No toda degradación es caída total. La pregunta clave: existe camino estable de ejecución o solo "éxitos" aleatorios.

Normal para full outage si:

  • casi todas las llamadas fallan de forma uniforme (5xx o indisponibilidad total);
  • el sistema pasa rápido a fail-fast;
  • no existe ilusión de "a veces funciona".

Peligroso para partial outage si:

  • en el mismo run se mezclan 200, timeout y 5xx;
  • el agente repite llamadas porque ve éxitos raros;
  • queue/latency suben incluso sin global incident claro.

Cómo frenar estos fallos

En práctica:

  1. fijar health snapshot de dependencias al inicio del run;
  2. al romper umbral, pasar workflow a degraded mode de inmediato;
  3. mantener retries en un solo tool gateway con budget estricto;
  4. devolver partial/fallback y stop reason explícito en vez de esperar "eternamente".

Guard mínimo para partial outage:

PYTHON
from dataclasses import dataclass
import time


RETRYABLE = {408, 429, 500, 502, 503, 504}


@dataclass(frozen=True)
class OutageLimits:
    max_retry_per_call: int = 2
    max_retry_total: int = 6
    max_run_seconds: int = 45
    max_tool_calls: int = 14
    degraded_error_threshold: float = 0.35
    min_sample_size: int = 5


class PartialOutageGuard:
    def __init__(self, limits: OutageLimits = OutageLimits()):
        self.limits = limits
        self.started_at = time.time()
        self.tool_calls = 0
        self.retry_count = 0
        self.total_calls = 0
        self.error_calls = 0

    def before_tool_call(self) -> str | None:
        self.tool_calls += 1
        if self.tool_calls > self.limits.max_tool_calls:
            return "partial_outage:tool_call_budget"
        if (time.time() - self.started_at) > self.limits.max_run_seconds:
            return "partial_outage:run_timeout"
        return None

    def on_tool_result(self, status_code: int, attempt: int) -> str | None:
        self.total_calls += 1

        if status_code in RETRYABLE:
            self.error_calls += 1
            error_rate = self.error_calls / max(1, self.total_calls)
            if (
                self.total_calls >= self.limits.min_sample_size
                and error_rate >= self.limits.degraded_error_threshold
            ):
                return "partial_outage:degraded_mode"
            self.retry_count += 1
            if self.retry_count > self.limits.max_retry_total:
                return "partial_outage:retry_budget"
            if attempt >= self.limits.max_retry_per_call:
                return "partial_outage:retry_exhausted"
            return "partial_outage:retry_allowed"

        error_rate = self.error_calls / max(1, self.total_calls)
        if (
            self.total_calls >= self.limits.min_sample_size
            and error_rate >= self.limits.degraded_error_threshold
        ):
            return "partial_outage:degraded_mode"

        return None

En esta versión, retry_count cuenta todas las respuestas retryable dentro del run, y attempt es la cantidad de reintentos de una llamada concreta.

Este es un guard base. En producción normalmente se amplía con per-tool health probes, circuit breaker y ruta safe-mode separada para runs degradados. before_tool_call(...) y on_tool_result(...) se llaman en tool gateway, para que la decisión de degradación sea centralizada y no por capa.

Dónde se implementa en la arquitectura

En producción, el control de partial outage casi siempre se reparte entre tres capas del sistema.

Tool Execution Layer aporta health signals: error rate, timeout patterns, retry budget y circuit breaker. Ahí se ve que una dependencia ya está inestable, incluso si parte de llamadas aún devuelve 200.

Agent Runtime toma decisiones por run: paso a degraded mode, stop reasons y cierre controlado con fallback. Sin esta capa, el sistema sigue esperando "una llamada exitosa más".

Orchestration Topologies define cómo aislar workflow degradado del resto del sistema (bulkheads, colas, prioridades). Esto evita que degradación local se vuelva incidente compartido.

Autoevaluación

Verificación rápida antes del release. Marca los puntos y mira el estado abajo.
Este es un sanity-check corto, no una auditoría formal.

Progreso: 0/8

⚠ Hay señales de riesgo

Faltan controles básicos. Cierra los puntos clave del checklist antes del release.

FAQ

Q: ¿Por qué partial outage suele ser peor que full outage?
A: Porque se enmascara como "a veces funciona". El sistema no se detiene y sigue quemando tiempo, tokens y worker pool.

Q: ¿Hay que desactivar de inmediato el tool degradado?
A: No siempre. Lo normal es activar degraded mode: limitar retries, bajar fan-out y pasar a ruta partial/fallback.

Q: ¿Dónde conviene decidir retries y degradación?
A: En un solo tool gateway. Si no, cada capa hace sus retries y partial outage escala rápido.

Q: ¿Qué mostrar al usuario cuando la dependencia degrada?
A: Stop reason explícito, qué falló exactamente y siguiente paso controlado: respuesta parcial o nuevo intento tras recuperación.


Partial outage casi nunca parece un choque ruidoso. Es degradación silenciosa: el sistema aún se mueve, pero ya no sostiene calidad ni ritmo. Por eso los agentes en producción necesitan no solo retries, sino modo de degradación estricto y aislamiento de dependencias.

Páginas relacionadas

Si este problema aparece en producción, también conviene revisar:

⏱️ 8 min de lecturaActualizado 12 de marzo de 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

Nick — ingeniero que construye infraestructura para agentes de IA en producción.

Enfoque: patrones de agentes, modos de fallo, control del runtime y fiabilidad del sistema.

🔗 GitHub: https://github.com/mykolademyanov


Nota editorial

Esta documentación está asistida por IA, con responsabilidad editorial humana sobre la exactitud, la claridad y la relevancia en producción.

El contenido se basa en fallos reales, post-mortems e incidentes operativos en sistemas de agentes de IA desplegados.