Accueil / Articles / Débogage des agents d’IA par couche : prompt, contexte, utilisation ou boucle

Débogage des agents d’IA par couche : prompt, contexte, utilisation ou boucle

Un modèle en couches pour les défaillances des agents d’IA : en quoi la conception des prompts, du contexte, des mécanismes de contrôle et des boucles diffèrent, ainsi qu’une procédure axée sur le suivi pour déterminer quelle couche a échoué.

3217 mots

Lorsqu’un agent IA se comporte mal en production, les équipes ont tendance à discuter du vocabulaire plutôt que des preuves : un ingénieur souhaite un meilleur prompt, un autre accuse le contexte, et un troisième pointe du doigt l’infrastructure. L’ingénierie des prompts, du contexte, de l’infrastructure et des boucles n’est pas constituée de courants de pensée rivaux ; il s’agit de quatre couches superposées, chacune échouant à sa propre manière reconnaissable. Ce guide définit chaque couche à l’aide d’un petit exemple de code avec un agent, puis vous propose une procédure basée sur le suivi des traces pour déterminer quelle couche a réellement échoué avant de modifier le moindre code.

La version courte

  • L’ingénierie des prompts définit les instructions données au modèle.
  • L’ingénierie du contexte décide de ce que le modèle voit avant de répondre.
  • L’ingénierie de l’infrastructure crée l’environnement dans lequel le modèle agit : outils, mémoire, fichiers, permissions et mécanismes de récupération.
  • Ingénierie des boucles : conception du cycle qui maintient le système en fonctionnement, vérification de son propre progrès et décision du moment d’arrêt.
  • La plupart des incidents coûteux liés aux agents proviennent de la correction d’une couche erronée parmi celles-ci.

    Lorsque la démonstration fonctionne mais pas en production

    C’est un schéma familier : un agent semble parfait lors d’une démonstration. Quelques jours après le lancement, il commence à boucler sans cesse, à consommer des tokens inutilement, oublie des informations qui lui avaient été communiquées une heure plus tôt, ou tombe en panne dès qu’un outil renvoie un chargement inattendu.

    L’équipe se divise en camps : certains proposent de réécrire le prompt, d’autres parlent d’un problème de contexte, et un troisième groupe soupçonne le framework utilisé. Sans méthode commune pour identifier la cause du dysfonctionnement, une correction prévue en deux jours se transforme en une réécriture de deux semaines, car chaque correctif s’applique à une couche qui fonctionnait pourtant correctement auparavant.

    C’est la raison pratique de maintenir ces quatre termes distincts. Chacun désigne un endroit précis où les choses peuvent mal se passer, et une fois qu’on sait les distinguer, le débogage devient un processus structuré plutôt qu’un jeu de devinette.

    PACT : un mnémotechnique pour les quatre couches

    Un moyen concis de se rappeler ces couches en cas d’incident est PACT : Prompt, Awareness, Control, Trajectory. Chaque mot correspond à une question :

    • Prompt : la tâche a-t-elle été définie clairement ?
    • Awareness : le modèle a-t-il reçu les informations nécessaires pour cette étape ?
    • Control : le système peut-il exécuter ce que le modèle demande, de manière sûre et fiable ?
    • Trajectory : le processus itératif mène-t-il vers une fin vérifiable ?

    L’objectif n’est pas d’ajouter une couche supplémentaire de jargon. Il s’agit de rendre les distinctions entre les types d’échec suffisamment faciles à retenir afin que vous puissiez vraiment les utiliser lorsque quelque chose prend feu.

    Comment ces couches sont apparues, et pourquoi l’ordre compte

    Ces termes sont apparus plus ou moins dans cet ordre, à mesure que les outils acquéraient de nouvelles capacités :

    • L’ingénierie des prompts (environ de 2022 à 2024) a été la première compétence : formulation des phrases, exemples, contraintes et schémas à quelques exemples visant une seule requête au modèle.
  • L’ingénierie du contexte (environ 2024 à 2025) a pris le dessus lorsque les agents ont dû gérer en même temps des documents récupérés, un historique de conversations et des définitions d’outils. La question a évolué, passant de la manière de formuler une demande à ce que le modèle voit réellement. Anthropic, LangChain et Chroma ont contribué à populariser cette approche parmi les professionnels, tandis que les commentaires d’Andrej Karpathy l’ont intégrée dans des discussions plus larges en ingénierie.
  • L’ingénierie de l’exploitation (début 2026) est devenue un enjeu majeur lorsque les agents ont obtenu un accès au système de fichiers, des commandes shell et la capacité d’exécuter des tâches pendant plusieurs heures. L’attention s’est portée sur la portée de l’agent ainsi que sur son comportement en cas d’appel d’outil échoué. Le travail d’OpenAI sur Codex a rendu ce sujet particulièrement important pour les agents de programmation ; son article sur l’ingénierie de l’exploitation avec Codex constitue une référence utile.
  • L’ingénierie des boucles (milieu 2026) est la nouvelle catégorie. Même avec un système de gestion en place, il reste nécessaire de déterminer ce que fait chaque itération et quand s’arrêter : observer, agir, vérifier, répéter ou cesser. IBM propose un explication sur l’ingénierie des boucles si vous souhaitez une autre perspective.
  • Ces dates indiquent quand ces termes ont gagné en popularité, et non des jalons formels ; de plus, le vocabulaire est encore en pleine évolution au moment de la rédaction. Ce qui est important à noter, c’est qu’aucun élément n’a été remplacé. Chaque couche a été ajoutée par-dessus la précédente, car chaque augmentation de l’autonomie nécessitait sa propre interface de contrôle.

    Ingénierie des prompts : le contrat local

    L’ingénierie des prompts consiste à formuler, structurer et illustrer une instruction de manière à rendre la réponse plus prévisible. Sans cela, on obtient des instructions vagues, des formats de sortie imprévisibles et un modèle contraint de deviner ce que l’on veut dire.

    Dans un agent de codage, un prompt d’examen de code pourrait ressembler à ceci :

    SYSTEM: You are a code reviewer.
    Given a diff, output ONLY valid JSON:
    {"issues": [{"line": int,
    "severity": "low|medium|high", "note": str}]}
    No prose. No markdown fences.
    If there are no issues, return {"issues": []}.
    

    Ce prompt définit un contrat local. Il attribue un rôle, décrit la transformation (différences à appliquer, liste des problèmes à identifier), précise la structure de la sortie jusqu’aux noms des champs et aux valeurs de gravité autorisées, et définit même le cas vide afin que le traitement ultérieur n’ait jamais à gérer du texte ou l’absence d’une clé.

    On affirme souvent que l’ingénierie des prompts est obsolète. Ce n’est pas le cas ; elle constitue plutôt la couche la plus fondamentale. Chaque pipeline de contexte finit par transmettre au modèle une instruction, et une instruction faible placée dans un cadre excellent produit toujours des résultats faibles, seulement désormais enveloppés dans une infrastructure impressionnante.

    Ingénierie du contexte : sélection judicieuse dans des limites budgétaires

    L’ingénierie du contexte consiste à choisir, pour chaque appel, quels documents, quelles données historiques, quelles définitions d’outils et quelles mémoires seront intégrés dans la fenêtre de contexte, ainsi qu’à décider délibérément de ceux qui ne le seront pas. Lorsqu’elle est négligée, le modèle répond en se basant sur des informations obsolètes, est dévié par des extraits irrelevants ou perd son focus à cause d’une fenêtre surchargée de matériel ajouté par précaution.

    def build_context(query, full_history, kb):
        relevant = retrieve(query, kb, top_k=8)
        reranked = rerank(relevant, query)[:3]
        summary = summarize_if_long(
            full_history, max_tokens=800
        )
        return {
            "docs": reranked,
            "history": summary,
            "query": query,
        }
    

    Il s’agit d’un processus en forme de entonnoir : la récupération élargit le champ des candidats à huit, le classement ultérieur en retient les trois les plus pertinents, et l’historique des conversations n’est résumé à environ 800 tokens que lorsqu’il devient trop long. La fonction renvoie un envoi de données compact et structuré plutôt que des informations brutes. Les compétences requises sont le sélectionnement, le classement et la compression, et non simplement l’accumulation de données.

    C’est pourquoi le malentendu le plus courant, selon lequel l’ingénierie du contexte signifie fournir davantage d’informations au modèle, est généralement erroné. Un contexte plus volumineux contient souvent davantage de bruit : instructions obsolètes, faits répétés et éléments contradictoires. Une grande partie du travail consiste à choisir ce qui doit être omis.

    L’ingénierie du contexte est plus large que le RAG

    La génération augmentée par la récupération est une technique au sein de l’ingénierie du contexte, qui concerne l’étape de récupération des informations. Un pipeline RAG peut extraire huit fragments d’information puis les réclasser en trois, comme indiqué ci-dessus. L’ingénierie du contexte comprend également la compression de l’historique, le formatage des définitions d’outils, le maintien de l’état critique de la tâche, l’envoi des résultats de vérification au modèle, ainsi que la décision de ce qui doit être omis.

    Même un agent de codage ne disposant d’aucun stock vectoriel doit encore résoudre un véritable problème de contexte. L’état de Git, les fichiers ouverts, les erreurs de compilation, les résultats des tests, le plan en cours ainsi que le journal des actions précédentes doivent tous parvenir au modèle sous une forme utilisable.

    Ingénierie de l’exploitation : la frontière entre intention et effet

    Le harnais représente la partie non liée au modèle du système : les outils et l’accès aux fichiers, la mémoire persistante, les règles de permission, les environnements isolés, le suivi des opérations, ainsi que tout ce qui se produit en cas d’échec. Sans un bon harnais, on obtient un agent qui sait raisonner mais ne peut pas agir en conséquence, ou bien un agent qui agit mais n’a aucun moyen fiable de se remettre en état lorsque l’appel à un outil échoue.

    Un enveloppeur d’appel à outil illustre bien cette idée :

    def call_tool(tool_name, args, retries=2):
        for attempt in range(retries + 1):
            try:
                result = TOOLS[tool_name](**args)
                log_trace(tool_name, args, result, status="ok")
                return result
            except ToolError as e:
                log_trace(tool_name, args, str(e), status="failed")
                if attempt == retries:
                    return {"error": str(e), "recoverable": False}
                args = repair_args(args, e)
    

    Cet enveloppeur ne tente pas de résoudre la tâche. Il définit les limites entre ce que le modèle a demandé et ce que fait le système réel. Chaque tentative est enregistrée avec ses arguments, son résultat et son statut. En cas d’échec, une tentative de réessai est lancée avec des arguments corrigés ; une fois les tentatives épuisées, l’enveloppeur renvoie une erreur structurée indiquant qu’elle n’est pas récupérable, permettant ainsi à l’appelant d’obtenir des données sur lesquelles il peut raisonner plutôt qu’une exception qui met fin à l’exécution.

    Il est tentant d’équivaler le harness au framework d’agent que vous avez installé. Un framework fournit une structure de base ; le harness, quant à lui, représente l’ensemble des décisions concrètes que vous prenez par rapport à cette structure : ce qui est enregistré, quelle action est entreprise en cas d’appel échoué, quel état survit à une panne, quels commandes sont autorisées, et comment les résultats de l’exécution sont restitués au modèle.

    Ingénierie des boucles : le contrat de terminaison

    L’ingénierie des boucles définit les tâches de chaque itération, la manière dont l’agent évalue s’il progresse, et surtout les conditions de cessation. Son échec typique est la boucle infinie : un agent qui continue d’appeler des outils et de consommer des tokens parce que rien ne lui indique qu’il a terminé ou qu’il est bloqué.

    def run_loop(task, harness, max_iters=15, stall_limit=3):
        state = init_state(task)
        stalls = 0
        for i in range(max_iters):
            action = plan_next_step(state)
            result = harness.call_tool(action.tool, action.args)
            state = update_state(state, result)
            if is_goal_met(state):
                return state, "success"
            if made_no_progress(state):
                stalls += 1
                if stalls >= stall_limit:
                    return state, "stalled — escalate"
            else:
                stalls = 0
        return state, "max iterations reached"
    

    Diverses limites sont appliquées ici. max_iters fixe la limite totale des itérations, is_goal_met permet de sortir en cas de réussite, et un compteur d’immobilisation suit les itérations consécutives sans progression, se réinitialisant dès que la progression reprend. Après stall_limit étapes d’immobilisation, la boucle renvoie un statut distinct indiquant la nécessité d’une escalade plutôt que de continuer silencieusement. Chaque voie de sortie indique explicitement la raison, ce qui facilite la classification des exécutions par la suite.

    L’idée centrale est le contrat de terminaison : un objectif clair, des indicateurs de progression mesurables, un nombre limité de tentatives, des budgets alloués pour le temps et les tokens, une étape de vérification, ainsi qu’une politique définie pour savoir quoi faire en cas d’arrêt de la progression. Pour des implémentations en TypeScript de ces mêmes concepts, consultez les boucles agentes limitées pour l’utilisation d’outils LLM.

    Les concepts de boucle et d’ingénierie de harness sont souvent confondus. Le harness définit ce que l’agent peut manipuler et comment les pannes sont gérées au niveau des outils individuels. La boucle se situe au-dessus et détermine le comportement étape par étape, y compris le moment où l’exécution dans son ensemble doit s’arrêter.

    Les quatre couches côte à côte

    • Prompt (P) : concerne les instructions. Échec typique : le modèle interprète mal l’intention ou renvoie un format incorrect. Première chose à vérifier : le résultat lui-même.
    • Contexte (A) : concerne l’état prêt à être utilisé par le modèle. Échec typique : le modèle agit sur des informations obsolètes, manquantes ou perturbatrices. Première chose à vérifier : les captures d’écran du contexte à chaque tour.
    • Harness (C) : concerne l’exécution et la récupération. Échec typique : les appels aux outils échouent, des tentatives de réessai sont effectuées sans discernement ou il n’est pas possible de se remettre en marche. Première chose à vérifier : les entrées échouées dans le suivi des outils.
    • Loop (T) : concerne les progrès et l’arrêt. Échec typique : l’agent ne converge jamais ou ne s’arrête jamais. Première chose à vérifier : des appels réussis répétés avec des arguments presque identiques.

    Distinguer une erreur du harness d’une erreur de boucle

    La constatation la plus utile pour gagner du temps est que deux bugs différents peuvent avoir l’air identiques de l’extérieur. Un agent bloqué dans une boucle en raison d’un contrôleur défectueux et un agent bloqué à cause d’un problème de gestion des outils présentent tous deux le même symptôme : il continue de fonctionner, la facture augmente sans cesse, et personne ne sait pourquoi. Une courte liste de vérification permet de les distinguer des autres problèmes.

    1. Vérifier le suivi des appels aux outils

    Des appels qui réussissent tous avec des résultats plausibles, tandis que l’agent utilise constamment le même outil avec presque les mêmes paramètres, indiquent une boucle.

    2. Rechercher des échecs répétés des outils

    Si un outil échoue à plusieurs reprises et que l’agent réessaie sans changer sa méthode, il faut suspecter le harness.

    3. Examiner ce que le modèle peut voir

    Si le modèle semble oublier un fait au milieu d’une exécution, examinez la construction du contexte : troncature, remplacement, compression ou la manière dont l’état est transmis entre les tours.

    4. Vérifiez d’abord la sortie

    Si les outils ont fonctionné, que le contexte était exact et que la boucle s’est terminée correctement, mais que la réponse est encore fausse, regardez le prompt.

    Une règle pratique

    Les bugs de boucle se situent dans la décision concernant ce qui se passe ensuite. Les bugs liés à l’utilisation des outils se situent dans ce qui se passe lorsque quelque chose ne fonctionne pas. Les bugs de contexte se situent dans ce que le modèle peut voir. Les bugs de prompt se situent dans ce que vous avez demandé.

    Répondez à la question qui correspond le mieux avant de modifier quoi que ce soit.

    Étude de cas : un examinateur de pull-request qui ne s’arrête pas

    Imaginez une équipe qui déploie un agent de codage chargé d’examiner les demandes de fusion. Les tests se déroulent sans problème. En production, certaines vérifications durent plus de 40 minutes pour une seule demande de fusion, ce qui entraîne des factures inattendues.

    La première théorie est que l’instruction donnée est trop vague et que l’agent réfléchit de manière excessive. L’instruction est réécrite, mais rien ne change. La deuxième théorie concerne le contexte : peut-être que l’agent relit tout le répertoire à chaque étape. Cependant, les traces montrent le contraire. La récupération des données est correctement ciblée, seuls les fichiers pertinents sont chargés.

    Ensuite, quelqu’un examine attentivement le journal des appels d’outils. L’agent invoque à plusieurs reprises son outil de exécution de tests, et chaque invocation se termine sans erreur. Le jeu de tests échoue réellement en raison d’un test d’intégration instable qui n’a aucun rapport avec la demande de fusion. L’agent continue d’essayer de corriger cet échec en apportant des modifications de code non pertinentes et en relançant les tests, car rien ne lui indique qu’il a effectué suffisamment d’essais pour ce sous-objectif et devrait s’arrêter pour demander de l’aide.

    Ce n’est ni un problème lié à la requête, ni un problème de contexte, ni un problème du framework ; les outils se sont comportés exactement comme prévu. Il s’agit purement d’une erreur de boucle. En analysant la situation étape par étape, on peut en arriver à cette conclusion.

    Étape 1 : vérifier que les outils fonctionnent

    Les exécutions réussies indiquées dans le journal éliminent les pannes les plus simples du framework, telles qu’une commande qui ne s’exécute jamais ou un adaptateur qui continue de planter.

    Étape 2 : comparer l’état entre les itérations

    La sortie du test est présente dans le contexte de l’agent, et la récupération des données s’effectue correctement, de sorte que le modèle ne manque pas d’éléments de preuve.

    Étape 3 : vérifier la convergence

    Le répertoire change à chaque itération, mais le signal de vérification pertinent ne s’améliore jamais. Il n’y a ni détecteur d’immobilisme ni limite au nombre d’essais pour atteindre le même sous-objectif.

    Étape 4 : apprendre au contrôleur à détecter la stagnation

    La solution consiste en une petite partie de logique de contrôleur qui compare les signes de progression entre les étapes :

    if progress_signature == previous_signature:
        stagnant_steps += 1
    else:
        stagnant_steps = 0
    
    if stagnant_steps >= 3:
        escalate("no measurable progress")
        stop()
    

    progress_signature peut être n’importe quoi qui permette de refléter un progrès significatif, par exemple l’ensemble des tests échoués ainsi que leurs messages d’erreur. S’il ne change pas, le compteur de stagnation augmente ; après trois étapes sans progression, le contrôleur envoie une raison d’arrêt. Tout changement réel réinitialise ce compteur.

    On peut aller plus loin en imposant un plafond aux tentatives par signature d’échec, et non seulement au nombre total d’itérations. Cette distinction est importante : quinze itérations productives peuvent être tout à fait acceptables, tandis que quinze tentatives face à un échec de test irréparable représentent une perte totale de temps. La véritable solution n’est pas de rendre le modèle moins têtu, mais de fournir au contrôleur une définition claire de ce qu’est une stagnation.

    Étude de cas : une contrainte qui disparaît du contexte

    Imaginez maintenant un agent qui détermine, au début d’une migration, qu’aucun élément ne doit endommager les clients existants. Quarante tours plus tard, la conversation est compressée et cette contrainte disparaît dans le résumé. L’agent propose alors un changement de schéma susceptible de causer des problèmes.

    Cela ressemble à un raisonnement erroné, mais la cause réside ailleurs. Comparez le contexte que le modèle a réellement reçu à différents moments. Si la contrainte était présente au cinquième tour mais absente au quarantième, la solution réside dans l’ingénierie du contexte : stocker les invariants critiques séparément de la conversation, faire en sorte que les résumés transmettent explicitement les contraintes, et cesser de considérer l’historique brut comme seule source de vérité.

    « Le modèle a oublié » n’est jamais un diagnostic complet. La question pertinente est de savoir ce que le modèle a réellement reçu.

    Strates, pas remplacements

    Chaque discipline plus récente s’appuie sur les disciplines antérieures plutôt que de les remplacer. Un agent de production enveloppe une instruction claire dans un contexte soigneusement choisi, l’exécute à l’intérieur d’un environnement fiable et gère tout le processus grâce à une boucle délibérée. La succession des éléments reflète ce que les équipes ont dû ajouter au fil du temps : des instructions plus claires, puis des informations mieux sélectionnées, ensuite un environnement d’exécution pour le modèle, et enfin un contrôleur qui maintient cet environnement en fonctionnement sans surveillance. Si vous devez décider si votre propre moteur d’exécution ou un framework doit gérer cette boucle externe, la comparaison des environnements d’exécution et frameworks composés présente les avantages et inconvénients respectifs.

    Résumé selon le modèle PACT :

    • Instruction : définir l’ordre d’exécution.
  • Conscience : construire l’état sur lequel le modèle fera des raisonnements.
  • Contrôle : rendre l’exécution observable, encadrée et réparable.
  • Trajectoire : transformer la répétition en progrès mesurable, aboutissant à une fin vérifiable.
  • Puis associer la correction à l’échec. Un modèle qui interprète mal une tâche clairement définie nécessite des travaux de correction immédiats. Un modèle qui manque d’informations dont il a besoin requiert des travaux de contextualisation. Des décisions judicieuses qui ne se traduisent pas en actions fiables exigent des travaux de mise en œuvre. Des actions qui réussissent alors que l’exécution globale ne converge jamais nécessitent des travaux de boucle.

    Questions fréquentes

    L’ingénierie de mise en œuvre n’est-elle qu’un autre nom pour un framework d’agent ?

    Non. Un framework fournit des éléments de base. Le « harness » correspond aux décisions que vous prenez lors de leur assemblage : le comportement en cas de panne d’outil, l’état persistant, la journalisation, les permissions, ainsi que le mode de retour des résultats vers le modèle.

    Un assistant à une seule question a-t-il besoin d’ingénierie de boucle ?

    Pas vraiment. L’ingénierie de boucle devient importante lorsque l’agent effectue plusieurs actions par tâche et doit déterminer, de manière autonome ou via du code de contrôle, que le travail est terminé. Un bot de questions-réponses à un seul échange a peu ou pas de boucle à concevoir.

    Quel niveau devez-vous apprendre en premier ?

    Commencez par l’ingénierie des prompts et du contexte, puis passez au « harness » et aux boucles. Il vous faut d’abord distinguer une instruction incorrecte d’un état manquant avant de pouvoir déboguer le temps d’exécution et le code de contrôle associés.

    Un bug peut-il concerner plusieurs niveaux ?

    Oui, et ce sont souvent les plus difficiles. Un bug de contexte peut cacher un signal de progression à la boucle, ce qui donne alors l’impression d’un bug de boucle. Suivez la cause du dysfonctionnement à travers les différentes couches plutôt que de corriger le premier symptôme visible.

    Points clés

    • Ces quatre termes décrivent des mécanismes de contrôle, et non des tendances concurrentes : l’instruction, l’état prêt pour le modèle, l’exécution et la récupération, ainsi que la progression répétée avec une règle d’arrêt.
    • Commencez toute enquête par l’historique des événements, et non par la requête : demandez ce que le modèle a vu, ce que le système d’exécution a fait, ce qui a changé entre les itérations, et pourquoi le mécanisme de contrôle a choisi de continuer.
    • Des appels à outils réussis qui se répètent avec des arguments presque identiques indiquent un problème lié à la boucle ; des échecs répétés avec des tentatives automatiques indiquent un problème lié au système de gestion.
    • Donnez aux boucles une définition explicite de ce qu’est un blocage, de préférence en fonction de la signature du dysfonctionnement, ainsi qu’une procédure d’escalade.
  • Conservez les contraintes durables en dehors de l’historique compressible afin que la compactation ne puisse pas les effacer.
  • Lectures complémentaires