Deadlocks d'agents : quand les agents se bloquent entre eux

Un deadlock apparaît quand plusieurs agents s'attendent mutuellement et que le système ne peut plus avancer. Pourquoi cela arrive en système multi-agent et comment l'éviter.
Sur cette page
  1. Problème
  2. Pourquoi cela arrive
  3. Pannes les plus fréquentes
  4. Attente circulaire (Circular wait)
  5. Lock sans TTL (Lock without lease)
  6. Attentes non bornées (Unbounded waiting)
  7. Boucle de retry inter-agents (Cross-agent retry loop)
  8. Comment détecter ces problèmes
  9. Comment distinguer deadlock et tâche réellement longue
  10. Comment arrêter ces pannes
  11. Où c'est implémenté dans l'architecture
  12. Auto-vérification
  13. FAQ
  14. Pages liées

Problème

Dans les traces d'un run, on voit une boucle d'attente : Agent A -> Agent B -> Agent C -> Agent A.

En 20 minutes, le nombre de runs en statut waiting peut monter à 40+. La file grossit, les workers restent occupés, et le travail utile devient presque nul.

Vu de l'extérieur, tout semble "calme" : pas d'erreur explicite, pas de crash du service. Mais le run ne se termine pas, car les trois agents attendent simplement les uns les autres.

Le système ne crash pas.

Il se fige et brûle les ressources en silence.

Analogie : imagine trois personnes dans une porte qui se laissent poliment passer. Personne ne se dispute, personne ne fait de "faute", mais personne ne passe. Un deadlock en système multi-agent ressemble exactement à ça.

Pourquoi cela arrive

Un deadlock apparaît non pas parce que les agents "réfléchissent trop longtemps", mais parce que le système ne sait pas qui doit faire avancer l'état.

En production, cela ressemble souvent à ceci :

  1. les agents échangent des messages et dépendent les uns des autres ;
  2. une attente est retardée (tool, approval, lock) ;
  3. les autres agents passent aussi en waiting ;
  4. sans timeout et owner de l'état du workflow, le workflow se bloque.

Le problème n'est pas un agent isolé. Le problème est la coordination non contrôlée entre agents.

Pannes les plus fréquentes

Pour rester pratique, on retrouve surtout quatre patterns de deadlock.

Attente circulaire (Circular wait)

Agent A attend B, B attend C, C attend A. Tout le monde est "occupé", mais il n'y a aucun progrès.

Cause typique : le graphe de dépendances contient un cycle et il n'y a pas d'orchestrator unique.

Lock sans TTL (Lock without lease)

Un agent prend un lock sur document/ticket puis crash. Les autres agents attendent ce lock indéfiniment.

Cause typique : lock sans lease/TTL et sans mécanisme de recovery de l'owner.

Attentes non bornées (Unbounded waiting)

Il y a un timeout HTTP, mais pas de timeout sur les waits internes entre agents. Le workflow peut attendre "pour toujours".

Cause typique : les timeouts sont implémentés au niveau transport, pas au niveau des états d'orchestration.

Boucle de retry inter-agents (Cross-agent retry loop)

Les agents se renvoient la tâche avec "revérifie encore", et cela devient un ping-pong infini.

Cause typique : pas de limite de retry et pas de stop reason pour les scénarios de blocked state.

Comment détecter ces problèmes

Le deadlock se voit bien via la combinaison des métriques workflow et runtime.

MétriqueSignal de deadlockAction
waiting_runsle nombre de runs en waiting augmente de façon stableajouter un wait-timeout et un stop reason pour blocked state
wait_duration_p95durée d'attente au-dessus de la normaleborner le temps d'attente à chaque state transition
blocked_transition_rateblocages fréquents entre les mêmes agentsvérifier le graphe de dépendances pour détecter les cycles
lease_conflict_rateconflits fréquents ou leases expiréesajouter TTL, renew et policy de recovery
queue_backlogla file augmente avec un trafic entrant normalnettoyer les runs figés, activer le fallback mode

Comment distinguer deadlock et tâche réellement longue

Chaque run long n'est pas un deadlock. Le critère clé : y a-t-il des transitions d'état et un progrès utile ?

Normal si :

  • le statut du workflow change comme prévu ;
  • après l'attente, un nouvel artefact ou une nouvelle étape apparaît ;
  • il existe un owner clair de la transition courante.

Dangereux si :

  • le run reste longtemps dans le même état waiting ;
  • plusieurs agents "attendent" simultanément les uns les autres ;
  • il n'y a pas de stop reason claire expliquant pourquoi le système n'avance pas.

Comment arrêter ces pannes

En pratique, cela ressemble à ceci :

  1. introduire un owner unique des transitions (orchestrator ou leader) ;
  2. poser un timeout sur chaque état waiting ;
  3. utiliser lease/TTL pour les shared resources ;
  4. en cas de no-progress, terminer le run de façon contrôlée : stop reason + fallback.

Garde minimale pour un 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 production, mark_wait_start(...) est généralement appelé lors du passage à waiting, et check_wait(...) est exécuté dans un scheduler ou une heartbeat loop pour terminer un run bloqué à temps.

Où c'est implémenté dans l'architecture

Le contrôle des deadlocks en production est généralement réparti sur plusieurs couches.

Agent Runtime gère le cycle de vie des runs : timeouts, stop reasons, arrêt forcé des états figés et transitions de fallback. C'est ici qu'on pose en général les règles deadlock_risk:*.

Orchestration Topologies définit qui possède les state transitions et comment les agents interagissent sans attente circulaire. Sans owner explicite de l'état dans la topologie, le deadlock devient une question de temps.

Tool Execution Layer couvre la partie technique : lease/TTL pour shared resources, retry policy unique et contrôle des attentes au niveau des tools.

Auto-vérification

Vérification rapide avant release. Coche les points et regarde le statut ci-dessous.
C'est un sanity-check court, pas un audit formel.

Progression: 0/9

⚠ Il y a des signaux de risque

Il manque des contrôles de base. Fermez les points clés de la checklist avant release.

FAQ

Q : Les deadlocks n'arrivent que dans de gros systèmes multi-agents ?
R : Non. Même 2-3 agents peuvent créer une boucle d'attente s'il n'y a pas d'owner d'état explicite.

Q : Ajouter des timeouts suffit ?
R : Les timeouts limitent le blocage, mais ne retirent pas la cause racine. Il faut aussi un orchestrator et des state transitions explicites.

Q : Les leases résolvent totalement le deadlock ?
R : Non. Les leases couvrent les problèmes de lock après crash, mais ne corrigent pas les cycles logiques entre agents.

Q : Que faire si un run est déjà bloqué en waiting ?
R : Forcer l'arrêt du run avec stop reason, libérer la lease, passer le workflow en fallback et analyser la chaîne d'attente dans les traces.


Un deadlock ressemble rarement à une panne bruyante. Le plus souvent, c'est un arrêt silencieux du progrès qui consomme workers et budget. C'est pourquoi les systèmes multi-agents en production ont besoin non seulement d'une répartition des rôles, mais aussi d'une discipline d'orchestration stricte.

Pages liées

Pour aller plus loin sur ce problème :

⏱️ 7 min de lectureMis à jour 12 mars 2026Difficulté: ★★☆
Implémenter dans OnceOnly
Guardrails for loops, retries, and spend escalation.
Utiliser dans 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 }
Intégré : contrôle en productionOnceOnly
Ajoutez des garde-fous aux agents tool-calling
Livrez ce pattern avec de la gouvernance :
  • Budgets (steps / plafonds de coût)
  • Kill switch & arrêt incident
  • Audit logs & traçabilité
  • Idempotence & déduplication
  • Permissions outils (allowlist / blocklist)
Mention intégrée : OnceOnly est une couche de contrôle pour des systèmes d’agents en prod.
Exemple de policy (concept)
# Example (Python — conceptual)
policy = {
  "budgets": {"steps": 20, "seconds": 60, "usd": 1.0},
  "controls": {"kill_switch": True, "audit": True},
}

Auteur

Nick — ingénieur qui construit une infrastructure pour des agents IA en production.

Focus : patterns d’agents, modes de défaillance, contrôle du runtime et fiabilité des systèmes.

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


Note éditoriale

Cette documentation est assistée par l’IA, avec une responsabilité éditoriale humaine pour l’exactitude, la clarté et la pertinence en production.

Le contenu s’appuie sur des défaillances réelles, des post-mortems et des incidents opérationnels dans des systèmes d’agents IA déployés.