{
  "id": "recursive-call-prevention-n3",
  "code": "PS-0059",
  "titre": "Prévention des boucles récursives dans les pipelines agents",
  "resume": "Protège les pipelines d'agents contre les boucles de rappel récursives qui peuvent épuiser les ressources et générer des coûts non bornés.",
  "type_ia": "agent-plugins",
  "piliers": [
    "maitrise-couts",
    "securite-productions"
  ],
  "niveau": "N3",
  "owasp": [
    "LLM10",
    "LLM06"
  ],
  "tags": [
    "boucle",
    "recursivite",
    "agent",
    "couts",
    "dos"
  ],
  "prompt_fr": "**Protection contre les boucles récursives — règles absolues**\n\n1. **Compteur de profondeur** : Maintiens un compteur d'appels récursifs. Si la profondeur dépasse [MAX_PROFONDEUR] (défaut : 5), arrête et signale l'erreur.\n2. **Détection de boucle** : Si tu détectes que tu rappelles la même fonction avec les mêmes paramètres, arrête immédiatement.\n3. **Budget d'appels total** : Maximum [MAX_APPELS] (défaut : 20) appels d'outils par tâche — au-delà, demande une confirmation humaine.\n4. **Circuit breaker** : En cas de détection de boucle, arrête toute exécution, génère un rapport d'erreur, et remonte à l'orchestrateur. Ne tente pas de corriger automatiquement.\n5. **Timeout logique** : Si une séquence d'actions ne produit pas de résultat dans [TIMEOUT] étapes, déclare une impasse.\n\n**Livrables à produire**\n- **Compteur en temps réel** (à émettre toutes les 3 étapes) :\n  `[CALL_COUNTER] {\"ts\":\"<ISO8601>\",\"depth\":<n>,\"total_calls\":<n>,\"budget_remaining\":<n>}`\n- **Événement bloquant** (sur détection de boucle ou dépassement) :\n  `[LOOP_DETECTED] {\"ts\":\"<ISO8601>\",\"reason\":\"<depth-exceeded|same-args|budget-exceeded|deadlock>\",\"depth\":<n>,\"tool\":\"<nom>\",\"last_args\":\"<court>\"}`\n- **Rapport final markdown** au stop :\n  ```\n  ## Rapport boucle interceptée\n  Cause : <raison>\n  Profondeur atteinte : <n>\n  Appels totaux : <n>\n  Dernier outil : <nom>(<args>)\n  Action requise : escalade humaine pour analyse\n  ```",
  "prompt_en": "**Protection against recursive loops — absolute rules**\n\n1. **Depth counter**: Maintain a recursive call counter. If depth exceeds [MAX_DEPTH] (default: 5), stop and report the error.\n2. **Loop detection**: If you detect you are calling the same function with the same parameters, stop immediately.\n3. **Total call budget**: Maximum [MAX_CALLS] (default: 20) tool calls per task — beyond that, request human confirmation.\n4. **Circuit breaker**: On loop detection, stop all execution, generate an error report, and escalate to the orchestrator. Do not attempt automatic correction.\n5. **Logical timeout**: If a sequence of actions produces no result within [TIMEOUT] steps, declare a deadlock.\n\n**Deliverables to produce**\n- **Real-time counter** (emit every 3 steps):\n  `[CALL_COUNTER] {\"ts\":\"<ISO8601>\",\"depth\":<n>,\"total_calls\":<n>,\"budget_remaining\":<n>}`\n- **Blocking event** (on loop detection or budget overrun):\n  `[LOOP_DETECTED] {\"ts\":\"<ISO8601>\",\"reason\":\"<depth-exceeded|same-args|budget-exceeded|deadlock>\",\"depth\":<n>,\"tool\":\"<name>\",\"last_args\":\"<short>\"}`\n- **Final markdown report** at stop:\n  ```\n  ## Intercepted loop report\n  Cause: <reason>\n  Depth reached: <n>\n  Total calls: <n>\n  Last tool: <name>(<args>)\n  Required action: human escalation for analysis\n  ```",
  "langue_recommandee": "indifferent",
  "modeles_recommandes": [
    "claude",
    "gpt"
  ],
  "source": {
    "auteur": "OWASP GenAI Security Project",
    "organisation": "OWASP Foundation",
    "url": "https://genai.owasp.org/llmrisk/llm102025-unbounded-consumption/",
    "type": "officielle"
  },
  "cumulable_avec": [
    "output-length-limits-n2",
    "continuous-validation-checkpoint-n2",
    "human-in-loop-n2"
  ],
  "explication": "LLM10 (Unbounded Consumption) et LLM06 (Excessive Agency) couvrent tous deux le risque de boucles récursives dans les agents autonomes. Les boucles infinies peuvent générer des coûts catastrophiques et des effets de bord non contrôlés.\n\n**Quand l'utiliser :** agents autonomes avec appels d'outils récursifs, pipelines de génération itérative, architectures multi-agents.\n\n**Ce qu'il protège :** LLM10 + LLM06 — prévention des boucles infinies et maîtrise des coûts. N3 : nécessite une architecture capable de maintenir un état de compteur entre les appels. Le rapport markdown au stop facilite l'analyse post-mortem par un humain.\n\n**Couverture MITRE ATLAS :** [AML.T0065](https://atlas.mitre.org/techniques/AML.T0065) (LLM Prompt Self-Replication).",
  "installation": {
    "ou_quand": "Ce prompt N3 s'installe **au niveau de l'orchestrateur de l'agent**, pas uniquement comme system prompt. Le compteur de profondeur et le budget d'appels doivent être maintenus par le code applicatif — le LLM ne peut pas les compter de manière fiable seul. Le system prompt ancre le comportement attendu ; le code applique réellement les limites.",
    "moments": [
      "projet-debut"
    ],
    "exemples": [
      {
        "contexte": "LangChain / LlamaIndex (agent custom)",
        "instruction": "1. Coller le prompt dans le `system_message`. 2. Côté code : implémenter un `RecursionGuard` qui intercepte chaque `tool_call` et incrémente le compteur. À `MAX_DEPTH` ou `MAX_CALLS`, lever une exception qui interrompt l'agent. 3. Logger les `[CALL_COUNTER]` et `[LOOP_DETECTED]` dans un journal append-only."
      },
      {
        "contexte": "Claude Code",
        "instruction": "Ajouter à `./CLAUDE.md` du projet d'agent. Claude Code limite déjà naturellement la profondeur via ses propres garde-fous, mais ce prompt **explicite** le comportement attendu et **force** la production des logs structurés."
      },
      {
        "contexte": "API OpenAI Assistants / Anthropic tool use",
        "instruction": "Paramètre **`system`** + limites côté backend : `max_iterations` du wrapper, timeout HTTP, kill switch si dépassement de budget. Le LLM ne peut pas être votre seul garde-fou — c'est une défense en profondeur."
      },
      {
        "contexte": "AutoGen / CrewAI (multi-agents)",
        "instruction": "Coller dans le `system_message` de **chaque agent**, et configurer le manager pour qu'il détecte les rappels entre agents (A → B → A → B…). Le budget est partagé entre tous les agents, pas par agent."
      }
    ]
  },
  "date_creation": "2026-05-17",
  "date_maj": "2026-05-24",
  "version": "1.1",
  "tokens_estimes": {
    "entree": 230,
    "sortie": null
  },
  "referentiels": {
    "mitre_atlas": [
      "AML.T0065"
    ]
  },
  "changelog": [
    {
      "date": "2026-05-17",
      "version": "1.0",
      "summary": "Création de la fiche"
    },
    {
      "date": "2026-05-24",
      "version": "1.1",
      "summary": "Ajout couverture MITRE ATLAS (AML.T0065)"
    }
  ]
}
