Pourquoi de nombreux systèmes agentiques échouent en production et comment concevoir des agents fiables avec des machines d'état, des contrats d'outils clairs, des stratégies de retry et une observabilité profonde.

Les systèmes agentiques sont des applications où un LLM ne se contente pas de répondre à une requête, mais décide de la suite : quels outils appeler, quelles données récupérer, quelles étapes exécuter et quand il a « fini ». Ils combinent un modèle, un ensemble d'outils (APIs, bases de données, services), une boucle de planification/exécution et une infrastructure qui relie le tout.
En démo, cela paraît magique : un agent élabore un plan, appelle quelques outils et renvoie un résultat parfait. Le chemin heureux est court, la latence faible et rien ne tombe en panne en même temps.
En charge réelle, le même agent est soumis à des stress que la démo n'a jamais vus :
Le résultat : un comportement instable difficile à reproduire, une corruption silencieuse des données et des parcours utilisateurs qui se bloquent ou tournent en boucle occasionnellement.
Les agents instables ne nuisent pas seulement à la « satisfaction ». Ils :
Cet article porte sur des patrons d'ingénierie, pas sur des « meilleurs prompts ». Nous verrons les machines d'état, les contrats d'outils explicites, les stratégies de retry et de gestion des erreurs, le contrôle de la mémoire et de la concurrence, et les schémas d'observabilité qui rendent les systèmes agentiques prédictibles sous charge — pas seulement impressionnants sur scène.
La plupart des systèmes d'agents semblent corrects dans une démo au chemin heureux. Ils échouent quand le trafic, les outils et les cas limites arrivent ensemble.
Une orchestration naïve suppose que le modèle fera « la bonne chose » en un ou deux appels. En usage réel, on observe des motifs récurrents :
Sans états explicites et conditions de fin, ces comportements sont inévitables.
La sample‑generation du LLM, la variabilité de latence et le timing des outils créent un non‑déterminisme caché. Une même entrée peut parcourir des branches différentes, appeler des outils différents ou interpréter différemment les résultats d'un outil.
À l'échelle, les problèmes d'outils dominent :
Chacun de ces éléments se transforme en boucles parasites, retries ou réponses finales incorrectes.
Ce qui casse rarement à 10 RPS casse constamment à 1 000 RPS. La concurrence révèle :
Les équipes produit attendent souvent des workflows déterministes, des SLA clairs et de l'auditabilité. Les agents, laissés sans contraintes, offrent un comportement probabiliste, « best‑effort », avec des garanties faibles.
Quand les architectures ignorent ce décalage — en traitant les agents comme des services traditionnels plutôt que comme des planificateurs stochastiques — les systèmes deviennent imprévisibles justement quand la fiabilité compte le plus.
Les agents prêts pour la production relèvent moins des « prompts brillants » que d'une conception système disciplinée. Une manière utile de les considérer est comme de petites machines prévisibles qui appellent parfois un LLM, et non comme des blobs mystérieux de LLM qui touchent occasionnellement vos systèmes.
Quatre propriétés importent le plus :
Ces propriétés ne viennent pas des seuls prompts. Elles viennent de la structure.
Le motif par défaut que beaucoup d'équipes adoptent est : « while not done, call the model, let it think, maybe call a tool, repeat ». C'est facile à prototyper et difficile à exploiter.
Un schéma plus sûr consiste à représenter l'agent comme un workflow explicite :
COLLECTING_INPUT, PLANNING, EXECUTING_STEP, WAITING_ON_HUMAN, DONE).Cela transforme l'agent en une machine d'état où chaque étape est inspectable, testable et rejouable. Les boucles libres paraissent flexibles, mais les workflows explicites sont ce qui rend les incidents débogables et les comportements auditable.
Les agents monolithiques qui « font tout » sont séduisants, mais ils créent un couplage fort entre responsabilités non liées : planification, récupération, logique métier, orchestration UI, etc.
Composez plutôt des agents ou skills petits et bien définis :
Chaque skill peut avoir sa propre machine d'état, ses outils et ses règles de safety. La logique de composition devient alors un workflow de plus haut niveau, et non un prompt sans cesse croissant dans un seul agent.
Cette modularité maintient chaque agent suffisamment simple pour être raisonnable et permet d'évoluer une capacité sans déstabiliser le reste.
Un modèle mental utile est de diviser un agent en trois couches :
Politique de décision (prompts + modèle)
Encapsule comment l'agent choisit les actions suivantes, interprétée sous des contraintes strictes. Vous devriez pouvoir remplacer le modèle, ajuster la température ou affiner les prompts sans toucher au câblage système.
Machine d'état / moteur de workflow
Possède où vous en êtes dans le processus, quelles transitions sont possibles et comment persister la progression. La politique propose un mouvement ; la machine d'état le valide et l'applique.
Couche d'outillage
Implémente ce qui peut réellement se produire dans le monde : APIs, bases, queues, services externes. Les outils exposent des contrats étroits et typés et appliquent autorisation, limites de débit et validation d'entrée.
En forçant cette séparation, vous évitez le piège d'enterrer la logique métier dans des prompts ou des descriptions d'outils. Le LLM devient un composant de décision à l'intérieur d'une coquille déterministe claire, pas la coquille elle‑même.
Les systèmes agentiques les plus fiables ne sont pas les démos les plus impressionnantes — ce sont ceux dont le comportement est explicable sur un tableau blanc.
Concrètement :
Cette préférence pour des agents petits, composables et bien structurés permet à la portée du système de croître sans s'effondrer sous sa propre complexité.
La plupart des implémentations d'agents commencent comme une boucle "penser, agir, observer" centrée sur un appel LLM. C'est acceptable pour des démos, mais cela devient rapidement opaque et fragile. Une meilleure approche consiste à traiter l'agent comme une machine d'état explicite : un ensemble fini d'états, avec des transitions bien définies déclenchées par des événements.
Au lieu de laisser le modèle décider implicitement de la suite, définissez un petit diagramme d'états :
Les transitions entre ces états sont déclenchées par des événements typés tels que UserRequestReceived, ToolCallSucceeded, ToolValidationFailed, TimeoutExceeded ou HumanOverride. Chaque événement, plus l'état courant, détermine l'état et les actions suivants.
Cela rend les retries et timeouts simples à gérer : vous attachez des politiques aux états individuels (par ex. CALL_TOOL peut retenter 3 fois avec backoff exponentiel, PLAN peut ne pas être retenté) au lieu de disperser la logique de retry dans tout le code.
Persistez l'état courant et le contexte minimal dans un store externe (base de données, queue ou moteur de workflow). L'agent devient alors une fonction pure :
next_state, actions = transition(current_state, event, context)
Ceci permet :
Avec une machine d'état, chaque étape du comportement de l'agent est explicite : quel état, quel événement, quelle transition et quels effets de bord ont été produits. Cette clarté accélère le débogage, simplifie les enquêtes d'incident et crée une piste d'audit naturelle pour les revues de conformité. Vous pouvez prouver, via les logs et l'historique d'état, que certaines actions risquées ne sont prises que depuis des états spécifiques et sous des conditions définies.
Les agents se comportent de manière beaucoup plus prévisible quand les outils ressemblent moins à des « APIs cachées dans de la prose » et plus à des interfaces bien conçues avec des garanties explicites.
Chaque outil doit définir un contrat couvrant :
InvalidInput, NotFound, RateLimited, TransientFailure) avec une sémantique claire.Exposez ce contrat au modèle sous forme de documentation structurée, pas de mur de texte. Le planner de l'agent doit savoir quelles erreurs sont retentables, lesquelles requièrent une intervention humaine et lesquelles doivent arrêter le workflow.
Traitez les entrées/sorties d'outil comme n'importe quelle API de production :
Cela vous permet de simplifier les prompts : au lieu d'instructions verbeuses, reposez-vous sur une guidance pilotée par schéma. Des contraintes claires réduisent les arguments hallucinés et les séquences d'outils absurdes.
Les outils évoluent ; les agents ne doivent pas casser à chaque changement.
v1, v1.1, v2) et épinglez les agents sur une version.La logique de planification peut alors mélanger agents et outils à différents niveaux de maturité en toute sécurité.
Concevez les contrats en prévoyant la défaillance partielle :
L'agent peut alors s'adapter : poursuivre un workflow avec des fonctionnalités réduites, demander une confirmation utilisateur ou basculer vers un outil de secours.
Les contrats d'outil sont un lieu naturel pour encoder des limites de sécurité :
confirm: true).Combinez cela avec des vérifications côté serveur ; ne comptez jamais uniquement sur le modèle pour « bien se comporter ».
Quand les outils ont des contrats clairs, validés et versionnés, les prompts peuvent être plus courts, l'orchestration devient plus simple et le débogage est grandement facilité. Vous déplacez la complexité hors d'instructions en langage naturel vers des schémas et politiques déterministes, réduisant les appels d'outils hallucinés et les effets de bord inattendus.
Les systèmes agentiques fiables partent du principe que tout finira par échouer : modèles, outils, réseaux, même votre couche de coordination. L'objectif n'est pas d'éviter l'échec, mais de le rendre peu coûteux et sans danger.
L'idempotence signifie : répéter la même requête a le même effet visible en externe que l'exécuter une fois. C'est critique pour les agents LLM qui réémettent fréquemment des appels d'outils après des échecs partiels ou des réponses ambiguës.
Rendez les outils idempotents par conception :
request_id stable. L'outil stocke ceci et renvoie le même résultat s'il voit l'ID à nouveau.Utilisez des retries structurés pour les échecs transitoires (timeouts, limites de débit, 5xx) : backoff exponentiel, jitter pour éviter les thundering herds et un nombre maximal d'essais strict. Journalisez chaque tentative avec des IDs de corrélation pour tracer le comportement de l'agent.
Pour les échecs permanents (4xx, erreurs de validation, violations de règles métier), ne retryez pas. Remontez une erreur structurée à la politique de l'agent afin qu'elle replanifie, demande à l'utilisateur ou choisisse un autre outil.
Implémentez des circuit breakers au niveau agent et outil : après plusieurs échecs, bloquez temporairement les appels vers cet outil et échouez rapidement. Associez cela à des fallbacks bien définis : modes dégradés, données en cache ou outils alternatifs.
Évitez les retries aveugles depuis la boucle d'agent. Sans outils idempotents et classes d'erreurs claires, vous ne faites que multiplier effets de bord, latence et coûts.
Les agents fiables commencent par une réflexion claire sur ce qui est de l'état et où il vit.
Considérez un agent comme un service traitant une requête :
Mélanger ces deux types mène à confusion et bugs. Par exemple, mettre des résultats d'outils éphémères dans la « mémoire » pousse les agents à réutiliser du contexte obsolète dans des conversations futures.
Vous avez trois options principales :
Règle utile : le LLM est une fonction sans état sur un objet d'état explicite. Persistez cet objet en dehors du modèle et régénérez les prompts à partir de lui.
Un échec courant est d'utiliser les logs de conversation, traces ou prompts comme mémoire de fait.
Problèmes :
Définissez plutôt des schémas de mémoire structurés : user_profile, project, task_history, etc. Dérivez les logs à partir de l'état, pas le contraire.
Quand plusieurs outils ou agents mettent à jour les mêmes entités (p.ex. CRM, ticket, document), vous avez besoin de contrôles de cohérence :
Pour les opérations à forte valeur, enregistrez un journal de décisions distinct du log conversationnel : qu'est‑ce qui a changé, pourquoi et sur la base de quelles entrées.
Pour survivre aux crashs, déploiements et limitations de débit, les workflows doivent être résumables :
Cela permet aussi le debugging temporel : vous pouvez inspecter et rejouer l'état exact qui a conduit à une mauvaise décision.
La mémoire est autant un passif qu'un actif. Pour des agents en production :
Traitez la mémoire comme une surface produit : conçue, versionnée et gouvernée — pas comme un dépôt textuel sans fin attaché à votre agent.
Les agents paraissent séquentiels sur un tableau blanc mais se comportent comme des systèmes distribués en charge réelle. Dès que vous avez de nombreux utilisateurs, outils et jobs background, vous gérez des conditions de course, du travail dupliqué et des problèmes d'ordonnancement.
Modes de panne courants :
Vous atténuez cela avec des contrats d'outils idempotents, un état de workflow explicite et du locking optimiste ou pessimiste au niveau données.
Les flux synchrones request–response sont simples mais fragiles : chaque dépendance doit être up, dans les limites de débit et rapide. Quand les agents diffusent vers beaucoup d'outils ou de sous‑tâches parallèles, placez les étapes longues ou à effets de bord derrière une queue.
L'orchestration basée sur queues vous permet :
Les agents frappent typiquement trois classes de limites :
Vous avez besoin d'une couche de rate‑limiting explicite avec throttles par utilisateur, par tenant et globaux. Utilisez des token buckets ou des leaky buckets et exposez des types d'erreur clairs (p.ex. RATE_LIMIT_SOFT, RATE_LIMIT_HARD) pour que les agents puissent reculer gracieusement.
Le backpressure protège le système sous stress. Stratégies :
Surveillez les signaux de saturation : profondeur des queues, utilisation des workers, taux d'erreur model/tool et percentiles de latence. Une montée des queues combinée à une latence croissante ou des 429/503 est le signal précoce que les agents dépassent leur environnement.
On ne peut pas rendre un agent fiable si l'on ne peut répondre rapidement à deux questions : qu'a‑t‑il fait ? et pourquoi l'a‑t‑il fait ? L'observabilité pour les systèmes agentiques vise à rendre ces réponses bon marché et précises.
Concevez l'observabilité de sorte qu'une seule tâche ait une trace qui relie :
Dans cette trace, attachez des logs structurés pour les décisions clés (choix de routage, révision de plan, déclenchements de garde‑fous) et des métriques pour le volume et la santé.
Une trace utile contient généralement :
Journalisez prompts, entrées et sorties d'outils sous forme structurée, mais faites‑les passer par une couche de redaction d'abord :
Conservez le contenu brut derrière des feature flags en environnements non‑prod ; la production doit par défaut fournir des vues rédigées.
Au minimum, suivez :
Quand un incident survient, de bonnes traces et métriques vous permettent de passer de « l'agent semble instable » à une affirmation précise telle que : « P95 des tâches échouent dans ToolSelection après 2 retries en raison d'un nouveau schéma dans billing_service », réduisant le diagnostic de heures à minutes et donnant des leviers concrets pour corriger le comportement.
Tester des agents signifie tester à la fois les outils qu'ils appellent et les flux qui les assemblent. Traitez cela comme des tests de systèmes distribués, pas comme du simple tâtonnement de prompts.
Commencez par des tests unitaires à la frontière des outils :
Ces tests ne dépendent jamais du LLM. Vous appelez l'outil directement avec des entrées synthétiques et vérifiez la sortie exacte ou le contrat d'erreur.
Les tests d'intégration exercent le workflow agent bout à bout : LLM + outils + orchestration.
Modélisez‑les comme des scénarios :
Ces tests vérifient les transitions d'état et les appels d'outils, pas chaque token de la sortie du LLM. Contrôlez : quels outils ont été appelés, avec quels arguments, dans quel ordre et quel état/résultat final l'agent a atteint.
Pour garder les tests répétables, fixturez les réponses LLM et les sorties d'outils :
Un motif typique :
with mocked_llm(fixtures_dir="fixtures/llm"), mocked_tools():
result = run_agent_scenario(input_case)
assert result.state == "COMPLETED"
Chaque changement de prompt ou de schéma doit déclencher une suite de régression non négociable :
L'évolution des schémas (ajout de champs, durcissement de types) mérite ses propres cas de régression pour attraper les agents ou outils qui supposent encore l'ancien contrat.
Ne déployez jamais un nouveau modèle, politique ou stratégie de routage directement en production.
Au lieu de cela :
Ce n'est qu'après avoir franchi ces barrières hors ligne qu'une nouvelle variante doit atteindre la production, idéalement derrière des feature flags et un déploiement progressif.
Les logs d'agent contiennent souvent des données sensibles. Les tests doivent respecter cela :
Codifiez ces règles dans votre pipeline CI pour qu'aucun artefact de test ne puisse être généré ou stocké sans contrôles d'anonymisation.
Exploiter des agents en production ressemble davantage à la gestion d'un système distribué qu'à l'envoi d'un modèle statique. Vous avez besoin de contrôles de déploiement, d'objectifs de fiabilité clairs et d'une gestion disciplinée des changements.
Introduisez progressivement de nouveaux agents ou comportements :
Soutenez tout cela par des feature flags et des politiques pilotables : règles de routage, outils activés, température, réglages de sécurité. Les changements doivent être configurables, pas codés, et immédiatement réversibles.
Définissez des SLO qui reflètent la santé système et la valeur utilisateur :
Raccordez‑les aux alertes et gérez les incidents comme pour tout service en production : responsabilités claires, runbooks de triage et étapes de mitigation standard (rollback via flag, drain de trafic, mode safe).
Utilisez logs, traces et transcripts de conversation pour affiner prompts, outils et politiques. Traitez chaque changement comme un artefact versionné avec revue, approbation et capacité de rollback.
Évitez les modifications silencieuses de prompts ou d'outils. Sans contrôle de changement, vous ne pouvez pas corréler régressions et edits, et la réponse aux incidents devient de la devinette au lieu d'ingénierie ciblée.
Un système agentique prêt pour la production bénéficie d'une séparation claire des responsabilités. L'objectif est de garder l'agent intelligent pour les décisions, mais peu intelligent sur l'infrastructure.
1. Gateway / API edge
Point d'entrée unique pour les clients (apps, services, UIs). Il gère :
2. Orchestrateur
L'orchestrateur est la « tige cérébrale », pas le cerveau. Il coordonne :
Les LLM vivent derrière l'orchestrateur, utilisés par le planner et par des outils spécifiques nécessitant de la compréhension langage.
3. Couche d'outillage et stockage
La logique métier reste dans des microservices existants, queues et systèmes de données. Les outils sont des wrappers fins autour de :
L'orchestrateur invoque les outils via des contrats stricts, tandis que les systèmes de stockage restent sources de vérité.
Appliquez auth et quotas à la gateway ; appliquez safety, accès aux données et politiques dans l'orchestrateur. Tous les appels (LLM et outils) émettent de la télémetrie structurée vers une pipeline qui alimente :
Une architecture simple (gateway → orchestrateur unique → outils) est plus facile à exploiter ; ajouter planners séparés, moteurs de politiques et gateways modèles augmente la flexibilité, au prix d'une coordination, d'une latence et d'une complexité opérationnelle accrues.
Vous disposez maintenant des ingrédients principaux pour des agents qui se comportent de façon prévisible sous charge réelle : machines d'état explicites, contrats d'outils clairs, retries disciplinés et observabilité profonde. La dernière étape est de transformer ces idées en pratiques répétables pour votre équipe.
Considérez chaque agent comme un workflow stateful :
Quand ces pièces s'alignent, vous obtenez des systèmes qui se dégradent gracieusement au lieu de s'effondrer face aux cas limites.
Avant d'envoyer un agent prototype aux vrais utilisateurs, confirmez :
Si un élément manque, vous êtes encore en mode prototype.
Une configuration durable sépare généralement :
Cela permet aux équipes produit d'avancer vite tandis que la plateforme impose fiabilité, sécurité et contrôle des coûts.
Une fois les fondations stables, vous pouvez explorer :
Avancez progressivement : introduisez ces composants d'apprentissage derrière des feature flags, avec évaluation hors ligne et garde‑fous stricts.
Le fil conducteur est le même : concevoir pour l'échec, préférer la clarté à l'ingéniosité, et itérer là où vous pouvez observer et revenir en arrière en sécurité. Avec ces contraintes, les systèmes agentiques cessent d'être des prototypes effrayants et deviennent une infrastructure sur laquelle votre organisation peut s'appuyer.
Un système agentique est une application où un LLM ne se contente pas de répondre à un seul prompt, mais décide de la suite des opérations : quels outils appeler, quelles données récupérer, quelle étape d'un flux exécuter et quand s'arrêter.
Contrairement à une simple complétion de chat, un système agentique combine :
En production, le LLM devient un composant de décision dans une enveloppe déterministe plus large — pas le système entier.
Les démos fonctionnent généralement sur un chemin heureux unique : un seul utilisateur, des outils qui se comportent idéalement, pas de timeouts, pas de dérive de schéma et des conversations courtes. En production, les agents font face à :
Sans workflows explicites, contrats et gestion des erreurs, ces facteurs provoquent des boucles, des blocages, du travail partiel et des erreurs silencieuses qui n'apparaissent pas en environnement de démo.
Faites opérer le LLM à l'intérieur d'une structure claire plutôt que d'une boucle libre :
Il s'agit de modéliser l'agent comme un workflow avec des états nommés et des événements typés au lieu de while not done: call LLM.
Des états typiques peuvent inclure :
Concevez les outils comme de véritables APIs de production, pas comme des descriptions en prose. Chaque outil devrait définir :
Supposez que tout appel externe finira par échouer parfois et concevez en conséquence.
Principes clés :
Séparez l'état à court terme de la mémoire à long terme, et considérez le LLM comme stateless.
Considérez votre système d'agents comme un système distribué soumis à la charge, même si chaque flux paraît séquentiel.
Pour rester fiable :
Vous devez pouvoir répondre à « qu'a fait l'agent ? » et « pourquoi a‑t‑il agi ainsi ? » pour n'importe quelle tâche.
Exigences concrètes :
Traitez les agents comme des services évolutifs et appliquez la même rigueur que pour tout autre système en production.
Bonnes pratiques :
Ainsi, vous pourrez expliquer, tester et déboguer le comportement étape par étape au lieu de courir après des « pensées » d'agent opaques.
PLAN – interpréter la requête et produire un plan pas à pasCALL_TOOL – invoquer un outil spécifique ou un lot d'outilsVERIFY – vérifier les sorties par rapport à des règles simples ou des vérifications secondaires par modèleRECOVER – gérer les erreurs via retries, solutions de secours ou escaladesDONE / FAILED – états terminauxLes événements (par ex. ToolCallSucceeded, TimeoutExceeded) + l'état courant déterminent l'état suivant. Cela rend les retries, timeouts et la gestion des erreurs explicites au lieu d'être dispersés dans des prompts ou du glue code.
InvalidInput, NotFound, RateLimited, TransientFailureValidez les entrées avant l'appel (pour attraper les erreurs du modèle) et les sorties après (pour détecter les régressions d'outil). Versionnez les contrats et épinglez les agents sur des versions pour éviter que des changements de schéma interrompent silencieusement les flux.
request_id stable ou une clé métier et renvoient le même résultat en cas de ré-appel.Cela maintient la fiabilité sans générer de boucles incontrôlées, d'effets en double ou de coûts runaway.
Évitez d'utiliser des logs bruts ou l'historique de conversation comme « mémoire » ; dérivez plutôt des enregistrements structurés avec des règles claires de rétention et de confidentialité.
Surveillez la profondeur des queues, les percentiles de latence et les taux 429/503 pour détecter une surcharge avant qu'elle ne devienne une panne.
Avec cela, le triage d'incident passe de « l'agent est instable » à la localisation précise de l'état, de l'outil et du changement responsable d'une régression.
Cela permet d'améliorer les agents en continu tout en gardant les échecs contenus, diagnostiquables et réversibles.