Le problème
03:07 du matin.
L'ingénieur on-call voit que l'agent a reçu une demande normale, a appelé un tool plusieurs fois, a reçu des résultats, mais n'a toujours pas pu terminer la tâche.
Dans les logs, la même séquence se répète :
plan → call_tool → analyze → plan → call_tool → analyze
Beaucoup d'étapes, beaucoup de tokens, aucun résultat.
L'agent essaie de trouver un email dans le CRM. La recherche renvoie 404, mais au lieu de répondre "non trouvé", l'agent commence à modifier la requête :
john@example.comJohn@example.comJOHN@example.comjohn@company.com
En 2 minutes, l'agent a fait 47 appels API, dépensé environ 5 $ en tokens, et n'a pourtant pas avancé vers la réponse.
Un runaway loop peut brûler en 30-40 minutes un budget prévu pour une semaine complète.
Analogie : imagine un caissier qui scanne le même article à l'infini, en ignorant le plafond de la carte du client. Il peut sembler "occupé", mais chaque nouvelle action augmente la perte. Pour les agents IA, ce rôle de contrôle est assuré par runtime : stop conditions, budgets et policy gates.
Pourquoi cela arrive
En production :
- le LLM propose l'étape suivante ;
- un appel d'outil est exécuté ;
- le résultat revient dans le reasoning loop ;
- runtime ne vérifie pas le progrès réel et n'arrête pas la boucle à temps.
Le problème n'est pas le modèle. Le problème est que runtime ne sait pas quand s'arrêter.
Quels échecs arrivent le plus souvent
Pour garder l'analyse simple, en production on commence généralement par trois types d'échec principaux.
Échecs de boucle (Loop failures)
L'agent répète les mêmes étapes sans nouvelles observations. Vu de l'extérieur, il peut sembler encore actif, mais en réalité le système tourne en rond et brûle du temps et de l'argent.
Cause typique : absence de max_steps, de progress check, ou de stop reason clair.
En production, cela ressemble le plus souvent à une boucle infinie.
Échecs d'outils (Tool failures)
L'agent appelle les outils trop souvent ou incorrectement. La latence et la charge API augmentent, et les pannes commencent à se propager dans la chaîne de services.
Cause typique : Tool Execution Layer trop permissive et validation faible des arguments.
Le résultat se transforme facilement en échec d'outil.
Échecs de budget (Budget failures)
Le budget de tokens et de temps augmente sans progrès visible. Le système devient plus coûteux, et les services dépendants tombent plus souvent en timeout.
Cause typique : pas d'execution budgets sur les étapes, les tokens, le temps et le nombre d'appels tool.
Sans limites, cela se transforme souvent en explosion de budget.
Dérive de contexte (Context drift)
Quand un agent tourne trop longtemps, l'historique de messages grossit. De nouveaux tokens peuvent évincer le system prompt, et l'agent commence à "oublier" son rôle ou la tâche initiale. C'est le context drift. On le corrige généralement via summarization et limites de context window ; un scénario proche en symptômes est empoisonnement du contexte.
Il faut aussi garder deux classes en vue :
Security failures: prompt injection et accès non autorisé aux write tools.Data failures: données intermédiaires fausses ou non validées qui cassent la réponse finale.
Comment détecter ces problèmes
Pour attraper ces échecs avant qu'ils deviennent des incidents, les systèmes de production suivent généralement quelques métriques clés.
| Métrique | Signal | Que faire |
|---|---|---|
steps_per_task | hausse brutale des itérations | vérifier les stop conditions, ajouter un progress check |
tool_calls_per_task | trop de répétitions suspectes | introduire dedupe tool+args et limiter les appels |
tokens_per_task | la consommation augmente sans progrès | limiter la taille du context window, ajouter summarization et caps sur tool output |
runtime_duration | la latence monte, la tâche se bloque | timeout et terminaison forcée du run |
Comment distinguer un échec d'une tâche vraiment difficile
Un run long n'est pas forcément un échec. Le signal clé n'est pas le nombre d'étapes, mais l'absence de progrès réel.
C'est normal si :
- les étapes
toolchangent les observations ; - de nouvelles données apparaissent ;
- le résultat se rapproche de
final_answer.
C'est dangereux si :
- répétitions sans nouvelles observations ;
- même
tool_callsans changement d'arguments ; - le coût augmente, mais le résultat ne s'améliore pas.
Comment arrêter ces échecs
La façon la plus simple de contrôler l'execution loop, c'est runtime limits. En général : max_steps, max_tool_calls, max_tokens et timeout.
max_steps est le premier frein d'urgence contre les runaway loops. Variante plus avancée : semantic progress check. Un petit modèle séparé (par exemple Gemini Flash ou Claude Haiku) analyse les 3 dernières étapes de l'agent et vérifie si un nouveau signal est apparu, ou si le système tourne en rond. Le résultat peut ressembler à ceci :
{
"is_progressing": true,
"is_looping": false
}
Un squelette runtime de base qui bloque la majorité des runaway loops :
class RunLimits:
def __init__(self):
self.max_steps = 8
self.max_tool_calls = 12
self.max_tokens = 4000
self.max_seconds = 30
self.steps = 0
self.tool_calls = 0
def check(self, step_tokens: int, elapsed_ms: int) -> str | None:
self.steps += 1
self.max_tokens -= step_tokens
if self.steps > self.max_steps:
return "max_steps_reached"
if self.tool_calls > self.max_tool_calls:
return "max_tool_calls_reached"
if self.max_tokens <= 0:
return "max_tokens_reached"
if elapsed_ms > self.max_seconds * 1000:
return "timeout"
return None
def register_tool(self):
self.tool_calls += 1
En production, ces limites sont souvent stockées dans Redis pour les appliquer entre stateless workers.
Mais les limites seules ne garantissent pas un comportement correct. Elles arrêtent seulement le runaway loop. Pour un agent stable, il faut aussi validation de tool output, policy boundaries et contrôle des write actions.
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/8
⚠ 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 : Pourquoi les agents IA échouent-ils plus souvent que les workflows classiques ?
R : Dans un workflow, les étapes sont fixées à l'avance. Dans un agent, le LLM propose l'étape suivante dynamiquement, et sans limites runtime la boucle sort vite de contrôle.
Q : Passer à un modèle plus fort suffit-il ?
R : Ça peut aider en partie, mais ça ne résout pas le fond du problème. Sans contrôle runtime, même un modèle fort peut boucler, dépasser le budget ou spammer les outils.
Si l'agent du début avait eu max_steps = 8 et dedupe sur tool+args, l'incident de 03:07 se serait terminé en quelques secondes.
En production, la stabilité d'un agent n'est pas définie par le modèle, mais par les limites que runtime pose autour de l'execution loop.
Pages liées
Pour mieux comprendre comment prévenir ces échecs, regarde les couches système qui contrôlent le comportement de l'agent :
- Agent Runtime - gère la boucle de l'agent, les limites et les stop reasons.
- Tool Execution Layer - exécute
tool_callde manière sûre via validation, policy et timeout. - Policy Boundaries - définit quelles actions sont autorisées et lesquelles sont bloquées par défaut.
- Memory Layer - aide à garder un état propre pour éviter les répétitions sans progrès.
Tu peux aussi passer aux scénarios d'échec ciblés :
- Infinite loop - comment détecter et arrêter les répétitions sans progrès.
- Tool spam - comment limiter les appels d'outil dupliqués.
- Budget explosion - comment contrôler la dépense en tokens et le budget API.