AI
AgentOps : arrêter une boucle de handoff entre agents avant qu'elle ne multiplie les actions
Un runbook de production pour détecter une boucle de délégation entre agents, contenir les effets de bord, reconstruire les traces et décider reprise contrôlée ou rollback mono-agent.
Un agent de triage transmet un incident réseau à un agent cloud. Celui-ci demande une vérification à un agent d’automatisation, qui renvoie le dossier au triage faute d’approbation. La conversation semble avancer, mais le même travail recommence sous de nouveaux identifiants. Les appels d’outils augmentent, plusieurs tickets sont préparés et un retry peut finir par déclencher deux fois la même action.
Le problème n’est pas seulement la qualité de la réponse. Une boucle de handoff est un incident d’orchestration : l’état de la tâche, la responsabilité et les effets déjà produits ne suivent plus le transfert. Ce runbook part d’un agent interne d’exploitation capable de lire des runbooks, d’interroger des logs et de préparer des actions soumises à validation. L’objectif est d’arrêter la multiplication sans perdre les preuves, puis de décider si le flux multi-agent peut reprendre ou doit revenir temporairement à un seul agent.
Reconnaître une boucle avant l’épuisement des limites
Une délégation légitime change le propriétaire parce qu’une compétence manque. Une boucle répète la même intention sans réduire l’incertitude, sans ajouter de preuve et sans rapprocher la tâche d’un état terminal.
Signaux a correler
meme task_id ou meme empreinte metier sur plusieurs traces
retour vers un agent deja visite sans preuve nouvelle
profondeur ou nombre de handoffs qui depasse le budget
meme outil appele avec des arguments equivalents
nouveaux tickets ou jobs prepares pour la meme intention
retries alors que l'etat precedent reste inconnu
hausse de latence et de cout sans progression d'etat Le timeout utilisateur est un signal tardif. La plateforme doit mesurer la profondeur, les agents visités, les empreintes d’action et le dernier résultat utile. Une réponse différente en prose ne constitue pas une progression si elle prépare la même opération.
Geler les effets de bord, pas les preuves
Dès que la boucle est probable, bloquez les nouveaux handoffs et les outils en écriture pour le périmètre concerné. Conservez la lecture, les traces et les appels de diagnostic sans effet. N’effacez pas les files ni les conversations avant d’avoir identifié les actions préparées, approuvées ou exécutées.
incident_scope:
workflow: incident-triage
task_id: task-7f31
correlation_id: corr-91ab
containment:
new_handoffs: blocked
write_tools: prepare_only
automatic_retries: disabled
read_only_diagnostics: allowed
trace_retention: preserved
operator_checks:
- list prepared and approved actions
- cancel duplicate pending work
- identify any executed side effect
- assign one human incident owner Le contrôle doit porter sur une tâche, un workflow ou un type d’action, pas forcément sur tous les agents. Si l’orchestrateur ne sait pas isoler ce périmètre, repassez les outils sensibles en lecture seule globalement jusqu’à ce que les actions en vol soient qualifiées.
Reconstruire la chaîne de responsabilité
Une trace exploitable relie la tâche logique aux exécutions, handoffs et outils. Chaque transfert doit indiquer qui délègue, à qui, pourquoi, avec quel état et quel résultat attendu. Sans cette enveloppe, deux runtimes peuvent recréer la même tâche et contourner un simple compteur local.
{
"taskId": "task-7f31",
"correlationId": "corr-91ab",
"parentRunId": "run-triage-04",
"runId": "run-cloud-05",
"fromAgent": "incident-triage",
"toAgent": "cloud-diagnostics",
"reasonCode": "missing-network-evidence",
"expectedOutcome": "read-only route evidence",
"visitedAgents": ["incident-triage", "cloud-diagnostics"],
"hop": 2,
"hopBudget": 4,
"actionFingerprint": "diagnose:subscription:resource:route",
"stateVersion": 6,
"deadline": "<timestamp>",
"sideEffectMode": "none"
} taskId reste stable pendant toute l’intention métier. runId change à chaque exécution. actionFingerprint déduplique une opération logique, même si le prompt ou l’ordre des arguments varie. stateVersion permet de refuser un agent qui tente d’écrire à partir d’un état périmé.
Lire la boucle dans les traces
Le schéma réel dépend de la plateforme, mais la requête doit regrouper les événements par tâche et reconstruire l’ordre des agents. Adaptez les noms de table et de colonnes à votre télémétrie.
let Window = 2h;
AgentOrchestrationEvents
| where TimeGenerated > ago(Window)
| where EventType in ("handoff", "tool_call", "terminal_state")
| summarize
FirstSeen = min(TimeGenerated),
LastSeen = max(TimeGenerated),
Handoffs = countif(EventType == "handoff"),
Agents = make_list_if(ToAgent, EventType == "handoff", 32),
DistinctAgents = dcountif(ToAgent, EventType == "handoff"),
RepeatedActions = count() - dcount(ActionFingerprint),
TerminalStates = countif(EventType == "terminal_state")
by TaskId, CorrelationId
| extend SuspectedLoop = Handoffs > 4
or (Handoffs > DistinctAgents and TerminalStates == 0)
or RepeatedActions > 1
| where SuspectedLoop
| order by Handoffs desc, LastSeen desc Ne concluez pas sur le seul nombre de transferts. Un workflow complexe peut traverser plusieurs spécialistes. La preuve forte combine revisite, absence de nouvel état, action répétée et absence de sortie terminale.
Imposer le contrat d’orchestration hors du prompt
Demander aux agents de « ne pas boucler » ne suffit pas. L’orchestrateur doit refuser une transition invalide avant d’appeler le runtime suivant.
handoff_policy:
max_hops: 4
revisit_agent: require_new_evidence
deadline: required
terminal_states: [resolved, refused, needs_human, failed]
progress_policy:
require_one_of:
- new_evidence_id
- narrower_scope
- validated_state_transition
reject_same_action_fingerprint: true
side_effect_policy:
idempotency_key: required
stale_state_write: reject
write_after_handoff: require_fresh_approval
unknown_tool_result: never_retry_automatically Le budget de sauts borne l’exécution, mais l’idempotence protège la production. Chaque outil d’écriture doit accepter une clé dérivée de la tâche et de l’action logique, puis retourner le résultat déjà connu au lieu de recommencer. Si un appel expire avec un état inconnu, l’orchestrateur doit interroger son statut avant tout retry.
Corriger la cause, pas seulement le compteur
Une boucle révèle souvent un contrat incomplet : responsabilités qui se chevauchent, raisons de handoff libres, état non partagé, absence de sortie needs_human, ou outil qui ne distingue pas préparation et exécution. Classez l’incident avant de modifier les prompts.
Si deux agents revendiquent le même domaine, clarifiez une règle de propriété. Si aucun agent ne peut terminer faute d’information, ajoutez une sortie humaine explicite. Si l’état se perd, centralisez la tâche logique et imposez des écritures conditionnelles sur stateVersion. Si un outil est appelé deux fois, corrigez l’idempotence avant de rouvrir les handoffs.
Rejouer sans action réelle
Reproduisez la trace fautive avec des outils simulés ou read-only. Le test doit vérifier la progression, les sorties terminales et l’absence de doublon, pas seulement la réponse finale.
cases:
- name: missing_evidence_returns_to_previous_agent
expected:
- second_visit_requires_new_evidence
- otherwise_needs_human
- no_write_tool
- name: tool_timeout_with_unknown_result
expected:
- query_execution_status
- no_automatic_retry
- same_idempotency_key
- name: hop_budget_exhausted
expected:
- terminal_state_needs_human
- full_handoff_summary
- pending_duplicates_cancelled
promotion_gate:
repeated_action_fingerprints: 0
writes_from_stale_state: 0
unbounded_tasks: 0
trace_completeness: required Ajoutez un cas légitime où plusieurs agents coopèrent et terminent correctement. Un garde-fou qui bloque toute délégation supprime la boucle, mais aussi la valeur de l’architecture.
Décider reprise ou rollback mono-agent
Réactivez d’abord les diagnostics read-only sur un petit périmètre. Ouvrez ensuite les handoffs avec budget et traces complètes, puis les outils de préparation. Les écritures ne reviennent qu’après validation de l’idempotence, des approbations et des cas de timeout.
Revenez temporairement à un agent unique si l’état partagé reste ambigu, si les outils ne garantissent pas l’idempotence ou si une action exécutée ne peut pas être reliée à une tâche. Le rollback doit fixer un propriétaire, désactiver les routes multi-agent touchées et conserver les mêmes contrôles d’outils. Il ne doit pas transformer l’agent unique en raccourci vers des écritures non bornées.
Conclusion
Une boucle de handoff se traite comme une panne de système distribué : identité stable de la tâche, état versionné, échéance, budget de sauts, sorties terminales et effets idempotents. Les traces servent à prouver la progression, pas seulement à compter les tokens.
La décision finale est opérationnelle : reprendre progressivement quand les transferts ajoutent une preuve et que les doublons sont impossibles, ou restaurer un flux mono-agent tant que l’orchestration ne garantit pas ces propriétés. L’objectif n’est pas de faire déléguer davantage, mais de rendre chaque délégation explicable et réversible.