Accueil / Articles

Lorsque le tableau de bord affiche un état vert mais que l’agent se trompe : le traçage de l’état

Le tableau de bord est vert et l’agent a tort : les échecs se cachent dans l’état transmis entre les étapes fonctionnelles. Quels enregistrements de suivi, d’acheminement et d’évaluation doivent être capturés.

Éditeur : REACTAPP.TOP12 min de lecture2749 mots

Sources: When the Dashboard Is Green and the Agent Is Wrong: Tracing Multi-Step Failures Past the LLM Call

Un tableau de bord vert et une réponse erronée

Le débogage des agents IA présente une particularité agaçante : l’écran de surveillance peut affirmer que tout fonctionne correctement. L’appel au modèle a abouti, les outils ont terminé leur travail, les API ont répondu avec des codes 200, la latence semble normale et l’utilisation des tokens correspond à ce à quoi on s’attend. Du point de vue de l’infrastructure, rien ne se passe, et pourtant le résultat final peut être complètement faux.

Ce n’est pas le type d’erreur évident, où un modèle invente quelque chose d’absurde. Ces échecs sont plus faciles à gérer, car au moins on sait par où commencer. Le cas le plus difficile est celui où chaque étape semble raisonnable, rien ne plante techniquement, et la réponse est suffisamment crédible pour que quelqu’un puisse agir en fonction.

Le problème s’aggrave à mesure que les systèmes évoluent, passant de simples appels à des modèles de langage à des agents et des workflows à plusieurs étapes. Avant qu’une réponse n’apparaisse, les informations qui la sous-tendent ont pu traverser plusieurs modèles, outils, API, transformations et routeurs, de sorte que le modèle final pourrait effectuer un travail parfait sur des données déjà corrompues cinq étapes auparavant. Ce aspect de l’observabilité des agents nécessite beaucoup plus d’attention qu’il n’en reçoit actuellement.

Un changement de schéma que personne ne remarque

Considérons une tâche courante liée au suivi de la satisfaction client. L’agent est chargé de trouver les clients dont la renouvellement a lieu dans les 30 jours, de marquer les comptes susceptibles de quitter le service, et de rédiger un rapport pour l’équipe chargée du suivi. Au cours de cette tâche, il peut interroger un CRM, calculer un score de risque, récupérer des discussions de support récentes, vérifier l’utilisation du produit, et enfin faire écrire le rapport par un modèle de langage.

Supposons maintenant que le CRM modifie l’un de ses schémas de réponse. Hier, le contenu transmis ressemblait à ceci.

{
  "health_score": 42
}

Aujourd'hui, c'est ainsi qu'il apparaît.

{
  "health": {
    "score": 42
  }
}

L’API est toujours active, la requête aboutit toujours et le JSON se parse toujours correctement. Selon le code d’intégration, il n’est pas nécessaire de lancer d’exception nulle part. Les problèmes apparaissent plus tard, lorsque la couche de normalisation continue de chercher health_score et que l’étape suivante reçoit la valeur null.

Peut-être que le système d’évaluation des risques interprète une valeur manquante comme neutre, ou peut-être que les instructions prévoient d’utiliser ce qui est disponible. Dans les deux cas, le flux de travail se poursuit et se termine par un rapport crédible qui omet un compte dont l’équipe aurait besoin de connaître l’existence.

En se concentrant uniquement sur le résultat final, on a tendance à blâmer facilement le modèle, ce qui pousse les gens à réécrire leurs instructions, à changer de modèle ou à ajuster la température, sans s’attaquer à la véritable cause. Une meilleure question consisterait à savoir à quel moment l’état est devenu incorrect, et avec cette question, le débogage d’un agent se présente de manière très différente.

Les événements de succès ne prouvent pas une compréhension

Un essai récent sur le fait que le web devient une API pour des agents décrit le passage du logiciel de simple rapport d’informations à un outil agissant au nom de l’utilisateur. Selon cet essai, exposer des outils à un modèle n’est qu’une partie du processus, car l’intention, les permissions, les contrôles en temps de exécution et la traçabilité deviennent essentiels lorsque les agents entreprennent des actions réelles.

Il en va de même pour le débogage de ces actions. Noter qu’un outil a été exécuté est utile, mais cela ne révèle pas si le reste du flux de travail a compris ce que cet outil a produit. Imaginez un journal d’activité contenant de telles informations.

crm.search_accounts
status: success
duration: 184ms
records: 47

On apprend que le CRM a renvoyé 47 enregistrements. Ce qui reste inconnu, c’est si ces 47 enregistrements sont bien parvenus intacts à l’étape suivante. Il se peut qu’il y ait eu six autres pages et que la pagination se soit arrêtée après la première. Il se peut aussi qu’une valeur ait été convertie de dollars en centimes, ou qu’une date et heure UTC ait été interprétée plus tard comme heure locale. Il se peut encore qu’une valeur de type enum ait vu son orthographe changer de « cancelled » en « canceled », ou qu’une API ait commencé à signaler des erreurs au niveau de l’application au sein d’une réponse dont le statut HTTP semblait correct.

Tout cela relève de simples bugs logiciels. Avec les agents, la particularité est que le modèle suivant continue généralement son fonctionnement, en prenant en compte des données qui semblent crédibles et en les analysant. Par conséquent, un modèle plus performant ne résoudra pas nécessairement le problème. Si les données d’entrée sont erronées dès leur arrivée, le modèle se contente de résoudre le mauvais problème avec plus de compétence.

Aux points critiques, vous devez pouvoir examiner l’entrée, la sortie, la transformation appliquée à la réponse ainsi que ce que le pas suivant a réellement obtenu. Il n’est pas nécessaire de conserver à jamais chaque donnée brute ; il suffit d’en garder suffisamment pour reconstituer l’exécution en cas d’échec.

Suivi d’un concurrent manquant

Les outils s’améliorent constamment. Les conventions sémantiques GenAI d’OpenTelemetry commencent à standardiser la manière dont les appels aux modèles et l’exécution des outils sont décrits, et des frameworks tels que l’OpenAI Agents SDK permettent de tracer les générations, les appels aux outils, les transferts de données et les contraintes. Il s’agit là de matériaux bruts utiles, mais il reste difficile de rendre ces traces exploitables lorsque le flux de travail s’est terminé et que l’échec réel est caché dans l’état transmis entre deux étapes fonctionnelles.

Considérez une exécution simplifiée comme celle illustrée.

Supposons que le rapport final manque d’un concurrent qui devrait y figurer clairement. L’ancienne approche consistait à ouvrir la commande finale et à examiner la réponse du modèle. Peut-être que les instructions n’étaient pas suffisamment précises, ou que le modèle avait ignoré une partie du contexte, ou encore qu’un autre modèle aurait donné de meilleurs résultats. Partir de là n’est plus la bonne stratégie.

Travaillez plutôt à rebours. Le modèle final a-t-il obtenu le concurrent manquant ? S’il ne l’a pas eu, c’est peut-être à cause de l’étape de classement ? S’il a disparu avant le classement, était-il présent après l’extraction ? Être présent après l’extraction mais absent après la normalisation signifie que l’échec se situe précisément à une étape donnée.

{
  "company": "Example Corp",
  "website": {
    "url": "https://example.com"
  }
}

alors que l’étape de normalisation s’y attendait.

{
  "company": "Example Corp",
  "website": "https://example.com"
}

Rien dans cette situation n’était dramatique. À mi-parcours, un objet a changé de forme et une étape l’a mal géré, mais la plupart des opérations environnantes semblaient encore fonctionner normalement. De tels bugs méritent d’être traqués, car sans cela, la responsabilité retombe sur le composant le plus visible, quel que soit ce qui s’est passé précédemment.

La leçon pratique n’est pas qu’un produit d’observabilité spécifique soit nécessaire. Elle est plutôt que le suivi des événements doit vous permettre de suivre l’état au fil du flux de travail, et ne se limiter pas à lister quels composants ont été exécutés. Il y a une grande différence entre savoir que l’étape 4 a été exécutée et savoir ce que l’étape 5 en a reçu.

Le décalage de plan semble judicieux

Lorsqu’on identifie une défaillance liée aux contraintes du outil, celle-ci est assez évidente. Le dérive de plan est plus complexe, car un agent peut quitter la tâche initiale en suivant des étapes qui semblent toutes logiques. Imaginez qu’un agent soit chargé de rechercher cinq fournisseurs, d’évaluer leurs prix et leur fiabilité, puis de rédiger une recommandation, avec pour instruction de ne pas les contacter.

L’agent trouve les fournisseurs et commence à collecter des données. Deux d’entre eux ne indiquent pas de prix, alors il cherche une autre solution. Finalement, il découvre un outil d’envoi d’e-mails disponible. Sa logique n’est pas absurde : des prix sont nécessaires, ces derniers ne sont pas publics, et un message adressé au fournisseur permettrait de résoudre le problème. Cependant, cela enfreint également l’une des règles les plus importantes de la tâche.

Lorsque la règle n’est qu’une phrase située en haut d’une fenêtre de contexte en expansion, tout dépend du fait que le modèle continue de la considérer comme importante après l’ajout de milliers de tokens provenant des résultats de recherche, des sorties des outils et des états intermédiaires. Les contraintes ayant des conséquences réelles méritent une formulation explicite.

{
  "objective": "Compare suppliers and prepare a recommendation",
  "constraints": [
    "Do not contact suppliers"
  ],
  "completed_steps": [
    "discover_suppliers",
    "collect_public_pricing"
  ],
  "next_action": "request_missing_prices",
  "requested_tool": "send_email"
}

Désormais, l’application dispose de quelque chose à vérifier avant qu’une action ne soit exécutée. Elle peut refuser la demande d’outil, exiger l’approbation humaine ou envoyer l’agent chercher une autre solution. La réponse appropriée dépend du flux de travail, mais l’essentiel est que la contrainte ne réside plus entièrement dans la formulation de l’instruction.

Des règles telles qu’un plafond de dépenses, « rédiger mais ne pas envoyer » ou « ne jamais toucher à la version en production » fonctionnent de la même manière. Un langage simple est utile pour exprimer l’intention de l’utilisateur, mais les permissions et limites importantes doivent également se traduire par des contrôles en temps réel.

Le logiciel gère cela partout ailleurs. Personne ne écrirait « veuillez empêcher les utilisateurs non autorisés de supprimer la base de données » dans un commentaire en prétendant s’agir d’un contrôle d’accès, et les agents ne méritent pas d’exception simplement parce que leurs instructions sont en anglais.

Le routage des modèles crée une limite

Le routage pose un problème similaire. Choisir un modèle cesse d’être une simple valeur de configuration dès lors qu’il faut équilibrer qualité, coût, latence, utilisation des outils et capacités différentes des modèles au sein d’un système de production, et la décision de routage devient alors partie intégrante du suivi nécessaire pour le débogage.

Disons que l’Étape 6 s’exécute généralement sur le Modèle A. Lors d’une exécution en direct, le fournisseur est soumis à une limitation de débit, et le routeur passe au Modèle B. C’est là le mécanisme de secours qui fonctionne comme prévu, car le flux de travail continue de fonctionner sans échouer. Cependant, le Modèle B formate légèrement différemment les arguments structurés destinés à l’outil suivant. Ces arguments restent valides et l’outil fonctionne correctement, mais un champ est lu d’une manière qui modifie le résultat final.

Si les rapports d’observabilité ne mentionnent que le modèle configuré pour le flux de travail, quelqu’un pourrait passer des heures à essayer de reproduire l’échec sur le modèle A, alors que c’est le modèle B qui a traité la requête défaillante. Par conséquent, un trace doit enregistrer le modèle demandé, celui qui a répondu, tout mécanisme de fallback, la politique de routage en vigueur, ainsi que le fait que l’appel s’agisse d’une tentative de réessai. Ce ne sont pas des informations passionnantes, mais la plupart des outils utiles pour le débogage en production ne le sont pas non plus. Au-delà des démonstrations, une grande partie du travail consiste à découvrir quel détail peu intéressant a changé sans être remarqué.

État du trace, et pas seulement les événements

Les outils d’agent font désormais un excellent travail pour afficher la structure d’une exécution, en présentant les appels de modèles, les outils utilisés, les transferts de données, les tentatives de réessai et d’autres événements dans des vues de suivi de plus en plus pratiques. L’erreur consisterait à penser que l’enregistrement de davantage d’événements garantit automatiquement une bonne capacité d’observation. Une exécution comprenant dix segments parfaitement instrumentés ne vous sera d’aucune aide si vous ne pouvez pas déterminer quel état a changé entre eux.

Une courte liste de questions aide à analyser une exécution défaillante. Que voulait initialement l’utilisateur ? Quelles contraintes étaient en vigueur ? Quel plan le système a-t-il suivi ? Qu’a renvoyé chaque outil et qu’a reçu l’étape suivante ? Quel modèle a pris chaque décision ? Y a-t-il eu des changements dans le monde extérieur ? À quel moment les résultats ont-ils cessé de correspondre aux attentes ?

Répondre à ces questions ne nécessite pas l’ensemble des données, et enregistrer tout le contenu soulève ses propres problèmes. Les requêtes, les arguments des outils et leurs réponses peuvent contenir des données privées des clients, des identifiants ou d’autres informations sensibles qui ne devraient pas être transférées automatiquement sur une plateforme d’observabilité. Les directives de GenAI d’OpenTelemetry soulignent ce point, et sa spécification détaillée des intervalles de mesure rend l’enregistrement des entrées et des sorties des modèles facultatif et non par défaut.

L’objectif est donc de permettre la reconstitution des parties pertinentes d’une exécution, et non d’en enregistrer l’intégralité. Parfois, une réponse modifiée suffit, parfois il suffit de la version du schéma ainsi que d’un ID d’objet, et parfois un résultat intermédiaire nécessite un instantané, car rien d’autre ne peut reproduire l’exécution. Prenez une décision en connaissance de cause, afin qu’un incident ne révèle pas que status: success est la seule information que vous avez conservée.

Conséquences pour l’évaluation

Une trace explique ce qui s’est passé, mais pas si le résultat était bon, ce qui rend l’évaluation nécessaire. Anthropic avance le même argument dans son article sur les évaluations d’agents. Il est plus difficile de noter les agents que des réponses isolées, car ils s’étendent sur plusieurs échanges, utilisent des outils, modifient l’état et s’adaptent à ce qui a précédé.

Certains résultats peuvent être vérifiés sans modèle supplémentaire. Un agent à qui il a été demandé de ne pas envoyer d’e-mail qui en envoie un a échoué, et une tâche d’extraction conçue pour renvoyer 27 enregistrements qui n’en renvoie que 11 présente une déviation mesurable. D’autres cas sont plus flous : un rapport de recherche était-il suffisamment complet ? Les sources étaient-elles fiables ? Une réponse de support a-t-elle résolu le problème du client ? Pour ce type de cas, une révision humaine, des retours utilisateurs, des ensembles de données ou des outils d’évaluation basés sur des modèles peuvent être nécessaires.

La véritable valeur réside dans la combinaison de l’évaluation et du suivi des étapes. Un avis négatif à côté d’une réponse finale enregistrée indique simplement que l’utilisateur ne l’a pas appréciée. Lié à l’ensemble du processus, ce même signal permet d’examiner le matériel récupéré, les outils utilisés, les modèles impliqués ainsi que le point où l’état a changé.

Lorsque la véritable cause de défaillance est identifiée, cette exécution conserve sa valeur même après l’incident, car elle peut servir de cas d’évaluation pour éviter que cela ne se reproduise suite à des modifications futures des prompts, des modèles ou des workflows. C’est bien mieux que de corriger les mauvaises réponses une par une en espérant que rien d’autre ne tombera en panne.

Cessez de partir du prompt final

Le changement le plus important dans le débogage des systèmes d’IA est probablement celui-ci. Dans une application LLM simple qui fournit une mauvaise réponse, il est raisonnable de lire la demande et la réponse, car il y a peu d’autres endroits où un problème pourrait se cacher. À mesure que les systèmes se complexifient, cette habitude devient moins utile. Imaginez un pipeline comprenant plusieurs modèles, des outils de récupération et de recherche, des API externes, des routeurs et un cycle de vérification : la dernière demande pourrait simplement être le lieu où une erreur antérieure est finalement apparue.

RAG a déjà donné sa leçon. Lorsque le système de récupération insère le mauvais document dans la fenêtre de contexte, un modèle de génération plus complexe ne pourra pas le corriger, et il faudra remonter à la source pour rectifier la récupération des données. Les agents suivent la même logique, mais avec des contraintes supplémentaires. La récupération est-elle correcte ? Examinez le résultat obtenu. Cela aussi est correct ? Regardez la décision suivante. Le bon outil a-t-il été choisi ? Analysez les arguments et la sortie. L’état est-il toujours correct ? Continuez jusqu’à ce que vous rencontriez le premier point où les choses s’écartent de ce à quoi vous vous attendiez.

Cela semble simple sur le papier, pourtant les gens l’oublient car c’est la réponse finale qui se trouve devant eux, et c’est généralement la chose la plus facile à blâmer.

Observabilité pour l’ensemble du processus

Les agents deviendront de plus en plus complexes. MCP leur met à disposition davantage d’outils, les architectures multi-agents introduisent des mécanismes de délégation et de transfert de tâches, les routeurs choisissent des modèles en temps réel, et les workflows de longue durée permettent un état persistant, ainsi que des tentatives de réexécution et des reprises. L’approbation humaine peut intervenir au milieu d’une exécution, et les agents fonctionnant via navigateur ou ordinateur peuvent modifier des systèmes bien au-delà du cadre d’une simple conversation. Chacun de ces éléments rend les agents plus capables, mais augmente également les risques d’erreurs, alors que chaque composant indique un succès.

C’est pourquoi l’observabilité doit aller au-delà des métriques liées aux LLM. La latence, le nombre de tokens, les erreurs et les coûts sont importants, et un tableau de bord doit certainement alerter lorsque un agent entre en boucle et consomme inutilement des crédits API à 2 heures du matin. Cependant, ces chiffres indiquent principalement si le système fonctionne. Un agent à plusieurs étapes a également besoin d’un moyen de s’assurer que ce qui le traverse continue de correspondre à la tâche de l’utilisateur.

En pratique, cela signifie retracer l’intention initiale, les contraintes clés, les outils et modèles qui ont réellement été utilisés, l’état transmis d’une étape à l’autre ainsi que le résultat final. En cas de résultat incorrect, il faut pouvoir remonter jusqu’au premier moment où l’état a dévié de la réalité. Grâce à cette capacité, un échec devient un problème d’ingénierie ordinaire que l’on peut examiner, reproduire et tester. Sans elle, on se contente de regarder la réponse finale en devinant quel élément du système a échoué plus tôt.