Ingénierie des prompts ou contexte, outils, boucles ? Débogage des agents IA par niveau.
L’ingénierie des prompts, l’ingénierie du contexte, l’ingénierie des outils et l’ingénierie des boucles échouent chacune à sa manière. Une routine axée sur le suivi permet de déterminer le niveau qui a défailli.
Lorsqu’un agent IA se comporte mal en production, les équipes ont tendance à se disputer sur le vocabulaire plutôt que sur les preuves : un ingénieur souhaite un meilleur prompt, un autre accuse le contexte, un troisième pointe du doigt l’outil de gestion. L’ingénierie des prompts, du contexte, de l’outil de gestion 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 d’agent de codage, puis vous propose une procédure basée sur le suivi des traces pour déterminer quelle couche a réellement défailli avant de modifier le moindre code.
Quatre couches d’un agent IA en bref
- 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.
- Ingénierie des harness : création de l’environnement dans lequel le modèle fonctionne — 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’un de ces éléments au mauvais endroit.
Lorsque la démonstration fonctionne mais pas en production
Le schéma est familier. Un agent semble parfait lors d’une démonstration. Quelques jours après son lancement, il commence à entrer en boucle, à consommer des tokens inutilement, oublie des informations qui lui ont é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 groupes. Quelqu’un propose de réécrire l’instruction, un autre parle d’un problème de contexte, et une troisième personne soupçonne le système de fixation. 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 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
Une façon concise 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 ?
- Contrôle : le temps de exécution peut-il mettre en œuvre ce que le modèle a demandé, de manière sûre et fiable ?
- Trajectoire : 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 claires pour que l’on s’en souvienne réellement lorsqu’il y a un problème urgent.
Comment ces couches sont apparues, et pourquoi l’ordre compte
Ces termes sont apparus plus ou moins dans cet ordre, au fur et à mesure que les outils acquéraient de nouvelles capacités :
- Ingénierie des prompts (environ de 2022 à 2024) a été la première compétence : formulation des demandes, exemples, contraintes et schémas à quelques exemples visant une seule invocation du modèle.
- Ingénierie du contexte (environ 2024 à 2025) est devenue centrale lorsque les agents ont dû gérer en même temps des documents récupérés, un historique de conversation et des définitions d’outils. La question a évolué de la manière de formuler une demande vers ce que le modèle voit réellement. Anthropic, LangChain et Chroma ont contribué à populariser cette approche auprès des professionnels, et les commentaires d’Andrej Karpathy l’ont intégrée dans des discussions plus larges en ingénierie.
- Ingénierie de l’exploitation (début 2026) a pris de l’importance lorsque les agents ont obtenu un accès au système de fichiers, des commandes de shell et la capacité de fonctionner pendant des 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 fait de cela une préoccupation majeure pour les agents de programmation ; son document sur l’ingénierie d’exploitation avec Codex constitue une référence utile.
- 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 une explication sur l’ingénierie des boucles si vous souhaitez une autre approche.
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. L’observation importante 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
Le génie 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 de revue 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": []}.
Cette instruction définit un contrat local. Elle attribue un rôle, décrit la transformation (différences à appliquer, liste des problèmes à résoudre), précise la structure du résultat 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 narratif ou un champ manquant.
On affirme souvent que l’ingénierie des instructions est obsolète. Ce n’est pas le cas ; elle constitue la couche la plus intime du processus. Chaque pipeline de contexte finit par transmettre un ordre au modèle, et une instruction faible, même intégré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 rigoureuse dans des limites budgétaires
L’ingénierie du contexte consiste à choisir, pour chaque requête, quels documents, quel historique, quelles définitions d’outils et quelles mémoires seront affichés dans la fenêtre, et de manière tout aussi délibérée, quels éléments en seront exclus. Lorsqu’elle est négligée, le modèle répond à partir d’informations obsolètes, est dévié par des extraits irrelevants, ou perd son focus parce que la fenêtre est remplie de matériel ajouté par précaution.
Un générateur de contexte pour un agent de codage peut récupérer des candidats, les réclasser et compresser l’historique :
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,
}
Considérez-le comme un entonnoir. La récupération de données lance un large filet comprenant huit candidats, le réclassement 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 la quantité d’informations.
C’est pourquoi la méprise la plus courante, selon laquelle l’ingénierie du contexte signifie fournir au modèle plus d’informations, est généralement fausse. Un contexte plus volumineux tend à contenir davantage de bruit : des instructions obsolètes, des faits répétés et des é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 de contexte, qui couvre l’étape de récupération. Un pipeline RAG peut extraire huit fragments et les réclasser en trois, comme indiqué ci-dessus. L’ingénierie de contexte comprend également la compression de l’historique, le formatage des définitions d’outils, le maintien de l’état des tâches critiques, 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 sans aucun stockage vectoriel doit résoudre un véritable problème de contexte. L’état de Git, les fichiers ouverts, les erreurs de compilateur, les résultats des tests, le plan actuel et 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 activités, ainsi que tout ce qui se produit en cas d’échec. Sans un bon harnais, on obtient un agent qui sait raisonner correctement mais ne peut pas agir en conséquence, ou un agent qui agit mais ne dispose d’aucun moyen fiable pour se remettre en état en cas d’erreur lors d’une appel d’outil.
Un enveloppeur d’appel d’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)
Le wrapper ne tente pas de résoudre la tâche. Il définit la frontière 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 état. Une erreur déclenche une tentative de réessai limitée avec des arguments corrigés, et une fois les tentatives épuisées, il renvoie une erreur structurée marquée comme irréparable, 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’équivaloir le harness au framework d’agent que vous avez installé. Un framework fournit une structure de base ; le harness correspond à l’ensemble des décisions concrètes que vous prenez à partir de celle-ci : ce qui est enregistré, ce que fait une appel échoué ensuite, quel état survit à une panne, quels commandes sont autorisées, et comment les résultats de l’exécution sont présentés au modèle.
Ingénierie des boucles : le contrat de terminaison
L’ingénierie des boucles définit le travail de chaque itération, la manière dont l’agent évalue s’il progresse, et, ce qui est le plus important, les conditions de cessation. Son échec typique est la boucle infinie : un agent qui continue d’appeler des outils et d’utiliser des tokens parce que rien ne lui indique jamais qu’il a terminé ou qu’il est bloqué.
Un contrôleur minimal ressemble à ceci :
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"
Plusieurs limites sont appliquées ici. max_iters fixe un plafond au travail total, is_goal_met permet de sortir en cas de réussite, et un compteur d’immobilisme suit les itérations consécutives sans progression, se réinitialisant dès que la progression reprend. Après stall_limit étapes d’immobilisme, 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 signaux de progression mesurables, un nombre limité de tentatives, des budgets pour le temps et les tokens, une étape de vérification, ainsi qu’une politique définie pour gérer les cas d’immobilisme de la progression. Pour des implémentations en TypeScript de ces mêmes concepts, consultez les boucles agentes bornées pour l’utilisation d’outils LLM.
La conception des boucles et celle des systèmes de gestion sont souvent confondues. Le système de gestion définit ce que l’agent peut toucher et la manière dont 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
- Instruction (P) : correspond à l’instruction donnée. Défaillance typique : le modèle interprète mal l’intention ou renvoie un format incorrect. Première chose à vérifier : la sortie elle-même.
- Contexte (A) : correspond à l’état prêt à être utilisé par le modèle. Défaillance typique : le modèle agit sur des informations obsolètes, manquantes ou perturbatrices. Première chose à vérifier : les captures de contexte à chaque étape.
- Système de gestion (C) : gère l’exécution et la récupération. Défaillance typique : les appels aux outils échouent, des tentatives de réessai sont effectuées de manière aveugle 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.
Distinguer une erreur de harness d’une erreur de boucle
La constatation la plus utile pour gagner du temps est que deux erreurs différentes peuvent sembler identiques de l’extérieur. Un agent bloqué dans une boucle à cause d’un contrôleur défectueux et un agent bloqué en raison d’un traitement de outil défaillant présentent tous deux le même symptôme : il continue de fonctionner, les coûts augmentent sans cesse, et personne ne sait pourquoi. Une courte liste de contrôle 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 des arguments presque inchangés, indiquent une boucle.
2. Rechercher des échecs répétés des outils
Si un outil échoue encore et encore et que l’agent réessaie sans changer sa méthode, suspectez le harness.
3. Vérifiez ce que le modèle peut voir
Si le modèle semble oublier un fait au cours d’une exécution, examinez la construction du contexte : troncature, remplacement, compression ou 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, examinez le prompt.
Une règle générale
Les bugs de boucle se situent dans la décision concernant ce qui se passe ensuite. Les bugs du harness se situent dans ce qui se passe lorsque quelque chose échoue. Les bugs de contexte se situent dans ce que le modèle peut voir. Les bugs du prompt se situent dans ce que vous avez demandé.
Répondez à la question qui s’applique parmi les quatre avant de modifier quoi que ce soit.
Étude de cas : un examinateur de demande de fusion qui ne s’arrêtait 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 une facture inattendue.
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, et seuls les fichiers importants 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 de tenter de résoudre cet échec en apportant des modifications de code non pertinentes et en relançant les tests, puisque rien ne lui indique qu’il a effectué suffisamment d’essais pour ce sous-objectif et qu’il devrait s’arrêter et faire monter l’incident en grade.
Il ne s’agit ni d’un problème de prompt, ni d’un problème de contexte, ni d’un problème lié au 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 parvenir à cette conclusion.
Étape 1 : vérifier que les outils fonctionnent
Les exécutions réussies mentionnées dans le journal éliminent les échecs les plus simples liés au framework, tels 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 est correctement ciblée, 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 la logique du contrôleur qui compare une signature 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 de stagnation, le contrôleur envoie une raison d’escalade et s’arrête. Tout changement réel réinitialise le compteur.
On peut aller plus loin en imposant une limite 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, au début d’une migration, s’assure que rien ne peut endommager les clients existants. Quarante tours plus tard, la conversation est compressée et la 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 l’ensemble 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 environnement 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’instruction à suivre.
- Conscience : construire l’état sur lequel le modèle fera des raisonnements.
- Contrôle : rendre l’exécution observable, encadrée et récupérable.
- Trajectoire : transformer la répétition en progrès mesurable, aboutissant à une fin vérifiable.
Ensuite, 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 de faits sur lesquels il compte a besoin d’un contexte complémentaire. Des décisions judicieuses qui ne se traduisent pas en actions fiables exigent des améliorations structurelles. Des actions qui réussissent alors que l’exécution globale ne converge jamais nécessitent des ajustements itératifs.
Questions fréquentes sur les couches d’agents
L’ingénierie des outils d’assistance n’est-elle qu’un autre nom pour un framework d’agents ?
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, le journalisation, les permissions, ainsi que la manière dont les résultats reviennent au 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, par lui-même 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 seul bug peut-il concerner plusieurs niveaux ?
Oui, et ce sont souvent les cas 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 l’échec à travers les différentes couches plutôt que de corriger le premier symptôme visible.
Une liste de contrôle pour le prochain incident avec un agent
- 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 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.