Un agent est une boucle while : où LangChain create_agent et LangGraph Fit
Un agent de création d’outils en vingt lignes, les quatre problèmes de production rencontrés par les boucles, et quand passer de LangChain create_agent à LangGraph state graphs.
Sources: An Agent Is a While Loop
L’utilisation d’outils attire beaucoup d’attention, mais ce qui détermine quand appeler un outil, quoi faire de son résultat et quand s’arrêter, c’est la boucle qui entoure le modèle. Les gens appellent cette boucle « orchestration », un terme qui lui donne une importance supérieure à la réalité. La manière la plus simple de comprendre cela est de regarder d’abord l’ensemble du processus, puis d’analyser pourquoi il n’est pas suffisant pour un environnement de production.
Un agent complet en une vingtaine de lignes
Prenez l’échange impliquant l’appel à un outil : le modèle demande l’utilisation d’un outil, votre code le exécute et le résultat revient au modèle ; entourez tout cela d’une boucle while. La conversation est d’abord initialisée :
messages = [system_prompt, user_question]
Puis le boucle elle-même :
while True:
reply = model(messages, tools=TOOLS) if not reply.tool_calls:
return reply.text # the model answered; done for call in reply.tool_calls:
result = TOOLS[call.name](**call.args) # your code runs it
messages.append(tool_result(call.id, result))
C’est un agent réel, et non une version caricaturale. Le modèle choisit l’outil à appeler. Votre code le lance et ajoute le résultat obtenu. Ce processus se répète jusqu’à ce que le modèle renvoie du texte plutôt qu’une demande d’outil.
Si cela semble un peu décevant en raison de sa petite taille, c’est justement l’effet recherché. Tout ce que fournit un framework est quelque chose que vous ajouterez une fois ce cycle mis en production.
Une exécution, étape par étape
Imaginons un agent de triage chargé d’analyser pourquoi les synchronisations nocturnes avec les transporteurs échouent avec l’erreur ERR_4412 depuis la version de décembre. Il parvient à une réponse en trois itérations, au cours d’un seul cycle sans framework.
Tour 1. Le modèle ne répond pas encore. Il envoie une demande, search_runbooks("ERR_4412"), et le cycle la met en œuvre. Trois résultats reviennent, et le premier indique que cette erreur signifie qu’un jeton d’authentification du transporteur a expiré. Cet élément est alors ajouté aux messages.
Tour 2. Après avoir lu cela, le modèle demande get_release_notes("decembre"). Un document indique que l’intervalle de renouvellement du jeton a été réduit de 24 heures à 12. Cela est ajouté à nouveau.
Tour 3. En conservant les deux résultats, le modèle répond en texte brut sans demander d’outil. Les synchronisations qui s’exécutent pendant la nuit durent plus de douze heures, ce qui fait que le jeton expire au milieu d’une exécution. Comme aucune demande d’exécution n’est faite, la boucle se termine.
Le modèle a choisi les outils et la boucle les a exécutés. La liste des messages s’est enrichie de deux résultats, et rien d’autre ne s’est produit.
Qu’est-ce qui tombe en panne après une semaine d’exécution
Quatre problèmes apparaissent généralement en production, habituellement dans cet ordre. Aucun ne concerne le modèle. Tous concernent l’environnement d’exécution qui l’entoure.
Le redémarrage. Au deuxième tour, le système se bloque en raison d’un incident lent ; huit minutes plus tard, le conteneur est recyclé. Comme les messages n’étaient stockés que en mémoire, ils disparaissent et l’exécution reprend depuis le début. La solution consiste à enregistrer la conversation après chaque tour et à reprendre à partir de cette sauvegarde.
Outil dangereux. Une autre nuit, au quatrième tour, le modèle conclut que la solution est rollback_release("dec-2025"). Laisser un modèle faire cela seul à 3 heures du matin n’est certainement pas souhaitable. Le cycle doit s’arrêter, demander l’intervention d’une personne, attendre, éventuellement jusqu’au matin, avant de reprendre exactement là où il s’était arrêté. Une simple boucle while ne peut pas attendre jusqu’au matin.
Le mauvais choix de direction. Le cinquième étape choisit une requête de recherche inadaptée, et les étapes 6 à 16 répètent cette recherche avec de légères modifications de formulation, chacune étant facturée. Fixer son regard sur une liste de seize messages ne permet pas de voir où se situe l’erreur. Ce qui aide, c’est une limite au nombre d’étapes ainsi qu’un enregistrement détaillé de chacune d’elles qui peut être consulté ultérieurement.
La bonne voie à suivre. Les erreurs d’authentification exigent une séquence d’étapes spécifique, tandis que les erreurs de données en nécessitent une autre ; lorsque deux outils sont en désaccord, le cas doit être transmis à un humain. Un modèle est capable de choisir un outil, mais il ne devrait pas improviser différemment le flux de contrôle à chaque exécution. Les branches logiques doivent être écrites de manière à fonctionner de la même façon à chaque fois.
Regardez à nouveau ces quatre éléments. Aucun ne blâme un modèle intelligent ou maladroit. Tous renvoient au code environnant, c’est-à-dire à ce qui y persiste, quand il s’arrête, ce qu’il enregistre et qui choisit la trajectoire. L’orchestration est cette couche environnante, d’où le fait qu’un cycle de vingt lignes puisse être parfaitement correct tout en étant un point à améliorer.
Transformez les étapes en boîtes
Dessinez à nouveau le même exécution, avec chaque étape représentée par une boîte reliées par des flèches : classer, rechercher les guides de fonctionnement, obtenir les notes de version, proposer une correction, approuver, puis appliquer ou répondre. Avec les étapes sous forme de boîtes, trois nouvelles capacités apparaissent.
- Chaque boîte se termine par l’enregistrement de l’état dans un stockage durable, de sorte que lors d’un redémarrage, l’exécution reprend à la dernière boîte terminée et non au début.
- Toute boîte peut suspendre l’ensemble de l’exécution et attendre une personne aussi longtemps que nécessaire, l’état étant stocké en toute sécurité.
La logique de bifurcation se trouve dans la case de classification, avec un chemin d’authentification, un chemin de données et une procédure d’escalade. Vous avez dessiné ces trois flèches. Le modèle choisit toujours des outils au sein d’un chemin, mais le chemin lui-même vous appartient.
Le modèle n’a pas changé. La boucle a acquis une forme que vous pouvez voir, enregistrer et interrompre.
Qu’est-ce que LangChain ?
LangChain est une bibliothèque Python, accompagnée d’une version JavaScript, qui fournit des composants prêts à l’emploi pour les applications basées sur des LLM, afin de ne pas avoir à réécrire constamment la même infrastructure. Trois types de composants sont importants.
Enveloppes de modèles. Une seule interface pour tous les fournisseurs. ChatAnthropic, ChatOpenAI et ChatGoogleGenerativeAI exposent toutes la même méthode .invoke(messages) ; ainsi, changer de fournisseur ne nécessite qu’une modification en une seule ligne, sans avoir à réécrire le code de la requête.
Intégrations. Des adaptateurs pour tout ce qui entoure le modèle : bases de données vectorielles, chargeurs de documents, outils de récupération, modèles d’incorporation ainsi que plusieurs centaines d’outils externes. C’est là que réside la majeure partie de l’économie de travail, car chaque adaptateur devrait sinon être écrit et entretenu par vous-même.
Boucle d’agent emballée. Depuis la version 1.0 en octobre 2025, l’entrée principale est la fonction create_agent, à importer de la manière suivante :
from langchain.agents import create_agent
et utilisé de cette manière :
agent = create_agent(
model="anthropic:claude-sonnet-4-6",
tools=[search_runbooks, get_release_notes],
system_prompt="You are the on-call triage assistant.",
)
result = agent.invoke({"messages": [("user", "Why is ERR_4412 failing?")]})
En réalité, le boucle mentionnée précédemment est déjà prête à l’emploi. Le middleware est également pris en charge : de petits modules qui s’exécutent avant ou après une appel à un modèle ou à un outil. Ceux existants permettent de suspendre l’exécution en attendant une validation humaine avant que l’outil ne s’exécute, de supprimer les données personnelles et de condenser une longue conversation.
Ce que create_agent omet, c’est le contrôle de l’intérieur du boucle : il n’y a pas de possibilité d’examiner l’état entre les étapes, aucune pause pouvant durer toute une journée, et un processus en panne entraîne l’échec de toute l’opération.
Qu’est-ce que LangGraph ?
Derrière create_agent se trouve LangGraph, une bibliothèque différente développée par le même créateur. LangChain fournit un boucle déjà prête, tandis que LangGraph fournit les éléments nécessaires pour en créer une propre, structurée comme le graphique présenté ci-dessus. Vous devez définir trois éléments.
État. Un objet textuel qui se déplace au sein du flux de traitement. Pour le tri, il contient les messages reçus jusqu’à présent, la classification de l’erreur, la correction proposée et l’indication de son approbation.
Nœuds. Des fonctions Python ordinaires qui reçoivent l’état et renvoient des mises à jour. classify, search_runbooks, propose_fix et ask_human ne sont chacun qu’une fonction.
Arêtes. L’ordre d’exécution. Les arêtes simples représentent des flèches fixes, tandis que les arêtes conditionnelles sont des fonctions qui lisent l’état et sélectionnent le nœud suivant, ce qui permet d’exprimer la séparation entre authentification et données.
L’importation :
from langgraph.graph import StateGraph
Et un graphique construit à partir de ces éléments :
g = StateGraph(TriageState)
g.add_node("classify", classify)
g.add_node("search", search_runbooks)
g.add_node("propose", propose_fix)
g.add_node("approve", ask_human)
g.add_edge("classify", "search")
g.add_conditional_edges("search", route_by_error_type)
g.add_edge("propose", "approve")app = g.compile(checkpointer=PostgresSaver(...))
Une seule ligne vers la fin est cruciale : il s’agit d’un point de contrôle, c’est-à-dire un endroit permettant de conserver l’état, fourni lors de la compilation du graphe. Grâce à lui, l’état est enregistré après chaque nœud. La capacité de redémarrer, l’utilisation de interrupt() pour attendre une action, ainsi que le réenregistrement d’un nœud afin de rejouer la séquence forward proviennent tous de cet argument plutôt que de code manuellement écrit. Votre contribution se limite aux cases et aux flèches.
Ainsi, le contraste est le suivant : LangChain fournit un boucle dont on ne voit pas l’intérieur. LangGraph vous demande de dessiner cette boucle, et en échange vous pouvez l’inspecter, la conserver, l’arrêter ou la rejouer. Les quatre problèmes mentionnés ci-dessus correspondent aux moments où ne pas pouvoir voir l’intérieur cesse d’être acceptable.
Une pile, deux portes
Puisque create_agent est basé sur un graphe LangGraph, choisir entre LangChain et LangGraph n’est pas une décision liée au framework. Il s’agit plutôt de savoir quelle porte utiliser, et les deux solutions se combinent. Un agent créé avec create_agent est lui-même un graphe, ce qui signifie qu’il peut être placé en tant que nœud unique à l’intérieur d’un StateGraph plus grand. Le graphe principal gère la classification, les approbations et la persistance, tandis que l’agent interne s’occupe des décisions à prendre par le modèle.
Utilisez create_agent lorsque vous avez besoin d’un agent fonctionnel dès aujourd’hui et que son architecture interne n’a pas d’importance. De nombreux agents n’ont jamais besoin de plus que cela. Recourez à StateGraph lorsque vous devez examiner l’état en cours d’exécution, attendre une personne, se remettre d’une panne ou revenir en arrière, ce qui correspond aux quatre problèmes énumérés précédemment.
Les SDK des fournisseurs Anthropic et OpenAI se situent à côté de cette pile technologique plutôt que dedans. Ils exécutent la même boucle, liée à une seule famille de modèles, ce qui génère le moins de friction si vous utilisez un seul fournisseur. Le prix à payer est la portabilité.
Conseils pour une équipe
Rédigez d’abord la boucle de vingt lignes, même si elle sera jetée par la suite. Cela prend une heure, et ensuite il devient clair ce que chaque framework fait à votre place, ce qui est le seul moyen de le déboguer.
Passez à LangGraph dès que l’un de ces quatre problèmes se pose réellement, et pas avant. Un chatbot qui appelle trois outils pour répondre peut se passer d’un graphe. Un agent censé survivre à une redémarrage, attendre une approbation ou être rejoué ne peut pas le faire, et une exécution durable construite de zéro constitue un projet à part entière.
Les équipes saisissent souvent le graphe dès le premier jour pour résoudre un problème que peut gérer une boucle simple, puis elles passent un quart du temps à apprendre le framework alors que ce temps aurait dû être consacré au problème lui-même.