v1.2 — Édition 2026. Un cours audio approfondi sur le framework d'orchestration LangChain v1.0. Créez des applications d'IA multi-agents fiables avec des appels d'outils standardisés, des sorties structurées, une validation avec un humain dans la boucle et une ingénierie de contexte avancée.
Nous explorons pourquoi LangChain a évolué d'un simple wrapper vers un framework d'orchestration complet. Vous découvrirez l'histoire du développement d'applications LLM et comment la sortie de la v1.0 standardise les interactions avec les modèles.
3m 21s
2
L'abstraction unifiée de l'agent
Nous plongeons dans la fonction principale create_agent qui unifie les précédentes abstractions de LangChain. Vous apprendrez comment la boucle ReAct fonctionne sous le capot pour gérer le raisonnement du modèle et l'exécution des outils.
3m 17s
3
Standardiser le chaos
Nous examinons comment LangChain standardise les interactions avec les modèles à travers différents fournisseurs. Vous apprendrez à initialiser des modèles de chat et à basculer facilement entre OpenAI, Anthropic et Google.
3m 29s
4
Le langage universel des LLMs
Nous décomposons l'unité fondamentale de contexte dans LangChain : les Messages. Vous apprendrez à structurer les messages System, Human, AI et Tool pour construire des historiques de conversation robustes.
3m 20s
5
Doter les agents d'outils
Nous explorons comment donner des actions à vos modèles en utilisant le décorateur @tool. Vous apprendrez comment les type hints et les docstrings sont automatiquement convertis en schémas JSON précis pour le modèle.
3m 32s
6
Injecter le contexte des outils
Nous nous penchons sur la transmission d'informations d'exécution directement à vos outils sans les exposer au LLM. Vous apprendrez à utiliser le paramètre ToolRuntime pour des configurations sécurisées avec injection de dépendances.
3m 28s
7
Persistance au niveau du thread
Nous abordons la mémoire à court terme et la manière de conserver l'historique des conversations. Vous apprendrez comment attacher des checkpointers à votre agent pour permettre aux conversations d'être mises en pause, reprises et mémorisées.
3m 37s
8
Compresser le contexte avec un Middleware
Nous explorons comment empêcher les longues conversations de faire planter votre modèle. Vous apprendrez à utiliser le SummarizationMiddleware pour compresser automatiquement les anciens messages et économiser des tokens.
3m 20s
9
Formats de données garantis
Nous discutons de la manière de forcer les modèles de langage à renvoyer des structures de données strictes et prévisibles. Vous apprendrez la différence entre ProviderStrategy et ToolStrategy pour générer des modèles Pydantic.
3m 20s
10
Intercepter la boucle de l'agent
Nous introduisons le paradigme du middleware, vous donnant un contrôle chirurgical sur l'exécution de votre agent. Vous apprendrez à utiliser les hooks wrap-style et node-style pour intercepter les appels de modèles.
2m 57s
11
Ingénierie de contexte dynamique
Nous plongeons dans l'ingénierie de contexte en générant dynamiquement des prompts système. Vous apprendrez à utiliser un middleware pour modifier les instructions en fonction du rôle de l'utilisateur actuel et de son environnement.
3m 44s
12
IA sécurisée avec des garde-fous déterministes
Nous sécurisons nos agents contre les fuites de données en utilisant un middleware intégré. Vous apprendrez à appliquer le PIIMiddleware pour masquer automatiquement les informations sensibles avant qu'elles n'atteignent le modèle.
3m 44s
13
Mise en pause pour approbation humaine
Nous explorons l'exécution d'outils à fort enjeu en ajoutant un humain dans la boucle. Vous apprendrez comment interrompre l'exécution d'un agent pour approuver, modifier ou rejeter des actions sensibles.
3m 41s
14
Retour d'information de l'agent en temps réel
Nous plongeons dans le streaming pour améliorer considérablement l'expérience utilisateur. Vous apprendrez à interpréter les modes de stream pour afficher les tokens du LLM en direct aux côtés des mises à jour d'exécution d'outils personnalisés.
2m 47s
15
Persistance inter-sessions
Nous explorons la mémoire à long terme pour construire des agents qui connaissent vraiment leurs utilisateurs. Vous apprendrez à utiliser les stores LangGraph pour sauvegarder des documents JSON à travers des conversations entièrement différentes.
3m 17s
16
Le paradigme multi-agents
Nous expliquons pourquoi les agents uniques échouent et introduisons l'architecture des Subagents. Vous apprendrez comment un agent superviseur principal coordonne des sous-agents en tant que fenêtres de contexte isolées pour éviter la surcharge de tokens.
4m 07s
17
Agents pilotés par l'état
Nous explorons comment les agents peuvent modifier dynamiquement leur comportement. Vous apprendrez le modèle Handoffs pour transférer le contrôle, et le modèle Skills pour charger des prompts spécialisés à la demande.
3m 36s
18
Workflows personnalisés et routeurs
Nous sortons de la boucle standard de l'agent. Vous apprendrez à utiliser LangGraph pour construire des architectures de routage personnalisées, en mélangeant une logique déterministe avec un raisonnement agentique non déterministe.
3m 46s
19
Communication d'agent à agent
Nous explorons le endpoint LangSmith A2A. Vous apprendrez comment des agents distribués déployés sur des serveurs entièrement différents peuvent converser nativement en utilisant le protocole A2A RPC de Google.
3m 24s
20
L'avenir est au MCP
Nous nous tournons vers l'avenir avec le Model Context Protocol, qui standardise la façon dont les agents accèdent aux outils externes. Vous apprendrez à connecter des serveurs MCP distants à votre agent en utilisant des transports standards.
4m 19s
Épisodes
1
L'ère de l'orchestration
3m 21s
Nous explorons pourquoi LangChain a évolué d'un simple wrapper vers un framework d'orchestration complet. Vous découvrirez l'histoire du développement d'applications LLM et comment la sortie de la v1.0 standardise les interactions avec les modèles.
Salut, c'est Alex de DEV STORIES DOT EU. LangChain v1.0 Orchestration Framework, épisode 1 sur 20. C'est incroyablement facile de créer un prototype d'agent IA, mais c'est super difficile d'en faire un assez fiable pour le passer en production. Le fossé entre une démo sympa du week-end et une application d'entreprise est énorme. La solution pour combler ce fossé, c'est ce qu'on appelle l'ère de l'orchestration.
D'abord, mettons au clair un malentendu très courant. On confond souvent LangChain avec un model provider. LangChain n'entraîne pas, n'héberge pas et ne sert pas de large language models. C'est la couche d'orchestration qui se place juste au-dessus de ces modèles. Vois ça comme le centre de contrôle qui gère la façon dont ton application interagit avec le modèle que tu as choisi d'utiliser.
Pour comprendre pourquoi une couche d'orchestration est nécessaire, il faut regarder comment la technologie a évolué. En 2022, interagir avec un language model, c'était simple. Tu envoyais une string de texte, et tu recevais une string de texte en retour. De simples prompt chains suffisaient pour faire le job. Tu n'avais pas besoin d'un framework lourd pour gérer un workflow basique de text-in, text-out. Tu pouvais facilement écrire un script où l'output du prompt A était simplement collé dans le prompt B.
Mais en avançant dans 2025 et en regardant vers 2026, le paysage est complètement différent. Les modèles ne traitent plus seulement du plain text. Ils ingèrent et génèrent des blocs multimodaux complexes. Une seule interaction peut impliquer le routing d'un prompt utilisateur, le déclenchement d'un tool call externe, le traitement d'une image et le retour d'un bloc de données structuré. Un modèle peut renvoyer une requête de database lookup juste à côté d'un résumé texte. Si le code de ton application doit inspecter manuellement chaque réponse pour savoir si c'est une string, une invocation de tool ou un fichier image, ta codebase va vite devenir un bazar fragile et impossible à maintenir.
Voici le point clé. Passer exactement le bon contexte à un modèle, exactement au bon moment, c'est beaucoup plus dur que de simplement choisir le modèle le plus puissant du marché. Tu peux utiliser le reasoning engine le plus intelligent disponible, mais s'il reçoit des données brouillonnes et non standardisées, toute l'interaction va planter.
C'est pour ça que LangChain a évolué, passant d'une simple library de chaining à une couche d'orchestration standardisée pour sa release 1.0. Il fournit un format de message standard qui fonctionne de manière cohérente avec tous les principaux model providers. Au lieu d'écrire une logique de parsing custom pour chaque API différente, tu utilises une structure uniforme. En standardisant le format des messages, LangChain s'assure qu'un tool call d'un provider ressemble exactement à un tool call d'un provider concurrent dans ton code. Tu définis une séquence où un message utilisateur entre, la couche d'orchestration le normalise, l'envoie au modèle, récupère la réponse multimodale, et retraduit cette réponse dans un format standard que ton application peut vraiment utiliser. Tu écris la logique de ton application une seule fois, et la couche d'orchestration gère la traduction.
Le modèle en lui-même n'est plus l'application entière, c'est juste le reasoning engine, et c'est la couche d'orchestration qui détermine si ce moteur résout vraiment ton problème métier.
Si tu veux nous aider à continuer de faire ces épisodes, tu peux soutenir l'émission en cherchant DevStoriesEU sur Patreon. C'est tout pour aujourd'hui. Merci pour ton écoute, et continue de coder !
2
L'abstraction unifiée de l'agent
3m 17s
Nous plongeons dans la fonction principale create_agent qui unifie les précédentes abstractions de LangChain. Vous apprendrez comment la boucle ReAct fonctionne sous le capot pour gérer le raisonnement du modèle et l'exécution des outils.
Salut, c'est Alex de DEV STORIES DOT EU. LangChain v1.0 Orchestration Framework, épisode 2 sur 20. Et si tu pouvais remplacer toute ta boucle de raisonnement complexe par un simple appel de fonction de dix lignes ? Tu passes des heures à écrire des parsers custom et des while-loops juste pour qu'un modèle de langage déclenche une fonction de manière fiable. L'Unified Agent Abstraction est l'architecture qui te libère de ça.
Pour comprendre pourquoi c'est important, on doit dissiper une confusion fréquente concernant les anciennes versions du framework. Dans la version zéro point x, les développeurs devaient naviguer dans un labyrinthe de classes d'agents spécifiques. Tu avais des conversational agents, des zero-shot agents, et des custom chains complexes. Si tu mets à jour ton code, tu peux oublier tout ça. L'Unified Agent Abstraction remplace intégralement toutes les anciennes chains et les legacy agents. Elle offre un point d'entrée clair et standardisé, via une fonction simplement appelée create agent.
Cette fonction existe pour gérer la ReAct loop. ReAct signifie Reason and Act. Quand un utilisateur pose une question complexe, un modèle de langage ne peut pas juste exécuter du code. Il doit raisonner sur le problème, décider de prendre une action, générer un output texte pour demander cette action, puis attendre une observation avant de pouvoir raisonner à nouveau. Gérer ce cycle manuellement, c'est fastidieux. Tu dois parser le texte généré par le modèle, le mapper à une fonction locale, exécuter cette fonction, formater l'output, le réinjecter dans le modèle, et évaluer si la tâche est terminée. La fonction create agent abstrait tout ce processus d'orchestration.
Regardons une implémentation simple en utilisant un tool pour vérifier la météo. D'abord, tu définis ton tool spécifique, par exemple une fonction appelée get weather qui prend un nom de ville. Ensuite, tu initialises le modèle de langage de ton choix. Puis vient l'abstraction. Tu appelles la fonction create agent et tu lui passes trois arguments. Tu passes ton modèle de langage, une liste contenant ton tool get weather, et un system prompt qui dicte les règles pour l'agent. Ce seul appel retourne un objet agent exécutable. Enfin, tu invoques cet objet avec une user query, pour demander la météo actuelle à Londres.
Voici le point clé du flow d'exécution. Quand tu invoques l'agent, tu démarres la ReAct loop. L'agent envoie la query et les descriptions des tools au modèle. Le modèle décide qu'il a besoin de données en temps réel et produit un tool call standardisé. L'abstraction de l'agent intercepte ce call automatiquement. Elle exécute ton tool get weather avec l'argument London, prend les données de température qui en résultent, et les repasse au modèle comme une nouvelle observation. Le modèle évalue ces données, réalise qu'il a la réponse à la user query, et génère une réponse finale.
Tu n'as pas écrit une seule loop, et tu n'as pas écrit d'output parser. Tu as seulement fourni les tools, le modèle, et les instructions. La puissance de l'Unified Agent Abstraction réside dans l'établissement d'une frontière architecturale stricte. Elle isole complètement la mécanique du cycle de raisonnement, ce qui te permet de consacrer tous tes efforts d'ingénierie à affiner la qualité de tes tools et la clarté de tes prompts.
C'est tout pour cet épisode. Merci d'avoir écouté, et continue de développer !
3
Standardiser le chaos
3m 29s
Nous examinons comment LangChain standardise les interactions avec les modèles à travers différents fournisseurs. Vous apprendrez à initialiser des modèles de chat et à basculer facilement entre OpenAI, Anthropic et Google.
Salut, c'est Alex de DEV STORIES DOT EU. LangChain v1.0 Orchestration Framework, épisode 3 sur 20. Les API des différents fournisseurs de modèles sont extrêmement différentes, ce qui veut dire qu'essayer un nouveau modèle t'oblige généralement à réécrire la moitié de ton application. Tu finis par être bloqué avec un seul fournisseur juste parce que le coût technique pour en changer est trop élevé. Standardiser tout ce bazar, c'est exactement le sujet de cet épisode.
Avant de rentrer dans les détails de comment LangChain règle ça, c'est utile de dissiper une confusion fréquente. Si tu as bossé avec les premiers modèles de langage, tu connais probablement les classes LLM legacy qui acceptent une simple string de texte brut en input. Les modèles de chat modernes sont différents. Ils exigent strictement une séquence structurée de messages, où chaque message a un rôle spécifique attaché, comme system, human ou AI. Tout ce dont on va parler maintenant s'applique à ces modèles de chat modernes, et pas aux modèles de text completion legacy.
Quand tu construis une application, hardcoder un fournisseur spécifique crée un vendor lock-in immédiat. Pour casser cette dépendance, LangChain introduit une seule factory function appelée init chat model. Vois ça comme un traducteur universel pour initialiser des clients d'intelligence artificielle. Au lieu d'importer une classe unique pour OpenAI, une autre pour Anthropic, et encore une autre pour Google, tu te reposes exclusivement sur cette seule fonction.
Voici l'idée clé. La fonction init chat model utilise une syntaxe de string toute simple pour savoir quoi construire. Tu fournis une string formatée avec le nom du fournisseur, suivi d'un deux-points, suivi de la version spécifique du modèle. Prends l'exemple d'un agent qui tourne actuellement sur le GPT-5 d'OpenAI. Tu initialises ton modèle simplement en passant la string openai deux-points gpt-5.
Maintenant, suppose qu'Anthropic sorte un nouveau modèle qui gère mieux la génération de code, et que tu veuilles le tester. Vu que tu as utilisé la fonction init chat model, tu ne touches pas à la logique de ton agent. Tu n'importes pas de nouveau package client. Tu changes juste cette unique string d'initialisation pour anthropic deux-points claude-sonnet-4-6. LangChain résout dynamiquement la string et charge la bonne classe d'intégration sous-jacente.
Ça, ça gère le modèle en lui-même, mais les fournisseurs ne sont pas non plus d'accord sur les paramètres de configuration. Une API peut attendre un paramètre appelé max sampled tokens, pendant qu'une autre attend max length. La fonction init chat model résout ça en acceptant des paramètres standards. Quand tu initialises ton modèle, tu peux passer des arguments comme temperature ou max tokens directement à la fonction.
Si tu mets ta temperature à zéro virgule deux et tes max tokens à mille, LangChain mappe ces termes génériques vers les clés de payload exactes requises par le fournisseur que tu as spécifié dans ta string. Tu configures ton modèle une seule fois en utilisant la terminologie standard, et le framework le traduit pour l'API de destination.
En séparant le code de ton application des détails d'implémentation spécifiques au fournisseur, tu gagnes en agilité architecturale, ce qui te permet d'évaluer des modèles concurrents en quelques secondes plutôt qu'en plusieurs jours.
C'est tout pour cet épisode. Merci d'avoir écouté, et continue à développer !
4
Le langage universel des LLMs
3m 20s
Nous décomposons l'unité fondamentale de contexte dans LangChain : les Messages. Vous apprendrez à structurer les messages System, Human, AI et Tool pour construire des historiques de conversation robustes.
Salut, c'est Alex de DEV STORIES DOT EU. LangChain v1.0 Orchestration Framework, épisode 4 sur 20. Si tu passes encore des strings en plain text à tes modèles de langage, tu limites considérablement tes applications. Les strings simples perdent le contexte. Elles ne peuvent pas contenir de manière fiable des références d'images, des résultats d'exécution de tools, ou des rôles d'interaction distincts. Pour résoudre ça, LangChain utilise des objets de message standardisés, qui servent de langage universel pour les LLMs.
Un message dans LangChain est une structure de données qui contient un rôle spécifique, le payload, et des métadonnées optionnelles. Les différents fournisseurs d'API gèrent les rôles de conversation et les inputs multimodaux différemment dans leurs APIs brutes. LangChain abstrait cette friction en quatre classes distinctes.
La première, c'est le SystemMessage. Cet objet établit les règles de fond, le persona, ou les contraintes strictes pour l'interaction. Ensuite, on a le HumanMessage, qui représente le prompt de l'utilisateur ou les fichiers uploadés. Puis on a l'AIMessage, qui capture la réponse générée par le modèle. Et enfin, il y a le ToolMessage. Cet objet renvoie spécifiquement le résultat de l'exécution d'une fonction externe au modèle, ce qui sépare proprement l'input brut de l'utilisateur des données factuelles générées par le système.
Tu orchestres les conversations en passant un array de ces objets de message au modèle. Tu peux construire cet array manuellement pour façonner l'output. D'abord, tu crées une liste et tu insères un SystemMessage qui assigne au modèle le rôle d'un expert en poésie au formatage strict. Ensuite, tu ajoutes un HumanMessage qui demande un haïku sur les migrations de base de données. Et c'est là qu'est l'astuce. Tu n'as pas besoin d'attendre que le modèle génère la réponse suivante. Tu peux instancier manuellement un AIMessage et l'injecter dans l'array juste après le prompt humain, avec une phrase d'accroche spécifique. Quand tu passes tout cet array au modèle, il interprète ton AIMessage injecté comme son propre comportement passé. Il va continuer le haïku de manière fluide à partir de ton point de départ exact, en respectant la structure que tu lui as imposée.
Quand tu reçois finalement un AIMessage en retour du modèle, tu dois extraire ce qu'il a réellement produit. Les développeurs confondent souvent l'attribut content brut avec le payload parsé. Chaque objet message possède une propriété content. Cependant, cet attribut content brut reflète directement ce que le fournisseur de LLM spécifique a renvoyé. Selon le fournisseur du modèle et le prompt, ça peut être une simple string de texte, ou ça peut être une liste de dictionnaires très imbriquée contenant un mélange de chunks de texte, d'URLs d'images et d'identifiants de tools. Parser ça manuellement rend ton code incroyablement fragile.
Au lieu de lire le content brut, tu devrais utiliser la propriété content blocks. La propriété content blocks est la représentation standardisée et strictement typée du payload du message dans LangChain. Quand tu lis à partir des content blocks, LangChain traduit la réponse spécifique au fournisseur en une liste uniforme d'objets block. Tu peux itérer sur cette liste en toute sécurité. D'abord, tu vérifies si un block est un text block, et si c'est le cas, tu extrais le payload textuel. Ensuite, tu vérifies si c'est un tool call block, et tu extrais les arguments. Construire ta logique de parsing autour de la propriété standardisée content blocks est le seul moyen de garantir que ton application reste totalement découplée des formats de réponse changeants des différents fournisseurs de modèles.
C'est tout pour cet épisode. Merci d'avoir écouté, et continue de builder !
5
Doter les agents d'outils
3m 32s
Nous explorons comment donner des actions à vos modèles en utilisant le décorateur @tool. Vous apprendrez comment les type hints et les docstrings sont automatiquement convertis en schémas JSON précis pour le modèle.
Salut, c'est Alex de DEV STORIES DOT EU. LangChain v1.0 Orchestration Framework, épisode 5 sur 20. Un agent d'IA sans accès au monde extérieur n'est qu'un générateur de texte. Pour en faire un système qui fait vraiment le boulot, tu dois lui donner des mains. Aujourd'hui, on parle de donner des outils aux agents, et plus précisément du décorateur @tool.
Dans LangChain, un outil est un pont entre le moteur de raisonnement d'un modèle de langage et tes systèmes externes. Mais il y a une idée reçue très courante. Beaucoup de développeurs pensent que le modèle de langage analyse la logique à l'intérieur de leur fonction Python pour comprendre comment l'utiliser. Ce n'est pas le cas. Le modèle de langage ne voit jamais ton code Python. Il ne voit qu'un schéma qui décrit la fonction.
Pour créer un outil, tu écris une fonction Python standard et tu places le décorateur @tool juste au-dessus. Ce décorateur fait quelque chose de crucial. Il inspecte la signature de ta fonction, extrait le nom de la fonction, lit les type hints pour chaque paramètre, et parse la docstring. Il prend toutes ces métadonnées et les regroupe dans un format structuré que le modèle de langage peut vraiment lire.
Comme le modèle lit uniquement ce schéma généré, la précision de ton code est critique. Prenons un scénario. Imagine que tu écris une fonction appelée search database. Si tu lui donnes une docstring un peu faible qui dit juste, cherche dans la base de données, et que tu oublies complètement les type hints, le modèle de langage navigue à l'aveugle. Il ne sait pas de quel genre de base de données il s'agit, et il ne sait pas quels arguments fournir. Il pourrait essayer de passer une phrase conversationnelle complète comme requête de recherche, ce qui ferait crasher ta fonction Python lors de l'exécution.
Voici le point essentiel. Quand tu utilises le décorateur @tool, tu dois écrire tes docstrings pour le modèle de langage, pas pour le développeur humain. Au lieu d'une description vague, tu écris une instruction claire, du genre, cherche dans la base de données clients par adresse e-mail pour récupérer l'historique de facturation.
Ensuite, tu appliques des type hints stricts à tes paramètres d'entrée. Tu spécifies que l'argument email doit être une string. Tu peux même ajouter une description à l'argument lui-même. Chaque information de type que tu ajoutes donne au modèle de langage des limites plus strictes sur ce qu'il a le droit de générer.
Quand tu passes cet outil fraîchement décoré à un agent, l'agent lit le schéma détaillé avant de faire quoi que ce soit d'autre. Quand un utilisateur pose une question sur le remboursement d'un client, l'agent scanne ses outils disponibles et reconnaît que l'outil search database est exactement ce qu'il faut, grâce à ta docstring précise. Grâce à ton type hint strict, il sait exactement comment formater l'argument. Il extrait la string email du prompt utilisateur, arrête sa génération de texte, et produit un tool call.
LangChain intercepte ce tool call. Il prend la string email que le modèle a générée, la passe à ta fonction Python sous-jacente, et exécute le code. Ta fonction parle à la base de données, récupère l'historique de facturation, et renvoie les données brutes directement à LangChain. LangChain renvoie ensuite ces données à l'agent sous forme d'observation. L'agent reprend son processus de réflexion, mais maintenant il a les vraies données que tu viens de lui fournir.
La capacité d'action du modèle de langage est complètement limitée par la qualité de la signature de ta fonction. Traite tes docstrings et tes type hints comme des contraintes d'ingénierie strictes, parce que pour le modèle de langage, ce sont les seules instructions qui existent. C'est tout pour aujourd'hui. Merci d'avoir écouté, et continue de développer !
6
Injecter le contexte des outils
3m 28s
Nous nous penchons sur la transmission d'informations d'exécution directement à vos outils sans les exposer au LLM. Vous apprendrez à utiliser le paramètre ToolRuntime pour des configurations sécurisées avec injection de dépendances.
Salut, c'est Alex de DEV STORIES DOT EU. LangChain v1.0 Orchestration Framework, épisode 6 sur 20. Si tu te fies à un modèle de langage pour passer correctement un token d'authentification ou l'identité d'un utilisateur à un tool de base de données, tu t'exposes à une énorme faille de sécurité. Le modèle ne sait pas qui est l'utilisateur actuel, et on ne devrait certainement pas lui faire confiance pour deviner. Tu as besoin d'un moyen de passer des données sensibles du backend directement à tes tools, en contournant complètement le modèle. C'est exactement ce que résout l'injection de Tool Context.
Quand tu construis un tool, certains arguments sont faits pour être générés par le modèle, comme une search string ou une plage de dates. D'autres arguments sont strictement pour ton infrastructure backend. C'est là qu'intervient l'objet ToolRuntime. Il te permet d'injecter une configuration statique dans un tool exactement au moment où il s'exécute.
Tu pourrais te dire que tu peux juste passer un dictionnaire de configuration comme un argument de tool normal et dire au prompt de l'ignorer. Ne fais pas ça. Quand tu définis un paramètre nommé config ou runtime dans ta fonction de tool, LangChain les traite comme des mots-clés réservés. Il les cache intentionnellement du schema du tool qui est envoyé au modèle de langage. Le modèle ne les voit jamais. Il voit uniquement les arguments qu'il est censé fournir. Ça veut dire que le modèle ne peut pas halluciner une fausse configuration ou essayer de contourner tes limites de sécurité.
Prenons un scénario concret. Tu construis un tool get account info pour une application bancaire. Le tool a besoin d'un user ID pour récupérer les bons enregistrements en base de données. Si le modèle fournit cet ID, une prompt injection astucieuse pourrait piéger le modèle et lui faire demander les données d'un tout autre client. Au lieu de ça, tu conçois ta fonction de tool pour accepter deux arguments. Le premier est le type de compte, que le modèle va fournir. Le second est un argument nommé runtime.
Dans le code principal de ton application, avant que le tool soit invoqué, tu remplis cet objet runtime. Plus précisément, tu utilises la propriété runtime point context. Tu places le vrai user ID authentifié de la personne qui fait la requête directement dans ce context. Tu pourrais aussi y placer une connexion active à la base de données ou l'adresse d'un endpoint régional.
Le modèle évalue la requête de l'utilisateur et décide d'appeler le tool get account info. Il regarde le schema, voit qu'il doit fournir un type de compte, et sort le mot savings. Il ne sort rien d'autre. LangChain intercepte cet appel d'exécution. Il prend le type de compte du modèle, le combine de façon transparente avec le runtime context de ton backend, et exécute la fonction Python. À l'intérieur de la fonction, tu extrais le user ID du context et tu lances ta requête de base de données de façon sécurisée.
Ce mécanisme t'offre une injection de dépendances sécurisée. Tu peux injecter tout ce dont ton tool a besoin pour fonctionner et que le modèle n'a pas à connaître. Les clés d'API pour des services de facturation tiers, les chemins du file system, ou les identifiants de tenant dans une architecture multi-tenant ont tous leur place dans le runtime context.
Voici l'idée clé. Cacher les arguments de configuration derrière le runtime context garantit que ton modèle agit purement comme un routeur logique, pendant que le code de ton application garde un contrôle absolu et sans compromis sur l'accès aux données et la sécurité d'exécution.
Merci d'avoir passé quelques minutes avec moi. À la prochaine, et prends soin de toi.
7
Persistance au niveau du thread
3m 37s
Nous abordons la mémoire à court terme et la manière de conserver l'historique des conversations. Vous apprendrez comment attacher des checkpointers à votre agent pour permettre aux conversations d'être mises en pause, reprises et mémorisées.
Salut, ici Alex de DEV STORIES DOT EU. LangChain v1.0 Orchestration Framework, épisode 7 sur 20. Sans mémoire, chaque interaction avec ton agent IA ressemble à une scène de 50 First Dates. Le modèle redémarre complètement à zéro, oubliant tout ce dont tu as discuté quelques secondes auparavant. La solution : la persistance au niveau du thread.
Les grands modèles de langage sont totalement stateless. Ils traitent du texte et renvoient du texte, sans absolument rien conserver entre les requêtes. Pour tenir une conversation, un agent a besoin d'un moyen de stocker et de récupérer les interactions passées. Dans le cadre d'une seule session active, on gère ça grâce à la mémoire à court terme, qui fait partie du state de l'agent et qui est persistée à l'aide de checkpointers.
On imagine souvent que la mémoire en IA est une sorte de capacité interne du modèle, où le réseau neuronal se souvient de toi par magie. Ce n'est pas le cas. La mémoire, c'est juste l'historique des messages. La persistance au niveau du thread consiste simplement à prendre la liste des messages en cours, à la sauvegarder dans une base de données après chaque étape, puis à la réinjecter dans le prompt avant que le modèle ne reçoive le prochain input. Le checkpointer gère ça automatiquement, ce qui t'évite d'écrire manuellement la logique de stockage et de récupération.
Dans LangGraph, le state est sauvegardé par thread. Un thread représente une session continue. Pour activer ça, tu as besoin d'un checkpointer. Pour le développement et les tests, tu peux utiliser le In Memory Saver. Quand tu compiles ton graph d'agent, tu passes cet objet saver comme argument checkpointer. Cette intégration indique à l'agent qu'à la fin de chaque exécution de node, il doit faire un snapshot de son state actuel et le transmettre au saver. Le state inclut tout ce que tu as défini dans ton graph, ce qui est généralement une liste de messages en cours.
Prenons un scénario concret. Tu compiles ton agent avec un In Memory Saver. Maintenant, tu veux invoquer l'agent. Au lieu de juste passer un message utilisateur, tu passes aussi un objet de configuration contenant un thread ID spécifique. Utilisons la valeur string conversation un. Tu envoies le message, je m'appelle Bob. L'agent le reçoit, génère une salutation polie et termine. En coulisses, le checkpointer sauvegarde le state mis à jour, qui contient désormais le message indiquant que tu t'appelles Bob, indexé sous conversation un.
Plus tard, tu invoques l'agent une deuxième fois. Tu envoies un nouveau message pour demander, quel est mon nom. Point crucial : tu passes exactement le même objet de configuration avec le thread ID conversation un.
Voici l'explication clé. Avant que l'agent ne route ta nouvelle question vers le modèle, le checkpointer intercepte le processus. Il cherche conversation un dans le In Memory Saver. Il récupère le snapshot du state de ton tour précédent, charge l'historique des messages sauvegardés et ajoute ta nouvelle question à la fin. Le modèle de langage reçoit le contexte historique complet, voit le message précédent où tu t'es présenté, et répond avec succès que tu t'appelles Bob.
Si tu changeais le thread ID pour conversation deux et que tu demandais ton nom, le checkpointer chercherait ce nouvel ID, ne trouverait aucun state existant et initialiserait une nouvelle liste de messages vide. L'agent n'aurait aucune idée de qui tu es. Le thread ID est la seule clé qui relie une séquence d'appels de modèle isolés et stateless en une session de mémoire à court terme cohérente.
Le checkpointer abstrait le travail répétitif de gestion des arrays de messages et d'interrogation des bases de données, garantissant que ton agent peut reprendre son travail exactement là où il s'est arrêté, tant que tu fournis le bon thread ID.
Merci pour ton écoute — à la prochaine.
8
Compresser le contexte avec un Middleware
3m 20s
Nous explorons comment empêcher les longues conversations de faire planter votre modèle. Vous apprendrez à utiliser le SummarizationMiddleware pour compresser automatiquement les anciens messages et économiser des tokens.
Salut, c'est Alex de DEV STORIES DOT EU. LangChain v1.0 Orchestration Framework, épisode 8 sur 20. Plus une conversation dure, plus un large language model est perturbé par des informations obsolètes. Tu perds en précision tout en payant des coûts en tokens plus élevés à chaque tour. Compresser le contexte avec un middleware résout exactement ce problème.
À mesure que l'historique du chat s'allonge, tu finis par atteindre la limite de la context window de ton modèle. Même avant d'atteindre cette limite stricte, injecter des milliers de tokens d'anciennes conversations dégrade les performances. La solution, c'est le SummarizationMiddleware dans LangChain. Au lieu de simplement couper les anciens messages, il les compresse en un seul bloc de résumé. Ça préserve le sens sémantique de la conversation sans l'énorme surcharge de tokens.
Il y a une idée reçue très courante sur la façon dont ça tourne. Les gens pensent souvent que l'agent principal doit faire le résumé lui-même. Ce n'est pas le cas, et ça ne devrait vraiment pas l'être. Tu veux que ton agent principal tourne sur ton modèle le plus intelligent et le plus performant pour gérer la logique complexe. Le résumé est une tâche beaucoup plus simple. Tu assignes un modèle plus petit et moins cher au SummarizationMiddleware exclusivement pour ce job.
Configurer le middleware nécessite de définir deux paramètres principaux. Le premier, c'est le trigger. Le trigger indique au middleware quand intervenir. Tu pourrais configurer le trigger pour qu'il s'active dès que le nombre total de tokens de la conversation atteint 4000. Le deuxième paramètre, c'est la condition keep. Ça indique au middleware quelle quantité de contexte récent laisser complètement intacte. Tu pourrais définir la valeur keep à 20, ce qui signifie que les 20 messages les plus récents restent intacts.
Voici le flux logique en pratique. Ton utilisateur discute avec l'agent principal. La conversation s'allonge. Au tour suivant, l'historique total des messages dépasse le seuil des 4000 tokens. Avant même que l'agent principal ne voie le nouvel input de l'utilisateur, le SummarizationMiddleware intercepte la requête. Il scanne l'historique et identifie tout ce qui est plus ancien que les 20 messages les plus récents. Il prend ce vieux morceau de conversation et le transmet à ton modèle plus petit dédié. Disons que tu as configuré le middleware pour utiliser gpt-4.1-mini.
Ce petit modèle lit les anciens messages et génère un paragraphe concis qui résume ce qui a été dit. Le middleware réécrit ensuite l'array d'historique. Il remplace tous ces anciens messages individuels par un seul system message contenant le nouveau résumé. S'il y avait déjà un ancien résumé issu d'un cycle de compression précédent, le middleware l'inclut dans le prompt pour que le nouveau résumé mette à jour la narration en cours.
Le paquet final envoyé à ton agent principal est hautement optimisé. Il contient le nouveau message de résumé, suivi des 20 messages récents non compressés, puis du dernier input de l'utilisateur.
Voici le point clé. L'agent principal ne se rend jamais compte que l'historique a été compressé en arrière-plan. Il reçoit juste une context window propre et ultra pertinente. Tu préserves le sens sémantique à long terme du chat, tu gardes le modèle concentré, et tu réduis considérablement tes coûts en tokens à chaque tour suivant.
Si tu trouves ces épisodes utiles et que tu veux soutenir l'émission, tu peux chercher DevStoriesEU sur Patreon. C'est tout pour cette fois. Merci d'avoir écouté, et continue de développer !
9
Formats de données garantis
3m 20s
Nous discutons de la manière de forcer les modèles de langage à renvoyer des structures de données strictes et prévisibles. Vous apprendrez la différence entre ProviderStrategy et ToolStrategy pour générer des modèles Pydantic.
Salut, c'est Alex de DEV STORIES DOT EU. LangChain v1.0 Orchestration Framework, épisode 9 sur 20. Développer un logiciel qui s'appuie sur le parsing de réponses en langage naturel avec des expressions régulières est une véritable bombe à retardement. Tu demandes un data object simple à un modèle de langage, et il te fournit des données parfaites, sauf qu'il ajoute une formule de politesse au début et qu'il wrappe le tout dans du formatage markdown. Ton parser plante instantanément. Les Guaranteed Data Formats sont la solution définitive à ce problème.
Le structured output oblige le modèle de langage à renvoyer les informations exactement comme ton application l'attend. Ça transforme une génération de texte imprévisible en objets logiciels fiables. Prends l'exemple d'un système qui traite les messages entrants du support client. Un utilisateur envoie un paragraphe brouillon et non structuré pour se plaindre d'un problème de login, en noyant son nom, son adresse e-mail et son numéro de téléphone quelque part dans le texte. Tu as besoin de ces trois données pour déclencher une recherche dans la base de données.
Au lieu d'écrire un prompt complexe pour supplier le modèle de formater correctement sa réponse, tu définis un modèle Pydantic standard. Tu crées une classe appelée ContactInfo et tu définis name, email et phone comme des required fields. Ensuite, il te suffit de passer ce schéma Pydantic au paramètre response format de la configuration de ton modèle de langage. Tu n'as pas besoin de fournir d'exemples ni d'écrire des scripts de validation custom.
C'est ça le plus important. Quand tu fournis ce schéma Pydantic, LangChain détermine automatiquement la méthode la plus fiable pour l'appliquer. Il fait ça en choisissant discrètement entre deux chemins d'exécution différents.
D'abord, il vérifie si le modèle de langage que tu as choisi possède une feature officielle de structured output intégrée à son API. Si c'est le cas, LangChain auto-sélectionne la Provider Strategy. Cette stratégie pousse ton schéma directement vers le provider, en exploitant ses contraintes natives côté serveur pour garantir le format de l'output.
Mais le hardware change et les modèles sont parfois remplacés. Si tu décides d'utiliser un modèle différent qui n'a pas de structured output natif, LangChain détecte ce manque. Il fait automatiquement un fallback sur la Tool Strategy. Sous le capot, il traduit ton schéma ContactInfo en une signature de fonction. Il parle au modèle d'un faux tool qui nécessite exactement un name, un email et un phone number pour s'exécuter. Le modèle tente d'appeler ce tool, et en faisant ça, génère les arguments structurés exacts dont tu as besoin. Le code de ton application n'a jamais besoin de changer pour s'adapter à ce remplacement.
Quand l'opération est terminée, les développeurs cherchent souvent leurs données au mauvais endroit. Tu pourrais supposer que l'output est renvoyé sous forme de texte brut que tu dois encore parser. Ce n'est pas du texte brut. LangChain intercepte le payload et instancie l'objet Pydantic pour toi. Il place cet objet Python entièrement validé directement dans le state de ton application. Tu le trouveras capturé dans la key structured response de ton state dictionary. Tu as juste à référencer cette key, et tu obtiens immédiatement ton objet ContactInfo, avec des champs type-safe prêts à être passés au reste de ton application.
En déplaçant la charge de la validation du schéma depuis la logique de parsing custom vers la couche du framework, les intégrations de ton modèle de langage deviennent aussi prévisibles qu'un call API standard.
Merci de ton écoute — à la prochaine.
10
Intercepter la boucle de l'agent
2m 57s
Nous introduisons le paradigme du middleware, vous donnant un contrôle chirurgical sur l'exécution de votre agent. Vous apprendrez à utiliser les hooks wrap-style et node-style pour intercepter les appels de modèles.
Salut, c'est Alex de DEV STORIES DOT EU. LangChain v1.0 Orchestration Framework, épisode 10 sur 20. Si ton agent plante silencieusement en production, c'est souvent parce que tu ne surveilles pas ce qui se passe entre les étapes de sa boucle de raisonnement. Le modèle crashe, la boucle s'arrête, et tu te retrouves devant un run incomplet. Intercepter la boucle de l'agent avec un middleware custom, c'est comme ça que tu reprends le contrôle.
Quand un agent exécute un cycle ReAct, il passe constamment le contrôle au modèle de langage, puis le récupère. Le middleware fournit des hooks pour exécuter ta logique exactement quand tu en as besoin pendant cet échange. Il y a deux types principaux de hooks que tu vas utiliser : les hooks de type node et les hooks de type wrap. Une erreur classique, c'est de les traiter de manière interchangeable. Les hooks de type node s'exécutent de façon séquentielle. Les hooks de type wrap englobent vraiment l'exécution et peuvent catch les exceptions.
Les hooks de type node utilisent des décorateurs appelés before model et after model. Quand tu attaches un hook before model à une fonction, le framework exécute complètement ta logique, et c'est seulement après qu'il déclenche l'API du modèle de langage. Quand le modèle répond, un hook after model s'exécute. Ces hooks sont excellents pour logger le prompt exact envoyé à l'API, injecter du contexte, ou nettoyer les mauvais caractères de l'output texte final. Mais comme ils s'exécutent strictement en séquence, ils n'offrent aucune protection contre les échecs. Si l'API du modèle de langage tombe en timeout, ton hook after model ne s'exécute jamais. L'erreur remonte et fait crasher toute la boucle de l'agent.
C'est là que ça devient important. Si tu as besoin de gérer l'instabilité, tu utilises un hook de type wrap. Le décorateur pour ça, c'est wrap model call. Un hook wrap englobe entièrement l'exécution du modèle. Ta fonction s'exécute, fait un peu de setup, puis cède explicitement le contrôle au modèle. Comme ton code custom wrap le vrai appel réseau, tu peux placer cette exécution à l'intérieur de structures de gestion d'erreurs standards.
Imagine que tu construises un middleware wrap model call pour gérer les rate limits de l'API avec une boucle de retry en exponential backoff. Tu écris une fonction décorée avec wrap model call. À l'intérieur de cette fonction, tu crées une boucle de retry. Tu places la commande qui passe le contrôle au modèle dans un bloc try. Si le modèle réussit, tu récupères la réponse, tu la retournes, et la boucle se termine. Si le modèle throw une erreur, ton bloc catch l'intercepte. Au lieu de faire planter l'agent, ton bloc catch déclenche une pause. Tu calcules un court délai, tu attends, puis tu laisses la boucle retenter l'appel, en doublant le délai à chaque fois.
L'orchestrateur de l'agent ne voit jamais les échecs. Le middleware catch les exceptions, gère la logique de retry de manière isolée, et renvoie en douceur une réponse réussie à la boucle ReAct principale quand ça finit par marcher.
Les hooks de type node préparent les inputs et formatent les outputs, mais les hooks de type wrap protègent l'exécution. C'est tout pour cet épisode. À la prochaine !
11
Ingénierie de contexte dynamique
3m 44s
Nous plongeons dans l'ingénierie de contexte en générant dynamiquement des prompts système. Vous apprendrez à utiliser un middleware pour modifier les instructions en fonction du rôle de l'utilisateur actuel et de son environnement.
Salut, c'est Alex de DEV STORIES DOT EU. LangChain v1.0 Orchestration Framework, épisode 11 sur 20. La raison numéro un pour laquelle ton agent échoue, ce n'est pas parce que le modèle sous-jacent est stupide. C'est parce que tu lui as donné le mauvais contexte pour le job. Si ton système traite un superuser et un guest exactement de la même manière, ton application est aveugle à la réalité. Pour corriger ça, on utilise le Dynamic Context Engineering.
D'abord, clarifions une idée reçue très courante sur la façon dont les prompts sont construits. Le contexte dynamique, ce n'est pas le system prompt de base que tu écris quand tu définis initialement ton agent dans le code. Ce system prompt initial est complètement statique. Le Dynamic Context Engineering, c'est le processus qui consiste à modifier ce prompt à la volée, juste quelques millisecondes avant que le modèle ne soit réellement appelé. Le context engineering, c'est le fait de donner au modèle de langage les règles exactes dont il a besoin pour un utilisateur spécifique à un moment précis, et rien de plus.
Si tu essaies de fourrer toutes les règles possibles dans un seul prompt statique massif — en disant au modèle comment agir si l'utilisateur est un admin, comment agir si c'est un viewer, et comment agir si on est mardi — tu gaspilles des tokens et tu embrouilles le modèle. Au lieu de ça, tu veux injecter dynamiquement uniquement les règles qui comptent sur le moment.
Dans LangChain, c'est géré en utilisant un décorateur spécifique appelé dynamic underscore prompt. Tu places ce décorateur au-dessus d'une fonction Python que tu définis. Quand ton application reçoit une query et déclenche la chain, LangChain se met en pause. Il cherche toute fonction encapsulée dans ce décorateur et l'exécute avant de parler au modèle.
À l'intérieur de ta fonction décorée, tu as besoin d'un moyen de savoir ce qui se passe actuellement. C'est là que tu lis depuis request dot runtime dot context. Cet objet context est essentiellement un dictionnaire. Il contient toutes les métadonnées en temps réel passées à la chain quand tu l'as invoquée. Tu peux y mettre tout ce que tu veux depuis le backend de ton application, comme des user IDs, des session states, des feature flags ou des niveaux d'accès.
Regardons un scénario concret. Tu écris une fonction appelée context aware prompt et tu l'encapsules avec le décorateur dynamic prompt. À l'intérieur de cette fonction, tu lis le rôle de l'utilisateur depuis le runtime context. Tu vérifies le rôle. Si l'utilisateur est un admin, ta fonction ajoute un bloc de texte spécifique au system prompt, indiquant au modèle de langage qu'il a la permission totale de renvoyer des commandes destructrices. Si l'utilisateur est un viewer, ta fonction ajoute un bloc de texte différent, avec des instructions strictes précisant que le modèle doit uniquement renvoyer des résumés en read-only et ne doit jamais suggérer de changements de configuration.
Maintenant, tu récupères une deuxième donnée depuis le runtime context, qui est l'état de l'environnement. Tu vérifies si l'environnement est défini sur production. Si c'est le cas, ta fonction ajoute un avertissement de sécurité sévère tout à la fin du system prompt, exigeant que le modèle revérifie la sécurité de son output. Si l'environnement est juste en staging, tu n'ajoutes pas du tout cet avertissement.
Voici l'idée clé. Ta fonction prend le base prompt statique, y colle les règles admin ou viewer, ajoute l'avertissement de production si besoin, et retourne la string finale. LangChain prend cette string entièrement assemblée et l'envoie au modèle de langage. Le modèle de langage ne sait jamais que le prompt a été assemblé de toutes pièces. Il voit juste un ensemble d'instructions ultra-spécifiques et parfaitement sur mesure. En faisant ça, tu gardes tes system prompts légers, précis et complètement pertinents pour la requête immédiate.
Tu arrêtes d'espérer que le modèle devinera quelles règles s'appliquent, et tu commences à imposer exactement les règles requises pour l'état actuel de ton application.
Je voudrais prendre un moment pour te remercier de ton écoute — ça nous aide beaucoup. Passe une excellente journée !
12
IA sécurisée avec des garde-fous déterministes
3m 44s
Nous sécurisons nos agents contre les fuites de données en utilisant un middleware intégré. Vous apprendrez à appliquer le PIIMiddleware pour masquer automatiquement les informations sensibles avant qu'elles n'atteignent le modèle.
Bonjour, ici Alex de DEV STORIES DOT EU. LangChain v1.0 Orchestration Framework, épisode 12 sur 20. Un simple chat log contenant un numéro de carte de crédit non masqué peut instantanément compromettre la conformité de toute ton application. Tu ne peux pas compter sur un modèle de langage pour ignorer poliment les données sensibles, et lui demander de s'autocensurer est lent et imprévisible. C'est là qu'intervient la Safe AI avec des garde-fous déterministes.
Les garde-fous déterministes sont des vérifications hardcodées, basées sur des règles. Ils s'appuient sur des patterns et une logique prévisibles, comme des expressions régulières ou des algorithmes fixes, au lieu de demander à un autre modèle de langage d'évaluer le texte. Comme ils évitent l'appel réseau vers une IA, ils s'exécutent en quelques millisecondes et ne coûtent pratiquement rien. Si tu développes pour la production, cette couche déterministe est obligatoire pour la sécurité.
Dans le framework, tu implémentes ça en utilisant le PII Middleware. Une erreur fréquente que font les développeurs, c'est d'essayer de filtrer les informations sensibles après coup, en scannant l'output du modèle. Mais pour protéger la vie privée des utilisateurs, le PII Middleware est conçu pour intercepter le message brut au moment même où l'utilisateur clique sur envoyer. Il traite le texte avant même que le call au modèle ne soit initié. Tu configures explicitement ce comportement en passant le paramètre apply to input sur true.
Prenons le scénario d'un agent de service client. Un utilisateur stressé envoie un message pour dire que son compte est bloqué, en incluant son adresse e-mail personnelle, puis il colle l'intégralité de son numéro de carte de crédit à seize chiffres pour vérifier son achat. Si ton code passe cette string brute à un provider d'IA tiers, tu violes la conformité de base des données. Tu as besoin d'une stratégie pour neutraliser le texte, et le middleware te donne trois actions intégrées : block, redact, et mask.
Si tu utilises la stratégie block, le middleware agit comme un mur infranchissable. Dès qu'il détecte le format de la carte de crédit, il lève une erreur stricte et termine complètement la chain. La requête est purement et simplement rejetée.
Si tu choisis la stratégie redact, le middleware supprime chirurgicalement les données spécifiques et insère un placeholder propre. L'adresse e-mail personnelle est complètement effacée de la string et remplacée par le mot email entre crochets. Le modèle de langage lit toujours une phrase cohérente et comprend qu'un e-mail a été fourni, mais les vraies données ont disparu.
La troisième stratégie, c'est mask. Le masking conserve une portion sûre des données d'origine. Le middleware remplace les douze premiers chiffres de la carte de crédit par des astérisques, ne laissant que les quatre derniers numéros exposés. C'est super efficace quand ton système backend a besoin de vérifier un compte sans exposer tout le dossier financier.
Implémenter ça nécessite de configurer le middleware avant que ta chain ne s'exécute. Tu instancies le PII Middleware et tu lui fournis une liste d'entités cibles. Dans ce cas, tu spécifies email et credit card. Tu assignes ensuite les stratégies de ton choix à ces entités, en choisissant peut-être redact pour l'email et mask pour la carte. Enfin, tu attaches ce composant middleware à ta chain principale, en t'assurant de régler le paramètre apply to input. Au moment où l'utilisateur soumet son message, les règles déterministes nettoient le texte, et l'IA ne reçoit qu'un prompt nettoyé.
Voici l'idée clé. La façon la plus sécurisée de gérer les informations personnelles sensibles dans n'importe quelle architecture d'IA générative, c'est de garantir que le modèle de langage ne les voie jamais en premier lieu. C'est tout pour cet épisode. Merci d'avoir écouté, et continue de builder !
13
Mise en pause pour approbation humaine
3m 41s
Nous explorons l'exécution d'outils à fort enjeu en ajoutant un humain dans la boucle. Vous apprendrez comment interrompre l'exécution d'un agent pour approuver, modifier ou rejeter des actions sensibles.
Bonjour, c'est Alex de DEV STORIES DOT EU. LangChain v1.0 Orchestration Framework, épisode 13 sur 20. Un agent autonome est incroyablement puissant, jusqu'au moment où il envoie tout seul par e-mail un brouillon de tes données financières au mauvais client. Certaines actions sont tout simplement trop risquées pour être exécutées sans un regard humain. C'est exactement pour ça qu'on utilise le Pausing for Human Approval.
Les agents exécutent des tools automatiquement en fonction des prompts de l'utilisateur. Ce comportement est idéal pour lire de la data, mais il est dangereux pour des actions destructrices ou irréversibles. On a besoin d'un moyen de mettre l'exécution en pause, de demander à un humain si une action est safe, puis de reprendre ou d'annuler.
Avant de parler de la mécanique, on doit clarifier une erreur très courante. Parfois, les ingénieurs configurent des interrupts et se demandent ensuite pourquoi l'agent crashe ou redémarre. Tu dois absolument avoir un checkpointer activé. Tu ne peux pas mettre un agent en pause s'il ne peut pas se rappeler où il s'est arrêté. Toute la mémoire de l'agent et sa progression actuelle doivent être sauvegardées dans la persistence layer pendant qu'il attend qu'un humain réponde. Sans checkpointer, pas de pause.
Avec la persistance activée, tu peux gérer l'exécution des tools en toute sécurité en utilisant le middleware Human In The Loop. Imagine une configuration où ton agent a deux tools : un tool de recherche et un tool de suppression de base de données. Tu veux que l'agent fasse des recherches librement, mais tu ne veux absolument pas qu'il drop des tables sans permission.
Quand tu configures ce middleware, tu définis un argument appelé interrupt on. Tu lui passes les noms spécifiques des tools qui nécessitent une supervision. Dans notre scénario, tu configures interrupt on pour surveiller uniquement le tool de suppression de base de données. Le tool de recherche est ignoré par le middleware et s'exécute immédiatement à chaque fois que l'agent l'appelle. Cependant, quand l'agent décide qu'il a besoin d'utiliser le tool de suppression de base de données, le middleware intercepte la requête. Il met le graph en pause, sauvegarde l'état actuel dans ton checkpointer, et stoppe complètement l'exécution.
Le graph est maintenant suspendu dans la persistence layer, en attente d'une intervention humaine. L'opérateur humain examine le tool call en attente et a trois façons de répondre au middleware.
La première décision possible est approve. L'humain regarde les paramètres que l'agent a générés, confirme qu'ils sont corrects, et envoie une commande d'approbation. Le graph se réveille et exécute la suppression exactement comme l'agent l'avait prévu au départ.
La deuxième décision possible est reject. L'opérateur voit que l'agent essaie de supprimer la mauvaise cible et envoie un rejet. Le tool ne s'exécute pas. À la place, l'agent reçoit une observation indiquant que l'action a été bloquée par un humain. L'agent traite ensuite ce feedback et peut soit essayer une approche différente, soit demander des précisions à l'utilisateur.
Voici le point clé. La troisième option est edit. Parfois l'agent a presque tout bon mais fait une erreur mineure, comme cibler l'environnement de production au lieu de l'environnement de staging. Plutôt que de rejeter complètement l'action et de forcer l'agent à raisonner de nouveau sur le problème, l'opérateur peut modifier directement les paramètres d'entrée du tool. L'humain remplace l'environnement cible par le staging, et soumet le call corrigé. L'agent reprend et exécute l'action en utilisant les paramètres modifiés, et continue sans problème.
En utilisant ce middleware, tu protèges ton système des erreurs dangereuses. Faire une pause pour approbation humaine ne fait pas qu'éviter des catastrophes, ça transforme ton agent d'une entité imprévisible en un collaborateur supervisé qui peut gérer des opérations à haut risque en toute sécurité.
C'est tout pour cet épisode. Merci de ton écoute, et continue de développer !
14
Retour d'information de l'agent en temps réel
2m 47s
Nous plongeons dans le streaming pour améliorer considérablement l'expérience utilisateur. Vous apprendrez à interpréter les modes de stream pour afficher les tokens du LLM en direct aux côtés des mises à jour d'exécution d'outils personnalisés.
Salut, c'est Alex de DEV STORIES DOT EU. LangChain v1.0 Orchestration Framework, épisode 14 sur 20. Ça ne dérange pas les utilisateurs d'attendre dix secondes pour une réponse complexe, tant que tu leur montres ce que le cerveau fait pendant ces dix secondes. Un écran blanc donne l'impression d'une application cassée. La solution à la latence perçue, c'est le feedback en temps réel de l'agent.
Pour corriger l'écran blanc, LangChain expose un paramètre appelé stream mode quand tu exécutes ton agent ou ton graph. Il contrôle exactement quel type de données l'agent renvoie sur la connexion pendant qu'il tourne. Le premier mode que tu dois connaître, c'est le mode messages. C'est lui qui gère l'effet de typing classique. Il stream les tokens bruts du language model au fur et à mesure qu'ils sont générés. Si le modèle écrit un paragraphe, ton application reçoit les chunks de texte un par un, ce qui permet à ton interface utilisateur de se mettre à jour de façon fluide au lieu d'attendre le bloc de texte entier.
On confond souvent le streaming des tokens de la réponse finale avec le streaming du raisonnement intermédiaire. C'est vraiment complètement différent. Si ton agent décide d'appeler un search tool, la génération de tokens s'arrête. Le language model attend que l'outil se termine. Si cet outil met cinq secondes à tourner, ton interface utilisateur freeze pendant cinq secondes. Le mode messages tout seul ne dit pas à l'utilisateur ce que l'agent fait vraiment en background. Il montre seulement ce que le language model est en train de dire.
Pour résoudre le problème de l'outil silencieux, tu utilises le mode custom. Le mode custom permet à tes outils et à tes nodes internes d'émettre leurs propres mises à jour de statut en temps réel directement dans le stream. Pour implémenter ça, tu utilises un utilitaire LangChain qui s'appelle get stream writer. Tu appelles cette fonction dans le code de ton outil. Elle te donne un objet writer, que tu peux utiliser pour émettre des custom events vers le client à n'importe quel moment pendant l'exécution de l'outil.
Imagine un outil de météo un peu lent. Ton agent reçoit un prompt qui demande les prévisions et décide d'appeler l'outil météo. À l'intérieur de la fonction Python pour cet outil, tu récupères le stream writer. Au moment où l'outil commence à requêter une API distante un peu lente, tu utilises le writer pour émettre un custom event avec un statut comme Acquired data. Ton frontend reçoit ce custom event immédiatement et affiche un loading spinner avec ce texte. L'utilisateur sait que l'agent est en train de travailler. Une fois que l'API distante renvoie les données, l'outil se termine et le language model reprend le contrôle. Il prend les données météo brutes, formule une réponse naturelle pour l'humain, et le stream de messages reprend, en tapant les prévisions finales à l'écran.
Voici le point clé. Tu n'es pas obligé de choisir un seul mode. Tu peux passer une liste contenant à la fois messages et custom au paramètre stream mode. LangChain va automatiquement entrelacer les tokens du language model et les logs de ton outil custom dans un seul feed continu. Ton frontend vérifie juste le type d'événement quand il arrive. Si c'est un custom event, tu mets à jour l'indicateur de statut. Si c'est un message event, tu ajoutes le token à la bulle de chat. La latence perçue tombe à zéro parce que le système parle en permanence à l'utilisateur.
Si tu veux aider à ce que ces épisodes continuent, tu peux soutenir l'émission en cherchant DevStoriesEU sur Patreon. Merci d'avoir écouté, et happy coding à tous !
15
Persistance inter-sessions
3m 17s
Nous explorons la mémoire à long terme pour construire des agents qui connaissent vraiment leurs utilisateurs. Vous apprendrez à utiliser les stores LangGraph pour sauvegarder des documents JSON à travers des conversations entièrement différentes.
Salut, c'est Alex de DEV STORIES DOT EU. LangChain v1.0 Orchestration Framework, épisode 15 sur 20. Pour créer un assistant vraiment personnalisé, il doit se souvenir que tu préfères les réponses brèves, même si tu le lui as dit il y a trois semaines dans un chat complètement différent. Si tu te reposes uniquement sur la mémoire de conversation standard, cette préférence disparaît dès que tu commences un nouveau thread. Le mécanisme qui empêche cette amnésie, c'est la Cross-Session Persistence en utilisant le paradigme de Store.
Beaucoup de développeurs confondent le checkpointer avec le store. Voici la différence. Un checkpointer gère le state à court terme. Il mémorise un seul thread de conversation. Quand l'utilisateur crée un nouveau chat, le checkpointer repart de zéro. Le store traverse ces frontières de thread. Il permet à tes agents de persister et de récupérer des informations globalement, à travers toutes les interactions avec un utilisateur spécifique.
À la base, la mémoire à long terme dans LangChain est juste un store key-value hiérarchique. Elle persiste des documents JSON. La hiérarchie repose sur des namespaces. Un namespace est une séquence de strings qui agit exactement comme un chemin de dossier sur ton ordinateur. Si tu veux stocker des données de profil, tu pourrais utiliser un namespace contenant la string users, suivi de l'identifiant de l'utilisateur. À l'intérieur de ce namespace, tu stockes des items. Chaque item nécessite une key unique sous forme de string, et un dictionnaire représentant la valeur JSON.
C'est là que ça devient intéressant. Les tools interagissent avec ce store directement via le runtime context. Tu ne passes jamais le store manuellement à travers le state de ton graph.
Prends l'exemple d'un custom tool nommé save user info. Son job est de capturer une préférence de langue parlée. Pendant le setup, tu initialises ton application avec un store en backend, comme un in-memory store pour les tests locaux. Dans la logique de ton tool, tu accèdes directement à l'instance du store depuis la configuration runtime injectée. Tu extrais l'identifiant de l'utilisateur depuis le contexte actuel. Ensuite, tu appelles la méthode put sur le store. Tu fournis le tuple du namespace contenant le mot users et l'ID utilisateur. Tu définis une key, comme language preference, et enfin tu passes le dictionnaire JSON contenant la valeur, disons Spanish.
Le store persiste ce document. Des semaines plus tard, l'utilisateur commence une toute nouvelle conversation. Le state du thread est vide. Mais comme l'agent a accès à un retrieval tool, il peut appeler la méthode get sur le runtime store en utilisant exactement le même namespace et la même key. Il récupère le document JSON, lit la préférence, et répond immédiatement en espagnol.
Séparer le contexte conversationnel à court terme de la mémoire factuelle à long terme permet de garder ton application légère. Le checkpointer ne s'alourdit pas avec des années d'historique utilisateur, et le state reste propre. Le store charge uniquement les documents JSON spécifiques que l'agent décide explicitement de fetch.
Traiter le contexte et la persistance comme deux systèmes entièrement distincts est la seule façon de scaler un agent de manière fiable. Le checkpointer contient le présent, tandis que le store contient le passé.
C'est tout pour aujourd'hui. Merci d'avoir écouté — va construire un truc cool.
16
Le paradigme multi-agents
4m 07s
Nous expliquons pourquoi les agents uniques échouent et introduisons l'architecture des Subagents. Vous apprendrez comment un agent superviseur principal coordonne des sous-agents en tant que fenêtres de contexte isolées pour éviter la surcharge de tokens.
Bonjour, ici Alex de DEV STORIES DOT EU. LangChain v1.0 Orchestration Framework, épisode 16 sur 20. Quand ton agent d'IA unique commence à planter à cause de sa propre liste massive de tools et d'instructions contradictoires, lui balancer une context window plus grande ne règlera pas le problème. Il est temps d'arrêter de coder un script monolithique et de commencer à recruter une équipe. C'est exactement là qu'intervient le paradigme multi-agents.
On construit des systèmes multi-agents parce que les agents uniques se heurtent à un mur cognitif. Donne à un agent trente tools, cinq pages de system prompts et un long historique de conversation, et il va perdre le fil. Il va appeler le mauvais tool ou oublier des contraintes. L'approche multi-agents découpe tout ça. Elle permet un développement distribué où différentes équipes gèrent différents agents. Elle autorise l'exécution en parallèle. Et surtout, elle impose une stricte context isolation.
Aujourd'hui, on se concentre sur une architecture spécifique appelée le pattern Subagents. Ça implique un agent superviseur principal qui délègue des tâches à des subagents spécialisés. On confond souvent un superviseur avec un simple router. Un router n'est qu'une fonction statique qui regarde une query et l'envoie sur un chemin fixe. Un superviseur est un agent actif qui réfléchit. Il maintient le state de la conversation, décide quels subagents invoquer sur plusieurs tours, et synthétise leurs réponses.
Voici l'idée clé. Les subagents offrent une parfaite context isolation. Quand le superviseur demande à un subagent de faire quelque chose, le subagent démarre avec une context window complètement vierge. Il n'a que les instructions et les tools spécifiques dont il a besoin pour son job exact. Le subagent peut faire des erreurs, appeler des tools trois fois, et remplir son propre scratchpad pendant qu'il cherche la réponse. Le superviseur ne voit jamais ce bazar. Il reçoit uniquement le résultat final nettoyé. Ça protège ton agent principal du context bloat et empêche les hallucinations.
Pour connecter le superviseur aux subagents, tu wrap les subagents comme des tools. Il y a deux façons de faire ça dans LangChain. La première méthode, c'est le tool-per-agent. Tu donnes au superviseur un tool spécifique pour chaque subagent. Si tu as cinq subagents, le superviseur a cinq tools. La deuxième méthode, c'est un single-dispatch tool. Là, le superviseur obtient exactement un seul tool qui s'appelle quelque chose comme delegate task. Ce tool nécessite deux inputs : le nom de l'agent cible et la description de la tâche.
Prends un scénario single-dispatch. Tu as un agent principal, un agent de recherche et un agent de rédaction. Un utilisateur demande un rapport de marché complexe. L'agent principal décide qu'il a d'abord besoin de données. Il appelle le single dispatch tool, en passant l'agent de recherche comme cible et la market query comme payload. L'agent de recherche spin up dans son propre context isolé, cherche sur le web, parse des documents, et retourne un paragraphe de résumé. L'agent principal reçoit ce texte. Ensuite, l'agent principal appelle à nouveau le dispatch tool, cette fois en ciblant l'agent de rédaction, en passant le résumé de la recherche et les instructions de formatage. L'agent de rédaction rédige le rapport final et le retourne à l'agent principal, qui le livre à l'utilisateur.
Tu peux exécuter ces sous-tâches différemment selon tes besoins. Tu peux exécuter les subagents de manière synchrone, où le superviseur attend que l'agent de recherche ait terminé avant de faire quoi que ce soit d'autre. Si tu as des tâches indépendantes, comme faire des recherches sur trois concurrents différents, tu peux exécuter les subagents de manière asynchrone. Le superviseur dispatch les trois tâches en même temps, elles s'exécutent en parallèle, et le superviseur attend qu'elles retournent toutes un résultat avant de continuer.
Grouper les tâches en subagents, ce n'est pas juste pour organiser ton code, c'est pour contrôler strictement ce que le modèle de langage est forcé de garder en mémoire à un instant T.
C'est tout pour cet épisode. Merci de ton écoute, et continue à builder !
17
Agents pilotés par l'état
3m 36s
Nous explorons comment les agents peuvent modifier dynamiquement leur comportement. Vous apprendrez le modèle Handoffs pour transférer le contrôle, et le modèle Skills pour charger des prompts spécialisés à la demande.
Bonjour, c'est Alex de DEV STORIES DOT EU. LangChain v1.0 Orchestration Framework, épisode 17 sur 20. Tu n'as pas besoin de surcharger le cerveau de ton agent avec tous les scénarios possibles dès le départ. Mettre cinquante pages d'instructions dans un seul system prompt ne fait que rendre ton modèle confus, lent et cher. Tu as juste besoin de lui apprendre à demander le bon manuel le moment venu. C'est le mécanisme principal derrière les State-Driven Agents.
Les State-Driven Agents fonctionnent sur un principe simple. Le comportement de l'agent change dynamiquement en fonction du state actuel de l'application. On gère ça en utilisant deux patterns principaux, qui sont les Skills et les Handoffs. Ces deux patterns s'appuient sur des tools pour mettre à jour les variables de state, qui à leur tour dictent ce qui se passe ensuite dans le workflow.
Regardons d'abord le pattern Skills. Ce pattern consiste en une divulgation progressive des connaissances. Au lieu de donner à un agent toutes ses instructions au départ, tu lui donnes un tool. Quand l'agent décide qu'il a besoin de plus d'informations pour résoudre un problème, il appelle ce tool. Le tool s'exécute, mais il fait bien plus que juste renvoyer une string au modèle. Il met à jour une variable de state spécifique dans ton application. Ta couche d'orchestration surveille ce state. Quand elle détecte le changement, elle injecte dynamiquement un nouveau set d'instructions ou de capacités dans le system prompt de l'agent pour le tour suivant.
Prends un agent de support client standard. Au début, son seul boulot est de comprendre ce que veut le client. Un utilisateur pose une question sur un produit cassé. L'agent appelle un tool pour récupérer un ID de garantie. L'exécution de ce tool met à jour une variable de state pour indiquer qu'une réclamation de garantie est active. L'application lit ce nouveau state et charge dynamiquement un skill de remboursement spécialisé dans le prompt. Ce skill peut inclure les règles spécifiques pour traiter les retours et l'accès à une base de données d'inventaire sécurisée. Les capacités de l'agent ont évolué en pleine conversation, pilotées entièrement par une mise à jour du state.
Maintenant, que se passe-t-il si la tâche demandée est trop complexe à gérer pour l'agent initial, même avec de nouveaux skills ? C'est là qu'intervient le pattern Handoff. Les Handoffs utilisent aussi des tools pour mettre à jour le state, mais au lieu de charger de nouvelles instructions dans l'agent actuel, le changement de state transfère le contrôle à un agent complètement différent. Revenons à notre scénario. L'agent de support récupère l'ID de garantie, mais au lieu de traiter le remboursement lui-même, il appelle un tool de handoff. Ce tool met à jour une variable de routage dans le state, changeant l'agent actif du bot de triage à un agent spécialiste conçu uniquement pour les retours de grande valeur. La couche d'orchestration voit ce changement de state et dirige la prochaine étape du workflow vers le spécialiste.
C'est souvent à ce point de transition que ça plante. Lors d'un handoff entre agents, le nouvel agent a besoin du contexte de la conversation. Beaucoup de développeurs essaient de nettoyer l'historique en passant juste les messages bruts de l'utilisateur au nouvel agent. Ne fais pas ça. Lors d'un handoff entre agents, tu dois inclure le message de l'IA contenant le tool call réel qui a initié le handoff, et le message Tool résultant qui confirme que le handoff a eu lieu. Si tu supprimes le tool call et le message Tool de l'array de messages, l'historique de la conversation est cassé. Le nouveau modèle perd la chain logique des événements. Il ne saura pas comment il est arrivé là, et il va probablement répéter des questions auxquelles l'utilisateur a déjà répondu. Passe toujours l'historique de messages intact.
Voici l'idée clé. Le state n'est pas juste un espace de stockage passif, mais le control plane qui dicte exactement ce que ton système est capable de faire à n'importe quelle milliseconde.
C'est tout pour cet épisode. Merci d'avoir écouté, et continue de développer !
18
Workflows personnalisés et routeurs
3m 46s
Nous sortons de la boucle standard de l'agent. Vous apprendrez à utiliser LangGraph pour construire des architectures de routage personnalisées, en mélangeant une logique déterministe avec un raisonnement agentique non déterministe.
Salut, c'est Alex de DEV STORIES DOT EU. LangChain v1.0 Orchestration Framework, épisode 18 sur 20. Parfois, tu ne veux pas qu'un agent IA décide librement de ce qu'il va faire ensuite. Tu veux juste qu'il exécute un flowchart strict et déterministe. Les custom workflows et les routers te donnent exactement ce niveau de contrôle.
Quand tu te reposes uniquement sur une agent loop standard, tu fais confiance au modèle de langage pour trouver chaque étape tout seul. Il peut chercher dans une base de données, se rendre compte qu'il a besoin de plus de data, chercher encore, et finir par répondre. C'est puissant, mais c'est imprévisible et souvent lent. Les custom workflows dans LangGraph te permettent de sortir de cette loop. C'est toi qui dessines la carte. Tu peux mixer sans problème une logique déterministe, comme l'exécution de scripts de récupération de data bien précis, avec le raisonnement non déterministe d'un agent. Tu places le modèle de langage à l'intérieur d'une séquence d'événements stricte.
Avant d'en construire un, on doit dissiper une confusion fréquente entre un router et un supervisor. Un supervisor orchestre activement une conversation multi-turn. Il regarde les agents parler, décide de qui prend la parole ensuite, et gère le dialogue dans le temps. Un router, ce n'est pas ça. Un router, c'est juste une étape de classification. Il regarde l'input, décide quel chemin le workflow doit prendre, route la data, et son boulot est terminé. Il peut être stateless ou stateful, mais ce n'est pas un gestionnaire de conversation.
Prenons un scénario concret. Tu construis un outil de knowledge base multi-sources. Un utilisateur pose une question, et la réponse peut être enfouie dans des pull requests GitHub, des threads Slack, ou les deux. Tu ne veux pas qu'un seul agent devine à l'aveugle où chercher. Tu veux un workflow structuré.
D'abord, tu crées un node de routing. Tu passes la query de l'utilisateur à un modèle de langage et tu lui demandes de sortir une simple liste de destinations. Si la query parle d'un bug fix récent, le modèle pourrait sortir les mots GitHub et Slack.
C'est ça la partie importante. Tu n'es pas obligé de choisir un seul chemin. Tu peux faire tourner plusieurs agents exactement en même temps en utilisant l'API Send. Dans LangGraph, au lieu de retourner une seule étape suivante depuis ta logique conditionnelle, ta fonction de routing retourne une liste de commandes Send. Chaque commande associe un node de destination avec la data spécifique dont il a besoin. Le graphe voit plusieurs commandes Send et exécute automatiquement tous ces target nodes en parallèle. C'est ce qu'on appelle le fanning out.
Pendant le fanning out, le workflow atteint tes agent nodes. Dans un custom workflow, invoquer un agent est super simple. Un agent est simplement un process runnable exécuté à l'intérieur d'une fonction de node standard. Le node Slack reçoit la query, fait tourner un agent Slack dédié pour chercher dans les channels, extrait le contexte, et le retourne au state global du graphe. Le node GitHub fait la même chose en simultané pour les repositories de code. Isoler ces agents à l'intérieur de nodes spécifiques garantit qu'ils ne font que le boulot pour lequel ils ont été construits.
Enfin, toutes ces branches parallèles doivent converger. Tu fais un fan in. Tu crées un node synthétiseur qui attend que les agents parallèles aient terminé. Il lit le state global du graphe, prend le contexte récupéré sur Slack et le contexte récupéré sur GitHub, les passe tous les deux à un modèle de langage final, et génère une réponse unique et propre pour l'utilisateur.
La vraie puissance des custom workflows, c'est d'envelopper la nature imprévisible des grands modèles de langage dans la fiabilité prévisible du routing logiciel standard.
C'est tout pour cet épisode. À la prochaine !
19
Communication d'agent à agent
3m 24s
Nous explorons le endpoint LangSmith A2A. Vous apprendrez comment des agents distribués déployés sur des serveurs entièrement différents peuvent converser nativement en utilisant le protocole A2A RPC de Google.
Salut, c'est Alex de DEV STORIES DOT EU. LangChain v1.0 Orchestration Framework, épisode 19 sur 20. Que se passe-t-il quand un agent développé en Python doit converser nativement avec un agent développé par une équipe complètement différente, qui tourne sur un serveur totalement différent ? Si tu te reposes sur des function calls internes hardcodés, ton système plante dès qu'il franchit une limite réseau. La solution, c'est la communication Agent-to-Agent.
L'Agent-to-Agent, ou A2A, est un protocole de communication qui permet d'avoir des systèmes multi-agents vraiment distribués. Ça permet à des agents hébergés sur des serveurs totalement différents de maintenir une conversation continue sans avoir besoin de partager la même codebase sous-jacente ou le même espace mémoire local. Au lieu de tout wrapper dans une seule application massive, tu routes les requêtes sur le réseau.
La communication repose strictement sur un format d'endpoint défini : slash a2a slash, suivi de l'assistant ID. Chaque agent qui participe à ce réseau distribué expose ce chemin d'endpoint précis. Quand un agent a besoin de l'aide d'un autre, il y envoie une requête HTTP POST. Le payload envoyé à cet endpoint est structuré comme un message JSON-RPC standard.
Pour garder la conversation cohérente à travers de multiples sauts réseau et différents serveurs, le protocole utilise deux identifiants distincts dans son payload. Les développeurs confondent parfois les deux, donc on va définir leurs limites. Le premier, c'est le Context ID. Le Context ID est responsable de la continuité globale du thread. Il représente tout l'historique global de la conversation, du premier prompt jusqu'à l'output final. Le second, c'est le Task ID. Le Task ID identifie la requête ou l'étape spécifique au sein de ce tour de parole. Le Context ID couvre toute la session. Le Task ID change à chaque fois qu'un agent demande à l'autre d'effectuer une nouvelle action.
Prenons un scénario pratique où l'Agent A tourne sur un serveur qui écoute sur le port 2024, et l'Agent B tourne sur un serveur différent sur le port 2025. L'Agent A se rend compte qu'il a besoin de l'Agent B pour gérer une sous-tâche spécifique, peut-être vérifier un inventaire externe. L'Agent A prépare un message JSON-RPC. À l'intérieur de ce message, il inclut le Context ID existant pour que l'Agent B sache à quelle conversation en cours ça appartient. L'Agent A génère aussi un tout nouveau Task ID pour cette requête d'inventaire spécifique.
L'Agent A envoie ce payload à l'endpoint A2A sur le port 2025, en insérant l'assistant ID spécifique de l'Agent B directement dans le chemin de l'URL. L'Agent B reçoit la requête. Il lit le Context ID pour rappeler tout state de background nécessaire, traite la tâche demandée dans les paramètres JSON-RPC, et calcule le résultat. L'Agent B construit ensuite une réponse JSON-RPC. Cette réponse inclut explicitement le Task ID exact que l'Agent A avait fourni au départ. L'Agent B renvoie cette réponse à l'Agent A sur le port 2024. L'Agent A reçoit le résultat, matche le Task ID avec sa requête en attente, et continue sa propre exécution interne.
Voici le point clé. Parce que le protocole impose le standard JSON-RPC et isole le tracking du state dans des identifiants Context et Task spécifiques, aucun des agents n'a besoin de savoir comment l'autre fonctionne en interne. Ils ne maintiennent pas de connexion socket ouverte en permanence. Ils s'échangent simplement à tour de rôle des messages structurés à travers des limites HTTP standards. Un serveur pose une question, l'autre répond, et la tâche globale progresse.
Quand tu sépares le thread de conversation à long terme de l'exécution de la tâche individuelle à court terme, tu peux scaler des réseaux multi-agents sur différents serveurs et frameworks indéfiniment. Si tu trouves ces épisodes utiles et que tu veux soutenir l'émission, tu peux chercher DevStoriesEU sur Patreon. C'est tout pour cet épisode. Merci pour ton écoute, et continue de builder !
20
L'avenir est au MCP
4m 19s
Nous nous tournons vers l'avenir avec le Model Context Protocol, qui standardise la façon dont les agents accèdent aux outils externes. Vous apprendrez à connecter des serveurs MCP distants à votre agent en utilisant des transports standards.
Salut, c'est Alex de DEV STORIES DOT EU. LangChain v1.0 Orchestration Framework, épisode 20 sur 20. À chaque fois que tu veux que ton agent communique avec une nouvelle base de données ou une API, tu finis par écrire un wrapper custom. Ta codebase se remplit d'intégrations fragiles qui cassent dès qu'une API externe change. Ça limite la vitesse à laquelle tu peux scaler tes applications. La solution à ce problème d'intégration, c'est le Model Context Protocol, ou MCP.
Vois le MCP comme l'USB-C des agents IA. Il standardise la façon dont les tools et le contexte sont exposés aux large language models. Avant ce protocole, si tu voulais que ton agent requête une base de données et check un service météo, tu devais écrire des fonctions Python spécifiques pour les deux, définir manuellement leurs input schemas, et les bind à ton modèle. Avec MCP, le service externe lui-même fournit une interface standardisée. Ton agent se plug simplement dessus et comprend instantanément quels tools sont disponibles, quels arguments ils requièrent, et comment les exécuter.
Une erreur courante est de penser qu'utiliser un serveur MCP distant signifie que la logique de ton agent part sur le réseau. Voici le point clé. Ton agent reste complètement local. Le serveur distant ne run pas ton agent et ne contrôle pas son raisonnement. Il expose simplement une liste de JSON schemas standardisés représentant les tools qu'il supporte. Ton agent local lit ces schemas, décide quel tool utiliser en fonction du prompt utilisateur, et renvoie une requête d'exécution au serveur. L'exécution se passe là-bas, et le résultat brut est renvoyé à ton agent local.
Dans LangChain, tu gères ces connexions avec le MultiServerMCPClient. Ce composant agit comme un hub central. Il permet à un seul agent de se connecter à plusieurs serveurs MCP différents en même temps, en récupérant les tools de chacun d'eux. Le client gère la communication sous-jacente en utilisant différentes transport layers. Les deux transports principaux que tu vas configurer sont l'entrée et la sortie standard, qu'on appelle stdio, et HTTP.
Prenons un scénario concret. Tu développes un agent qui doit faire des calculs complexes avec un script Python local, tout en récupérant des données météo en live depuis un service distant. Au lieu d'écrire des tool wrappers custom pour ces tâches, tu configures le MultiServerMCPClient pour gérer les deux.
D'abord, tu définis ton serveur de maths local en utilisant le transport stdio. Tu configures le client avec la commande à run, comme l'exécutable Python de ton système, et le path vers ton script de maths. Quand le client s'initialise, il lance ce script comme un process local en background. Le client LangChain et le script s'échangent des messages directement via les streams d'entrée et de sortie standard.
Ensuite, tu définis le serveur météo avec le transport HTTP. Pour ça, tu fournis juste l'URL de l'endpoint du service météo distant. Ce setup repose généralement sur les Server-Sent Events pour maintenir une connexion persistante, ce qui permet à l'agent de requêter des actions et de streamer les réponses sur le web.
Une fois les deux transports définis, tu initialises le MultiServerMCPClient. Le client contacte immédiatement le process de maths local via stdio et l'URL météo distante via HTTP. Il demande aux deux serveurs de lui transmettre leurs définitions de tools. Il collecte les schemas, les merge en une seule liste continue, et les fournit à ton agent LangChain. Du point de vue de l'agent, il voit juste une liste unifiée de tools disponibles. Il ignore complètement qu'un tool s'exécute dans un process binaire local et que l'autre déclenche une requête HTTP vers un serveur à l'autre bout du monde.
Le passage à des protocoles standardisés signifie que tu peux passer ton temps à développer une meilleure logique d'agent au lieu de maintenir des API wrappers à n'en plus finir. Comme c'est le dernier épisode de la série, je t'encourage vivement à lire la documentation officielle de LangChain et à essayer de setup un serveur MCP local toi-même. Si tu as des suggestions de sujets que tu veux voir dans notre prochaine série, visite devstories dot eu et laisse-nous un message. La vraie puissance d'un agent ne réside pas dans ce qu'il sait, mais dans ce à quoi il peut se connecter de façon transparente.
C'est tout pour cet épisode. Merci d'avoir écouté, et continue de développer !
Tap to start playing
Browsers block autoplay
Share this episode
Episode
—
Copy this episode in another language:
Ce site n'utilise pas de cookies. Notre hébergeur peut enregistrer votre adresse IP à des fins d'analyse. En savoir plus.