Deadlocks de agentes: cuando los agentes se bloquean entre sí

Un deadlock ocurre cuando varios agentes se esperan mutuamente y el sistema no puede avanzar. Por qué pasa en sistemas multi-agent y cómo prevenirlo.
En esta página
  1. Problema
  2. Por qué pasa
  3. Fallos más frecuentes
  4. Espera circular (Circular wait)
  5. Lock sin TTL (Lock without lease)
  6. Espera no acotada (Unbounded waiting)
  7. Bucle de retry entre agentes (Cross-agent retry loop)
  8. Cómo detectar estos problemas
  9. Cómo distinguir deadlock de una tarea realmente larga
  10. Cómo detener estos fallos
  11. Dónde se implementa en la arquitectura
  12. Autoevaluación
  13. FAQ
  14. Páginas relacionadas

Problema

En los traces de un run se ve un ciclo de espera: Agent A -> Agent B -> Agent C -> Agent A.

En 20 minutos, la cantidad de runs en estado waiting puede llegar a 40+. La cola crece, los workers siguen ocupados y el trabajo útil es casi nulo.

Desde fuera todo parece "silencioso": no hay error explícito ni caída del servicio. Pero el run no termina porque los tres agentes solo se esperan entre sí.

El sistema no se cae.

Simplemente se queda colgado y quema recursos en silencio.

Analogía: imagina a tres personas en una puerta cediéndose el paso con cortesía. Nadie discute y nadie comete un "error", pero nadie pasa. Un deadlock en sistemas multi-agent se ve exactamente así.

Por qué pasa

Un deadlock no aparece porque los agentes "piensen demasiado", sino porque el sistema no tiene claro quién debe mover el estado hacia adelante.

En producción normalmente se ve así:

  1. los agentes intercambian mensajes y dependen entre sí;
  2. una espera se retrasa (tool, approval, lock);
  3. otros agentes también pasan a waiting;
  4. sin timeout y owner del estado del workflow, el workflow se atasca.

El problema no es un agente aislado. El problema es la coordinación no controlada entre agentes.

Fallos más frecuentes

Para no complicarlo, en deadlocks se repiten cuatro patrones.

Espera circular (Circular wait)

Agent A espera a B, B espera a C, C espera a A. Todos están "ocupados", pero no hay progreso.

Causa típica: el grafo de dependencias contiene un ciclo y no hay un orchestrator único.

Lock sin TTL (Lock without lease)

Un agente toma un lock sobre documento/ticket y crashea. Otros agentes esperan ese lock indefinidamente.

Causa típica: lock sin lease/TTL y sin mecanismo de recovery del owner.

Espera no acotada (Unbounded waiting)

Hay timeout en HTTP, pero no timeout en waits internos entre agentes. El workflow puede esperar "para siempre".

Causa típica: los timeouts están implementados a nivel transport, pero no a nivel de estados de orchestration.

Bucle de retry entre agentes (Cross-agent retry loop)

Los agentes se pasan la tarea con "revísalo otra vez", y eso se vuelve ping-pong infinito.

Causa típica: no hay límite de retries ni stop reason para escenarios de blocked state.

Cómo detectar estos problemas

El deadlock se ve bien con la combinación de métricas de workflow y runtime.

MétricaSeñal de deadlockQué hacer
waiting_runsla cantidad de runs en waiting crece de forma sostenidaagregar wait-timeout y stop reason para blocked state
wait_duration_p95esperas por encima de lo normalacotar el tiempo de espera en cada state transition
blocked_transition_ratebloqueos frecuentes entre los mismos agentesrevisar el grafo de dependencias para detectar ciclos
lease_conflict_rateconflictos frecuentes o leases expiradasagregar TTL, renew y policy de recovery
queue_backlogla cola crece con tráfico de entrada normallimpiar runs colgados, activar fallback mode

Cómo distinguir deadlock de una tarea realmente larga

No todo run largo es deadlock. El criterio clave: ¿hay state transitions y progreso útil?

Normal si:

  • el estado del workflow cambia como se espera;
  • después de esperar aparece un artefacto o paso nuevo;
  • hay un owner claro de la transición actual.

Peligroso si:

  • el run permanece mucho tiempo en el mismo estado waiting;
  • varios agentes "esperan" al mismo tiempo entre sí;
  • no hay un stop reason claro de por qué el sistema no avanza.

Cómo detener estos fallos

En la práctica se ve así:

  1. introduces un owner único de transiciones (orchestrator o leader);
  2. pones timeout en cada estado waiting;
  3. usas lease/TTL para shared resources;
  4. cuando no hay progreso, terminas el run de forma controlada: stop reason + fallback.

Guard mínimo para wait-state:

PYTHON
import time


class WaitGuard:
    def __init__(self, wait_timeout_s: int = 30):
        self.wait_timeout_s = wait_timeout_s
        self.wait_started_at: dict[str, float] = {}

    def mark_wait_start(self, run_id: str):
        self.wait_started_at[run_id] = time.time()

    def check_wait(self, run_id: str):
        started = self.wait_started_at.get(run_id)
        if started is None:
            return None
        if time.time() - started > self.wait_timeout_s:
            return "deadlock_risk:wait_timeout"
        return None

En producción, mark_wait_start(...) suele llamarse al pasar a waiting, y check_wait(...) se ejecuta en scheduler o heartbeat loop para cerrar a tiempo un run colgado.

Dónde se implementa en la arquitectura

El control de deadlocks en producción normalmente se reparte entre varias capas.

Agent Runtime gestiona el ciclo de vida del run: timeouts, stop reasons, finalización forzada de estados colgados y transiciones de fallback. Aquí se suelen definir reglas deadlock_risk:*.

Orchestration Topologies define quién posee las state transitions y cómo interactúan los agentes sin esperas circulares. Si la topología no tiene un owner claro del estado, el deadlock es cuestión de tiempo.

Tool Execution Layer cubre la parte técnica: lease/TTL para shared resources, una retry policy unificada y control de waits a nivel de tools.

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/9

⚠ Hay señales de riesgo

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

FAQ

Q: ¿Los deadlocks solo pasan en sistemas multi-agent grandes?
A: No. Incluso 2-3 agentes pueden crear un ciclo de espera si no hay owner explícito del estado.

Q: ¿Basta con agregar timeouts?
A: Los timeouts limitan el bloqueo, pero no eliminan la raíz del problema. También necesitas orchestrator y state transitions explícitas.

Q: ¿Las leases resuelven por completo el deadlock?
A: No. Las leases cubren problemas de locks tras crashes, pero no corrigen ciclos lógicos entre agentes.

Q: ¿Qué hago si un run ya está colgado en waiting?
A: Forzar finalización del run con stop reason, liberar lease, pasar workflow a fallback y revisar la cadena de espera en traces.


Un deadlock casi nunca parece una caída ruidosa. Más bien es una parada silenciosa del progreso que consume workers y presupuesto. Por eso los sistemas multi-agent en producción necesitan no solo reparto de roles, sino disciplina estricta de orchestration.

Páginas relacionadas

Para cubrir este problema con más profundidad:

⏱️ 6 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.