Idée en 30 secondes
No Stop Conditions est un anti-pattern où un agent démarre sans conditions de fin claires.
Résultat : l'agent peut boucler et consommer du budget sans progrès réel. Cela augmente la latency, le cost et le risque d'effets secondaires (changements d'état).
Règle simple : chaque run d'agent doit avoir des stop conditions explicites pour une terminaison réussie et une sortie sûre.
Exemple de l'anti-pattern
L'équipe construit un agent support qui doit trouver une réponse dans des données internes et retourner le résultat à l'utilisateur.
Mais la boucle agent n'a pas de stop conditions claires.
state = init_state(user_message)
while True:
decision = agent.next_step(state)
result = run_tool(decision.tool, decision.args)
state.append(result)
# pas de has_final_answer(...)
# pas de no_progress(...)
# pas de vérification repeated_action(...)
Dans ce schéma, l'agent peut répéter indéfiniment des étapes similaires :
search_docs -> fetch_page -> summarize -> search_docs -> ...
Pour ce cas, il faut une boucle contrôlée avec des limites explicites :
for step in range(MAX_STEPS):
...
if has_final_answer(state):
return build_answer(state)
Ici, l'absence de stop conditions entraîne :
- risque de runaway loop (boucle infinie)
- appels tool et LLM inutiles
- consommation non contrôlée du temps et du budget
Pourquoi cela arrive et ce qui se passe mal
Cet anti-pattern apparaît souvent quand l'équipe se repose sur le modèle et suppose qu'il va "comprendre" seul quand arrêter.
Causes typiques :
- absence de
max_steps,timeoutou budget limit explicite - pas de définition de ce qu'est une "réponse prête"
- pas de vérification
no_progressni d'actions répétées - le contrôle d'arrêt reste uniquement au niveau infrastructure
Cela crée des problèmes :
- boucles infinies ou longues - l'agent répète des étapes proches sans terminer
- latency plus élevée - la réponse arrive beaucoup plus tard, ou n'arrive jamais
- cost plus élevé - le nombre d'étapes LLM/tool augmente pour une demande
- effets secondaires (changements d'état) - actions répétées pouvant créer des doublons, réappliquer un statut, dupliquer un appel API ou renvoyer une action externe
- résultats instables - une même demande se termine différemment selon les runs
Signaux production typiques montrant que les stop conditions sont absentes ou faibles :
- une part visible des runs finit en infrastructure timeout au lieu d'un arrêt contrôlé
- le
P95du nombre d'étapes augmente en continu - les traces montrent des appels identiques répétés avec peu de changement d'arguments
- le
cost per requestaugmente plus vite que lesuccess rate
Point important : chaque étape suivante fait partie de l'inference LLM. Si la boucle n'a pas de conditions de fin claires, le modèle continue à choisir "encore une étape", même quand il n'y a presque plus d'information utile nouvelle.
Quand ce schéma grossit, sans trace ni visualisation d'exécution, il devient difficile d'expliquer pourquoi un run ne s'est pas arrêté à temps. C'est pourquoi les systèmes de production ont généralement une couche d'observabilité dédiée aux runs d'agents.
Bonne approche
Commencez par la boucle contrôlée la plus simple qui couvre de façon stable la majorité des demandes actuelles. Ajoutez de nouvelles stop conditions uniquement lorsqu'il existe un échec mesurable, un risque ou une limite du design actuel.
Cadre pratique :
- définissez une condition de fin positive (
final_answer_ready) - définissez des garde-fous (
max_steps,timeout,budget) - ajoutez des vérifications
no_progresset des actions répétées - enregistrez stop reason pour chaque run et suivez les métriques (par exemple, amélioration de success rate sans forte hausse de latency et de cost per request)
En pratique, no_progress signifie souvent répétition des mêmes appels tool, changements d'état minimes, ou absence de nouvelle information utile après une étape supplémentaire.
MAX_STEPS = 8
def run_agent(user_message: str):
state = init_state(user_message)
for step in range(MAX_STEPS): # hard limit for runaway loops
if timed_out():
return stop("timeout")
if budget_exceeded():
return stop("budget_exceeded")
decision = agent.next_step(state)
if decision.type == "final_answer":
if validate_output(decision.output): # format, required fields, no empty answer
return decision.output
return stop("invalid_output")
result = run_tool(decision.tool, decision.args)
if no_progress(state, result): # same tool/result pattern or no meaningful state change
return stop("no_progress")
state.append(result)
return stop("max_steps_exceeded")
Dans ce schéma, la boucle devient contrôlée : le système retourne soit une réponse valide, soit un arrêt avec raison transparente.
Test rapide
Si vous répondez "oui" à ces questions, vous avez un risque no-stop-conditions :
- Une partie des runs se termine-t-elle en timeout au lieu d'un
stop_reasoncontrôlé ? - Une seule demande fait-elle parfois un nombre disproportionné d'étapes sans progrès visible ?
- Les traces montrent-elles des actions similaires répétées sans nouveau résultat ?
Différence avec les autres anti-patterns
No Monitoring vs No Stop Conditions
| No Monitoring | No Stop Conditions |
|---|---|
| Problème principal : le système n'a pas assez d'observabilité pour voir ce qui se passe pendant un run. | Problème principal : la boucle agent n'a pas de conditions de fin claires. |
Quand il apparaît : quand logs de run, traces, métriques et stop_reason sont absents. | Quand il apparaît : quand un run continue sans max_steps, timeout, budget limit ni vérification no_progress. |
Agents Without Guardrails vs No Stop Conditions
| Agents Without Guardrails | No Stop Conditions |
|---|---|
| Problème principal : l'agent fonctionne sans policy boundaries ni limites système. | Problème principal : l'agent peut exécuter des boucles infinies ou trop longues. |
| Quand il apparaît : quand il n'y a pas d'allowlist, de deny-by-default, de limites budget ou safety. | Quand il apparaît : quand la logique de boucle n'a ni critère de fin explicite ni stop_reason contrôlé. |
Auto-vérification : avez-vous cet anti-pattern ?
Vérification rapide de l'anti-pattern No Stop Conditions.
Cochez les points pour votre système et regardez le statut ci-dessous.
Vérifiez votre système :
Progression: 0/8
⚠ Il y a des signes de cet anti-pattern
Essayez de déplacer les étapes simples dans un workflow et de garder l'agent uniquement pour les décisions complexes.
FAQ
Q : Si on a max_steps, est-ce déjà suffisant ?
R : Non. max_steps est nécessaire, mais ne couvre pas tous les risques à lui seul. Il faut aussi timeout, budget limit, vérification du progrès et critère valide de réponse prête.
Q : Quand ajouter une nouvelle stop condition ?
R : Quand il existe un signal concret : incidents, boucles répétées, hausse de cost ou de latency que les règles actuelles ne couvrent pas sans complexité disproportionnée.
Q : Comment démarrer si les stop conditions sont presque absentes aujourd'hui ?
R : Commencez avec le minimum : max_steps, timeout, budget, stop_reason dans les logs. Ajoutez ensuite no_progress et validation de la réponse finale.
Et ensuite
Anti-patterns proches :
- No Monitoring - quand vous ne voyez pas que l'agent boucle ou se dégrade.
- Too Many Tools - quand l'excès d'outils augmente le nombre d'étapes inutiles.
- Overengineering Agents - quand la complexité supplémentaire rend le contrôle de fin plus difficile.
Ce qu'il faut construire à la place :
- Stop Conditions - modèle de base pour définir des conditions d'arrêt sûres.
- Step Limits - comment définir des limites d'étapes au niveau gouvernance.
- Budget Controls - comment limiter le coût d'un run.
- Kill Switch - arrêt d'urgence quand le système sort du contrôle.