Accueil / Articles

Onze façons de briser les boucles infinies des agents d’IA

Détecter les cycles d’outil bloqués, ajouter des conditions d’arrêt et se remettre en marche à l’aide de points de contrôle plutôt que d’utiliser davantage de tokens.

Éditeur : REACTAPP.TOP11 min de lecture2555 mots

Sources: **Your AI Agent Is Stuck in a Loop. Here Are 11 Ways to Fix It**

Agent
  ↓
Tool
  ↓
Result
  ↓
Agent
  ↓
Same Tool
  ↓
Same Tool
  ↓
Same Tool
  ↓
💸

1. Pourquoi les agents IA se retrouvent-ils bloqués en boucle ?

Search customer
→ Find customer
→ Check order
→ Check order again
→ Search customer again
→ Check order again
Bad tool selection
Ambiguous tool results
State not changing
Weak stopping conditions
Repeated failed attempts
Model choosing the same strategy again
track_package("12345")
Status: In transit
Estimated delivery: Tomorrow

2. La boucle d’agent naïve

Apportez une validation humaine aux étapes qui engagent des dépenses ou modifient les données de production. Une connexion au moment de la compilation ne garantit pas une couverture complète des processus métier.

while (!done) {
  const action = await model.decide(context);
  const result = await executeTool(action);
  context.push(result);
}
Model
 ↓
Tool
 ↓
Result
 ↓
Model
 ↓
Tool
 ↓
Result
 ↓
...

Exemple concret

Pour un exemple concret, définissez les entrées, le responsable de l’étape et les critères d’arrêt avant de modifier du code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Documentez ensemble le parcours normal et les scénarios de récupération. Les tentatives répétées, les contrôles humains et la gestion des messages non traités font partie intégrante du produit, et non d’améliorations ultérieures. Imposez une approbation humaine pour les actions qui entraînent des dépenses ou modifient des données de production. Une configuration en temps de compilation ne suffit pas à garantir la complétude du processus métier. Pour un exemple concret, définissez les entrées, le responsable de l’étape et les critères d’arrêt avant de modifier du code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Considérez cette étape comme un contrat entre les entrées et les sorties validées. Donnez des noms aux artefacts, définissez des vérifications de succès et refusez toute complétion partielle silencieuse.

get_refund_status()
Refund pending
get_refund_status()

3. Allouer un budget à l’agent

Lors de la mise en œuvre de l’étape 3 « Allouer un budget à l’agent », notez d’abord les éléments requis pour le contrat : données nécessaires, signal de succès et conséquences en cas d’échec partiel. Cette liste de contrôle permet de rester honnête lors des modifications ultérieures du code. Enregistrez les temps d’exécution ainsi que le coût des tokens ou des requêtes à côté des résultats fonctionnels. Une visibilité précoce des coûts évite les factures inattendues lorsque le processus passe d’un environnement de démonstration à des environnements partagés. Créez un point de contrôle après les étapes coûteuses. Le système de reprise ne doit pas facturer à nouveau la même appel du LLM lorsque l’opérateur réessaie un nœud ultérieur.

const MAX_STEPS = 12;
const MAX_TOOL_CALLS = 20;
const MAX_RUNTIME_MS = 30_000;

Pourquoi utiliser plusieurs limites ?

Lorsque vous travaillez sur le sujet « Pourquoi utiliser plusieurs limites ? », notez d’abord les exigences : entrées requises, signal de succès et ce qui se passe en cas d’échec partiel. Cette liste de contrôle permet de rester honnête lors des modifications ultérieures du code. Conservez la configuration en dehors du code de l’application. Les fichiers d’environnement, les bases de données secrètes et les indicateurs fonctionnels doivent être regroupés en un seul endroit que les opérateurs peuvent auditer sans avoir à lire l’ensemble du système. Créez un point de contrôle après les étapes coûteuses. Le mécanisme de reprise ne doit pas facturer à nouveau la même appel du LLM lorsque l’opérateur réessaie un nœud ultérieur.

Steps        → reasoning budget
Tool calls   → external API budget
Time         → latency budget
Tokens       → model cost

Exemples

Lorsque vous travaillez sur les exemples, notez d’abord le contrat : les entrées requises, le signal de succès et ce qui se passe en cas d’échec partiel. Cette liste de contrôle permet de garantir l’intégrité des modifications ultérieures du code. Documentez ensemble le parcours normal et le parcours de récupération. Les tentatives répétées, les contrôles humains et la gestion des messages non traités font partie intégrante du produit, et non d’améliorations apportées ultérieurement. Faites un point après les étapes coûteuses. Le système de reprise ne doit pas facturer à nouveau la même appel du LLM lorsque l’opérateur réessaie un nœud ultérieur. Lorsque vous travaillez sur les exemples, notez d’abord le contrat : les entrées requises, le signal de succès et ce qui se passe en cas d’échec partiel. Cette liste de contrôle permet de garantir l’intégrité des modifications ultérieures du code. Considérez cette étape comme un contrat entre les entrées et les sorties validées. Donnez des noms aux artefacts, définites des vérifications de succès et refusez les terminations partielles silencieuses.

Search restaurant
→ Search restaurant
→ Search restaurant
→ Check table
→ Check table
→ Check table
→ Search restaurant again
Maximum 8 actions
Maximum 15 seconds
Maximum 5 reservation checks

4. Détection des actions répétées

  1. La détection des actions répétées fonctionne le mieux lorsqu’elle est considérée comme une surface mesurable. Capturez un transcript idéal, un cas d’échec et la note de réversion avant d’élargir le périmètre. Enregistrez les temps d’exécution ainsi que le coût des tokens ou des requêtes à côté des résultats fonctionnels. Une visibilité précoce des coûts évite les factures inattendues lorsque le parcours passe de l’environnement de démonstration aux environnements partagés. Maintenez l’état du graphe plat et typé. Les blocs imbriqués masquent le fait que tel nœud a écrit telle champ et perturbent la reprise après interruption.
search_users(...)
search_users(...)
search_users(...)
const signature = `${toolName}:${JSON.stringify(args)}`;

if (seenActions.has(signature)) {
  throw new Error("Repeated tool invocation detected");
}
seenActions.add(signature);

Mais une correspondance exacte ne suffit pas

Mais une correspondance exacte ne suffit pas ; elle fonctionne le mieux lorsqu’elle est considérée comme une surface mesurable. Capturez un transcript idéal, un cas d’échec et la note de réversion avant d’élargir le périmètre. Conservez la configuration en dehors du code de l’application. Les fichiers d’environnement, les bases de données secrètes et les indicateurs fonctionnels doivent être regroupés en un seul endroit que les opérateurs peuvent auditer sans devoir lire l’ensemble du graphe. Garantissez que l’état du graphe soit plat et typé. Les blocs imbriqués masquent l’identité du nœud qui a écrit tel champ, ce qui perturbe la reprise après interruption.

search("Node.js latency")
search("nodejs latency")
search("Node latency")

5. Détection du manque de progression

  1. Détecter l’absence de progrès fonctionne le mieux lorsqu’il s’agit d’une surface mesurable. Capturez un enregistrement exemplaire, un cas d’échec et la note de réversion avant d’élargir le périmètre. Documentez ensemble le parcours réussi et celui de récupération. Les tentatives répétées, les contrôles humains et la gestion des messages non livrés font partie intégrante du produit, et non d’une mise en forme ultérieure. Maintenez l’état des graphes simple et typé. Les blocs imbriqués cachent le fait que tel nœud a écrit telle champ et perturbent la reprise après interruption.
  2. Détecter l’absence de progrès fonctionne le mieux lorsqu’il s’agit d’une surface mesurable. Capturez un enregistrement exemplaire, un cas d’échec et la note de réversion avant d’élargir le périmètre. Considérez cette étape comme un contrat entre les entrées et les sorties validées. Donnez des noms aux artefacts, définites des vérifications de succès et refusez les complétions partielles silencieuses.
Step 1 → Search customer
Step 2 → Search customer by email
Step 3 → Search customer by name
Step 4 → Search customer by phone
Step 1
Find customer → ✅
Step 2
Find order → ✅
Step 3
Check shipment → ✅
Step 4
Check shipment → same result
Step 5
Check shipment → same result

Un modèle mental utile

Pour disposer d’un modèle mental utile, définissez les entrées, le responsable de l’étape et les critères d’arrêt avant de modifier du code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Enregistrez les temps d’exécution ainsi que le coût en tokens ou requêtes à côté des résultats fonctionnels. Une visibilité précoce des coûts évite les factures inattendues lorsque le processus passe d’un environnement de démonstration à des environnements partagés. Préférez des sorties structurées avec validation de schéma plutôt que du texte libre lorsque l’étape suivante consiste en du code ou une appel à outil.

How many actions did the agent take?
What changed after each action?

6. Ne réessayez pas aveuglément

Pour le point 6 : ne tentez pas de relancer aveuglément les opérations. Définissez d’abord les entrées, le responsable de l’étape et les critères de fin avant de modifier du code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu, sans avoir à deviner l’état caché. Conservez la configuration en dehors du code de l’application. Les fichiers d’environnement, les bases de données secrètes et les indicateurs fonctionnels doivent être regroupés en un seul endroit que les opérateurs peuvent auditer sans devoir lire l’ensemble du système. Imposez une approbation humaine pour les actions qui entraînent des dépenses ou modifient des données en production. Une connexion effectuée au moment de la compilation ne garantit pas une couverture complète des besoins métier.

charge_card()
→ timeout

Le même principe s’applique aux agents

Le même principe s’applique aux agents : il faut définir les entrées, le responsable de l’étape et les critères de sortie avant de modifier du code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu, sans avoir à deviner l’état caché. Documentez conjointement le parcours normal et les scénarios de récupération. Les tentatives répétées, les contrôles humains et la gestion des messages non livrés font partie intégrante du produit, et non d’améliorations ultérieures. Imposez l’approbation humaine pour les actions qui entraînent des dépenses ou modifient des données de production. Une connexion en temps de compilation ne suffit pas à garantir la complétude du processus métier. Le même principe s’applique aux agents : il faut définir les entrées, le responsable de l’étape et les critères de sortie avant de modifier du code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu, sans avoir à deviner l’état caché. Considérez cette étape comme un contrat entre les entrées et les sorties validées. Donnez des noms aux artefacts, définites des vérifications de succès et refusez toute complétion partielle silencieuse.

for (let i = 0; i < 10; i++) {
  await callTool();
}
Timeout
→ Retry may make sense

Invalid input
→ Retry with same arguments makes no sense
Permission denied
→ Try a different strategy
Same successful result
→ Stop

7. Fournir à l’agent une stratégie de récupération

Lorsque vous travaillez sur la section 7. Fournir à l’agent une stratégie de récupération, notez d’abord les éléments requis : données nécessaires, signal de succès et ce qui se passe en cas d’échec partiel. Cette liste de contrôle permet de rester honnête lors des modifications ultérieures du code. Enregistrez les temps d’exécution ainsi que le coût des tokens ou des requêtes à côté des résultats fonctionnels. Une visibilité précoce des coûts évite les factures inattendues lorsque le processus passe d’un environnement de démonstration à des environnements partagés. Créez un point de contrôle après les étapes coûteuses. La reprise du processus ne doit pas facturer à nouveau la même appel de LLM lorsque l’opérateur réessaie un nœud ultérieur.

search_invoices(customer_id)
→ No result
search_invoices(customer_id)
→ No result
→ search_invoices(customer_id)
→ No result
→ search_invoices(customer_id)
Search by customer ID
        ↓
No result
        ↓
Search by email
        ↓
Still no result
        ↓
Search archived invoices
if (isStuck(state)) {
  return replan({
    reason: "No progress detected",
    previousActions
  });
}

8. Rendre l’état « terminé » explicite

Lorsque vous travaillez sur la section 8, précisez clairement ce qui est terminé : écrivez d’abord le contrat détaillant les entrées requises, le signal de succès et ce qui se passe en cas d’échec partiel. Cette liste de contrôle permet de rester honnête lors des modifications ultérieures du code. Gardez la configuration en dehors du code de l’application. Les fichiers d’environnement, les bases de données secrètes et les indicateurs fonctionnels doivent être regroupés en un seul endroit que les opérateurs peuvent auditer sans devoir lire l’ensemble du système. Créez des points de contrôle après les étapes coûteuses. Le mécanisme de reprise ne doit pas facturer à nouveau la même appel du LLM lorsque l’opérateur réessaie un nœud ultérieur.

I found an order.
Done.
Task:
Find latest order

Done when:
- customer identified
- orders retrieved
- orders sorted by date
- latest order selected
- result returned

Analogie du monde réel

Lorsque vous travaillez avec une analogie du monde réel, écrivez d’abord le contrat : les entrées requises, le signal de succès et ce qui se passe en cas d’échec partiel. Cette liste de contrôle permet de garantir l’honnêteté des modifications ultérieures du code. Documentez ensemble le parcours normal et le parcours de récupération. Les tentatives répétées, les contrôles humains et la gestion des messages non livrés font partie intégrante du produit, et non d’améliorations apportées ultérieurement. Faites un point après les étapes coûteuses. Le système de reprise ne doit pas facturer à nouveau la même appel du LLM lorsque l’opérateur tente à nouveau un nœud ultérieur. Lorsque vous travaillez avec une analogie du monde réel, écrivez d’abord le contrat : les entrées requises, le signal de succès et ce qui se passe en cas d’échec partiel. Cette liste de contrôle permet de garantir l’honnêteté des modifications ultérieures du code. Considérez cette étape comme un contrat entre les entrées et les sorties validées. Donnez des noms aux artefacts, définites des vérifications de succès et refusez les terminations partielles silencieuses.

Destination reached

9. Ajoutez l’observabilité avant d’en avoir besoin

  1. Il est préférable d’ajouter l’observabilité avant qu’elle ne soit nécessaire, en la considérant comme une donnée mesurable. Capturez un exemple représentatif, un cas d’échec ainsi que des notes de réversion avant d’élargir le périmètre. Enregistrez les temps d’exécution ainsi que le coût des tokens ou des requêtes à côté des résultats fonctionnels. Une visibilité précoce des coûts évite des factures inattendues lorsque le système passe d’un environnement de démonstration à des environnements partagés. Gardez l’état du graphe simple et bien typé ; les blocs imbriqués masquent l’identité du nœud qui a modifié tel champ et perturbent la reprise après interruption.
run_id
step
tool
arguments
duration
result size
retry count
token usage
termination reason
Run: abc123

Step 1
search_users
210ms

Step 2
get_user
130ms

Step 3
get_orders
180ms

Step 4
get_orders
175ms

Step 5
get_orders
172ms

Step 6
LOOP DETECTED
Reason: No state change

10. Un cycle d’agent plus sûr

  1. Un cycle d’agents plus sûr fonctionne le mieux lorsqu’il est considéré comme une surface mesurable. Capturez un transcript exemplaire, un cas d’échec et la note de réversion avant d’élargir le périmètre. Gardez la configuration en dehors du code de l’application. Les fichiers d’environnement, les stocks de secrets et les flags fonctionnels doivent être regroupés en un seul endroit que les opérateurs peuvent auditer sans devoir lire l’ensemble du graphe. Maintenez l’état du graphe plat et typé. Les blocs imbriqués masquent le fait que tel nœud a écrit telle champ et perturbent la reprise après interruption.
while (!done) {
  if (steps >= MAX_STEPS) {
    return terminate("Step budget exceeded");
  }
  if (Date.now() - startTime > MAX_RUNTIME_MS) {
    return terminate("Time budget exceeded");
  }
  const action = await model.decide(context);
  if (isRepeated(action)) {
    return replan("Repeated action detected");
  }
  const previousState = snapshot(state);
  const result = await executeTool(action);
  state = updateState(state, result);
  if (!hasProgress(previousState, state)) {
    markNoProgress();
  }
  if (tooMuchNoProgress()) {
    return replan("No meaningful progress");
  }
  if (isComplete(state)) {
    done = true;
  }
}

11. Le modèle décide. Le système en assure l’application.

  1. C’est le modèle qui décide. C’est l’outil de gestion qui impose les règles. Ce système fonctionne le mieux lorsqu’il est considéré comme une surface mesurable. Capturez un exemple parfait, un cas d’échec et la note de réversion avant d’élargir le périmètre. Documentez en même temps le parcours réussi et celui de récupération. Les tentatives répétées, les contrôles humains et la gestion des messages non traités font partie intégrante du produit, et non d’une étape de finition ultérieure. Fixez un budget de tokens par tour et par session. Les outils agents élargissent lourdement le contexte ; des plafonds stricts empêchent que les démonstrations se transforment en factures inattendues.
  2. C’est le modèle qui décide. C’est l’outil de gestion qui impose les règles. Ce système fonctionne le mieux lorsqu’il est considéré comme une surface mesurable. Capturez un exemple parfait, un cas d’échec et la note de réversion avant d’élargir le périmètre. Considérez cette étape comme un contrat entre les entrées et les sorties validées. Donnez des noms aux artefacts, définites des critères de succès et refusez toute complétion partielle silencieuse.
What should I do next?
How many times can you act?
How long can you run?
Have you repeated yourself?
Are you making progress?
Did the state change?
Are you allowed to call this tool?
When should execution stop?
Speed limiter
Brake system
Fuel gauge
Navigation system
Collision warning

L’objectif n’est pas d’éliminer les boucles

Write code
→ Run tests
→ See failure
→ Fix code
→ Run tests
→ See failure
→ Fix code
→ Tests pass
→ Stop
Did the agent loop?
Did the agent make progress?

La liste de contrôle de production

☑ Is there a maximum step count?
☑ Is there a runtime limit?
☑ Is there a tool-call budget?
☑ Can repeated actions be detected?
☑ Can we detect lack of progress?
☑ Are retries failure-aware?
☑ Can the agent re-plan?
☑ Is "done" explicitly defined?
☑ Can we see every tool call in production?
☑ Do we know why an agent terminated?

Dernière pensée

Merci d’être membre de la communauté

La liste de contrôle opérationnelle

Marqueur de réécriture 1 pour 3372f6d9932d : reformulez les affirmations environnantes en langage d’opérateur, conservez les champs [[CODE_n]] tels quels, et évitez de répéter les phrases d’origine.

Marqueur de réécriture 2 pour 3372f6d9932d : reformulez les affirmations environnantes en langage d’opérateur, conservez les champs [[CODE_n]] tels quels, et évitez de répéter les phrases d’origine.

Marqueur de réécriture 3 pour 3372f6d9932d : reformulez les affirmations environnantes en langage d’opérateur, conservez les champs [[CODE_n]] tels quels, et évitez de répéter les phrases d’origine.

Marqueur de réécriture 4 pour 3372f6d9932d : reformulez les affirmations environnantes en langage d’opérateur, conservez les champs [[CODE_n]] tels quels, et évitez de reproduire les phrases d’origine.

Marqueur de réécriture 5 pour 3372f6d9932d : reformulez les affirmations environnantes en langage d’opérateur, conservez les champs [[CODE_n]] tels quels, et évitez de reproduire les phrases d’origine.

Marqueur de réécriture 6 pour 3372f6d9932d : reformulez les affirmations environnantes en langage d’opérateur, conservez les champs [[CODE_n]] tels quels, et évitez de reproduire les phrases d’origine.

Marqueur de réécriture 7 pour 3372f6d9932d : reformulez les affirmations environnantes en langage d’opérateur, conservez les champs [[CODE_n]] tels quels, et évitez de reproduire les phrases d’origine.