LangChain 1.x en pratique : chaînes, RAG, outils et agents localement
Apprenez à créer des chaînes, une génération améliorée par la récupération d’informations, des outils et un système RAG agentiel avec LangChain 1.x en utilisant une installation locale gratuite d’Ollama, sans besoin de clés API.
Ce troisième volet fait partie d’une série pratique qui poursuit les travaux précédents sur la création de RAG et d’agents à partir de zéro en Python pur. L’approche adoptée est délibérément différente : au lieu de monter vous-même chaque composant, vous verrez comment LangChain regroupe toute cette logique en quelques lignes de code seulement. Comme vous avez déjà construit les éléments de base manuellement, vous êtes en bonne position pour comprendre réellement ce que fait chaque abstraction, plutôt que de la considérer comme une magie. Cette compréhension est essentielle : elle fait la différence entre les développeurs qui utilisent LangChain efficacement et ceux qui doivent constamment lutter contre ses limites.
Tout dans ce tutoriel s’exécute localement et gratuitement, en utilisant un modèle local via Ollama ainsi que des embeddings locaux. Aucune clé API n’est nécessaire, et il n’y a pas de limites de fréquence à craindre.
Remarque sur les versions : ce tutoriel vise LangChain 1.x, testé avec
langchain==1.3.11etlangchain-core==1.4.8. LangChain 1.0 a entraîné une réorganisation importante — l’API actuelle des agents se concentre surcreate_agent, tandis que des composants plus anciens tels queAgentExecutoretinitialize_agentont été déplacés dans un package distinctlangchain-classic. De nombreux tutoriels en ligne illustrent encore les schémas antérieurs à 1.0 ; les importations présentées ici sont à jour, et chacune a été vérifiée pour s’assurer qu’elle fonctionne correctement.
Comment suivre les instructions : ouvrez un fichier nommé lc.py, exécutez chaque bloc de code dans l’ordre, et terminez les exercices « C’est à vous » au fur et à mesure que vous les rencontrez. Chaque fois que vous verrez l’expression « vous avez construit ceci », elle fait référence à la mise en œuvre manuelle présentée dans les tutoriels précédents de cette série.
Étape 0 — Qu’est-ce que LangChain exactement
LangChain peut être compris comme une collection de composants standardisés et interchangeables permettant de créer des applications utilisant des modèles LLM — tels que des enveloppes de modèle, des modèles de prompts, des outils de récupération d’informations, des bases de données vectorielles, des outils et des agents. Tous ces éléments respectent une interface commune, ce qui vous permet de les relier entre eux et d’en remplacer un par un (changer de modèle, modifier la base de données vectorielle) sans avoir à réécrire la logique de votre application.
Le concept qui relie tout est le Runnable. Chaque composant expose la même méthode .invoke(), et n’importe quels deux composants peuvent être enchaînés entre eux à l’aide de l’opérateur de pipe |. Ce mécanisme de piping est connu sous le nom de LCEL, abréviation de LangChain Expression Language. Une fois que chaque partie de votre système utilise l’interface Runnable, tout un pipeline ou agent RAG peut être défini en seulement quelques lignes.
Un compromis important à mentionner dès le début : LangChain réduit le code répétitif et vous donne accès à un vaste catalogue d’intégrations prêtes à l’emploi. En contrepartie, il introduit des couches d’abstraction qui peuvent rendre le débogage plus difficile — il y aura des moments où vous préférerez examiner directement la boucle que vous avez écrite vous-même. Savoir quand cette abstraction en vaut la peine est là la véritable compétence, et nous reviendrons sur ce compromis à l’Étape 7.
Mise en place (l’environnement local gratuit)
pip install langchain langchain-core langchain-ollama langchain-huggingface langchain-text-splitters sentence-transformers
Vous aurez également besoin d’avoir Ollama installé (il est gratuit et fonctionne localement) ; après cela, vous devriez télécharger un modèle capable d’appeler des outils :
ollama pull llama3.2 # ~2 GB; needs ~8 GB RAM. qwen2.5 also works well.
Si vous préférez éviter Ollama, vous pouvez toujours exécuter les sections chain et RAG en utilisant un modèle local de Hugging Face via
langchain-huggingface. Cependant, les sections agent dépendent d’un comportement fiable de appel d’outils, que les petits modèles gourmands en CPU ont tendance à gérer mal. L’utilisation d’Ollama est fortement recommandée pour les étapes 4 à 6.
Étape 1 — L’action principale : une chaîne avec le pipe |
Dans le tutoriel RAG précédent, vous avez assemblé manuellement une requête à l’aide d’une chaîne de caractères f, vous l’avez transmise au modèle et vous avez nettoyé la sortie avec .strip(). LangChain capture cette même séquence sous forme d’expression de pipe. Ajoutez ceci à lc.py :
from langchain_ollama import ChatOllama
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
llm = ChatOllama(model="llama3.2", temperature=0)
prompt = ChatPromptTemplate.from_template(
"Explain {topic} in exactly one sentence."
)
# The chain: prompt -> model -> plain-string parser
chain = prompt | llm | StrOutputParser()
print(chain.invoke({"topic": "retrieval-augmented generation"}))
Lecture du pipeline de gauche à droite : prompt convertit votre dictionnaire d’entrée en un message correctement formaté, llm transforme ce message en une réponse du modèle, et StrOutputParser() extrait le texte brut de l’objet de réponse.
Ce système a déjà été mis en place par vous. Ce pipeline est fonctionnellement identique à f"Explain {topic}..." suivi de generator(prompt) puis de [0]["generated_text"].strip() vu dans la démonstration RAG précédente — trois étapes manuelles, maintenant exprimées sous forme de trois Runnables connectés par des pipelines. La logique n’a pas changé ; seule l’interface a été standardisée.
Votre tour : chaque Runnable prend également en charge .batch() et .stream() directement. Essayez donc :
for piece in chain.stream({"topic": "vector embeddings"}):
print(piece, end="", flush=True) # tokens arrive as they're generated
print()
print(chain.batch([{"topic": "agents"}, {"topic": "chunking"}])) # two at once
Remarquez que le streaming et le batchage ont été inclus gratuitement simplement parce que vous avez utilisé l’interface standard Runnable. Ce moment de « gratuité » représente, en miniature, toute la raison d’utiliser LangChain.
Étape 2 — RAG, à la manière de LangChain
C’est le moment de reconstruire votre pipeline RAG manuel à l’aide des éléments de base de LangChain. Chaque composant correspond directement à quelque chose que vous avez déjà écrit manuellement.
from langchain_huggingface import HuggingFaceEmbeddings
from langchain_core.vectorstores import InMemoryVectorStore
from langchain_text_splitters import RecursiveCharacterTextSplitter
# Same Nimbus knowledge base from the RAG tutorial
DOCUMENTS = [
"Nimbus is a fictional note-taking app. The free plan, Nimbus Lite, allows up to 50 notes and 1 GB of storage.",
"Nimbus Pro costs 8 dollars per month billed annually, or 10 dollars billed monthly. It includes 50 GB of storage and collaboration for up to 5 people.",
"Nimbus stores notes encrypted at rest with AES-256. End-to-end encryption is Pro-only and must be enabled in Settings > Security.",
"Nimbus offers a 30-day refund policy on all paid plans. Refunds reach the original payment method within 5 business days.",
"Nimbus live chat support is staffed for Pro customers, Monday to Friday, 9am-6pm UTC. Free users get email support with a 48-hour response time.",
]
# 1. Split (↔ your chunk_text function)
splitter = RecursiveCharacterTextSplitter(chunk_size=200, chunk_overlap=40)
chunks = splitter.create_documents(DOCUMENTS)
# 2. Embed locally (↔ your sentence-transformers model)
embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
# 3. Store + index (↔ your numpy array of vectors). No server needed.
vectorstore = InMemoryVectorStore.from_documents(chunks, embeddings)
# 4. Retriever (↔ your retrieve() with cosine top-k)
retriever = vectorstore.as_retriever(search_kwargs={"k": 3})
for doc in retriever.invoke("How much does Pro cost?"):
print("-", doc.page_content[:70], "...")
↔ c’est vous qui avez construit tout cela. RecursiveCharacterTextSplitter remplit la fonction de découpage du texte, mais il le fait avec plus de prudence : il divise le texte en fonction des limites entre paragraphes et phrases plutôt que de se baser uniquement sur le comptage des mots. HuggingFaceEmbeddings n’est qu’un enveloppe autour du même modèle all-MiniLM-L6-v2 que vous avez utilisé précédemment. InMemoryVectorStore remplace votre tableau numpy de vecteurs, et sa méthode .as_retriever() effectue la même recherche top-k par similarité cosinus que vous aviez codée manuellement. Quatre lignes suffisent ici pour couvrir tout ce que vous avez développé aux étapes 2 à 4 précédemment.
Ensuite, connectez la récupération des données à la génération en utilisant LCEL :
from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser
rag_prompt = ChatPromptTemplate.from_template(
"Answer using only the context. If it's not there, say you don't know.\n\n"
"Context:\n{context}\n\nQuestion: {question}\nAnswer:"
)
def format_docs(docs):
return "\n\n".join(d.page_content for d in docs)
rag_chain = (
{"context": retriever | format_docs, "question": RunnablePassthrough()}
| rag_prompt
| llm
| StrOutputParser()
)
print(rag_chain.invoke("How much does Nimbus Pro cost per month?"))
Le dictionnaire situé au début de la chaîne fait fonctionner deux branches en parallèle : question transmet simplement l’entrée telle quelle, tandis que context dirige cette même entrée vers le récupérateur et formate les résultats. Les deux sorties se retrouvent ensuite dans le prompt. ↔ vous avez construit ceci correspond essentiellement à votre ancienne fonction rag_answer() — récupérer, insérer dans un prompt, générer — condensée en une seule expression.
Votre tour : Essayez d’appeler rag_chain.invoke("Les utilisateurs libres peuvent-ils utiliser le chat en direct ?"), puis suivez cela d’une question non liée comme rag_chain.invoke("Quelle est la capitale de la France ?"). Faites attention à la réponse « Je ne sais pas » — il s’agit de la même vérification que dans le tutoriel RAG précédent, qui souligne à nouveau le point suivant : la qualité de la récupération détermine la qualité de la réponse. Ensuite, appelez retriever.invoke(...) séparément pour voir exactement ce qui a été extrait lorsque la réponse semble incorrecte. Cette séparation — vérifier la récupération indépendamment de la génération — est une habitude de débogage que vous avez déjà utilisée, et LangChain la conserve en gardant ces deux étapes comme des Runnables distincts.
Étape 3 — Outils
Dans le tutoriel sur les agents, vous avez défini les outils sous forme de dictionnaire TOOLS et écrit vous-même un analyseur basé sur des expressions régulières pour extraire le nom de l’outil et ses paramètres à partir du texte brut généré par le modèle. LangChain élimine complètement la nécessité d’un tel analyseur grâce à l’appel natif d’outils : vous décrivez ce que fait un outil, le modèle répond par une requête structurée, et LangChain s’occupe de l’affectation. La définition d’un outil se fait ainsi, en utilisant le décorateur @tool :
from langchain_core.tools import tool
import ast, operator, datetime
_OPS = {ast.Add: operator.add, ast.Sub: operator.sub, ast.Mult: operator.mul,
ast.Div: operator.truediv, ast.Pow: operator.pow, ast.USub: operator.neg}
def _ev(n):
if isinstance(n, ast.Constant): return n.value
if isinstance(n, ast.BinOp): return _OPS[type(n.op)](_ev(n.left), _ev(n.right))
if isinstance(n, ast.UnaryOp): return _OPS[type(n.op)](_ev(n.operand))
raise ValueError("unsupported")
@tool
def calculator(expression: str) -> str:
"""Evaluate a basic arithmetic expression like '8 * 12'."""
return str(_ev(ast.parse(expression, mode="eval").body))
@tool
def get_today(_: str = "") -> str:
"""Return today's date in ISO format."""
return datetime.date.today().isoformat()
Voici les détails qui méritent une attention particulière. Vous pouvez examiner précisément ce que LangChain a généré à partir de votre fonction :
print(calculator.name) # 'calculator'
print(calculator.description) # the docstring
print(calculator.args) # {'expression': {'title': 'Expression', 'type': 'string'}}
Ce dernier ligne est bien une sortie réelle et vérifiée. LangChain a examiné votre indication de type (expression: str) ainsi que la documentation, afin d’en construire un schéma — c’est précisément ce schéma que le modèle lit pour déterminer s’il doit invoquer l’outil et comment le faire. ↔ c’est vous qui avez créé ce schéma ; auparavant, vous écriviez manuellement des descriptions d’outil à l’intérieur de votre SYSTEM_PROMPT et analysiez vous-même la sortie du modèle. Désormais, c’est la documentation elle-même qui sert de description, et l’analyse se fait automatiquement. Cela explique pourquoi les documents de description et les indications de type ont une réelle importance — ce ne sont pas simplement de la documentation, ils définissent la manière dont le modèle comprend et utilise l’outil. Une documentation négligée entraîne un modèle qui invoque l’outil de manière incorrecte.
Votre tour : Remplacez la docstring du calculateur par quelque chose d’inutile, comme """effectue des calculs mathématiques""", puis vérifiez à nouveau .description. À l’étape 4, vous verrez de vos propres yeux comment une docstring insuffisante entraîne de pires décisions de sélection d’outil de la part du modèle. La description que vous écrivez agit comme le volant qui guide le comportement du modèle.
Étape 4 — Agents en une seule appel
C’est ici que les travaux précédents portent leurs fruits. Votre agent personnalisé nécessitait une boucle, un espace de travail temporaire, un analyseur, un mécanisme de gestion des erreurs, une limite par étape, ainsi qu’un prompt système pour enseigner au modèle le format ReAct. Dans LangChain 1.x, tout cela se résume en une seule appel de fonction : create_agent.
from langchain.agents import create_agent
agent = create_agent(
model=llm, # your ChatOllama from Step 1
tools=[calculator, get_today], # the @tool functions from Step 3
system_prompt="You are a helpful assistant. Use tools for math and dates.",
)
result = agent.invoke(
{"messages": [{"role": "user", "content": "What is 8 times 12, and what is today's date?"}]}
)
print(result["messages"][-1].content)
C’est l’agent dans son intégralité, du début à la fin. ↔ c’est vous qui l’avez construit — en totalité. La fonction create_agent exécute internement le cycle raisonner-agir-observer, envoie les tâches à l’outil approprié, renvoie les observations au modèle, vérifie la condition d’arrêt et respecte la limite de pas — chaque élément que vous avez assemblé manuellement à l’intérieur de run_agent. En sous-main, elle s’appuie sur LangGraph, ce qui explique pourquoi le comportement itératif est si fiable.
Si vous souhaitez voir le processus de raisonnement se dérouler — le même effet que celui obtenu avec verbose=True — diffusez les étapes intermédiaires au lieu d’attendre simplement une réponse finale :
inputs = {"messages": [{"role": "user", "content": "How much is a year of Nimbus Pro?"}]}
for chunk in agent.stream(inputs, stream_mode="updates"):
print(chunk)
Lorsque l’exécution se déroule, vous verrez chaque décision prise par le modèle ainsi que chaque résultat retourné par l’outil, affichés un après l’autre. Il s’agit du même schéma Pensée/Action/Observation que dans le suivi manuel, mais présenté sous forme d’objets de mise à jour structurés plutôt que de texte brut que vous deviez parser vous-même.
Votre tour : Essayez une question qui oblige le modèle à utiliser deux outils en chaîne — par exemple, demandez-lui de déterminer la date de fin d’une fenêtre de remboursement de 30 jours sachant qu’un essai a commencé aujourd’hui. Vérifiez s’il appelle correctement d’abord get_today, puis calculator dans l’ordre. Ensuite, revenez à l’étape 7 du matériel sur les agents — tous les modes de défaillance que vous y avez documentés (format d’ sortie erroné, noms d’outils inventés, boucles infinies) peuvent encore se manifester ici. Le framework ne renforce pas le raisonnement d’un modèle faible ; il cache simplement la logique sous-jacente. Comprendre cette différence est précisément ce qui vous permettra de déboguer ces agents plus rapidement que quelqu’un qui se lance directement dans le framework sans en construire un d’abord.
Étape 5 — Assembler le tout : un agent qui récupère des informations (agentic RAG)
C’est ici que convergent les trois leçons précédentes. Prenez votre chien de recherche et utilisez-le comme un outil, puis donnez cet outil à l’agent. Désormais, c’est l’agent lui-même qui décide quand une recherche de document est nécessaire — et il peut effectuer des recherches multiples ou combiner la récupération d’informations avec des calculs selon ses besoins.
@tool
def search_nimbus_docs(query: str) -> str:
"""Search the Nimbus product documentation for facts about plans, pricing, refunds, security, and support."""
docs = retriever.invoke(query)
return "\n\n".join(d.page_content for d in docs)
smart_agent = create_agent(
model=llm,
tools=[search_nimbus_docs, calculator, get_today],
system_prompt=(
"You answer questions about the Nimbus app. "
"Use search_nimbus_docs for any product facts, and calculator for arithmetic. "
"Base answers only on retrieved facts."
),
)
q = "How much would Nimbus Pro cost a team of 4 for a full year?"
result = smart_agent.invoke({"messages": [{"role": "user", "content": q}]})
print(result["messages"][-1].content)
Pour répondre correctement à une telle question, l’agent doit d’abord rechercher le prix de l’abonnement mensuel, puis seulement calculer 8 * 12 * 4. Il s’agit donc de la récupération d’informations (provenant du premier tutoriel) présentée sous forme d’outil (du troisième), mise en œuvre par un agent (du deuxième) — trois concepts distincts fonctionnant ensemble au sein d’un même système. Permettre à l’agent de choisir le moment de la récupération d’informations offre une grande flexibilité par rapport au rag_chain à chemin fixe de l’Étape 2, et c’est un schéma fréquemment utilisé dans les systèmes de production réels.
Votre tour : Diffusez également l’exécution de cet agent en utilisant smart_agent.stream(..., stream_mode="updates"), et confirmez l’ordre des opérations — la recherche a lieu avant le calcul. Si votre modèle local tente de résoudre les opérations arithmétiques par lui-même au lieu d’utiliser l’outil de calculateur (tendance courante chez les modèles plus petits), renforcez l’instruction système avec une phrase du type "Vous DEVEZ utiliser le calculateur pour chaque étape arithmétique."> C’est le même remède qui a fonctionné dans le tutoriel des agents.
Étape 6 — Un bref aperçu de ce qu’il y a d’autre
À ce stade, vous avez déjà le squelette essentiel en place. Quelques éléments supplémentaires de LangChain méritent d’être connus, chacun correspondant à quelque chose que vous avez déjà construit manuellement :
- Chargeurs de documents (
langchain-community) — permettent d’ingérer des PDF, des pages web, des pages Notion et d’autres sources similaires directement dans les mêmes objetsDocumentque votre outil de segmentation de texte utilise déjà. Cela remplace le collage manuel de textes dans une liste par un chargement réel et structuré. - Stockages vectoriels de niveau production — permettent de remplacer le stockage en mémoire par Chroma ou FAISS (importés via
from langchain_chroma import Chroma) afin de conserver les embeddings sur disque et d’augmenter la capacité au-delà des limites de la mémoire. Comme ces outils exposent tous deux l’interface.as_retriever()identique, rien dans la chaîne de traitement ne doit être modifié — c’est précisément cette cohérence qui justifie ce changement.
create_agent ne suffit plus (chemins bifurqués, étapes d’approbation avec intervention humaine, plusieurs agents collaborant), vous passez à LangGraph, le moteur de graphes de niveau inférieur sur lequel create_agent lui-même est construit.Étape 7 — Quand recourir à LangChain, et quand ne pas le faire (un avis honnête)
À ce stade, vous avez construit le même type de système à deux reprises — une fois de zéro, une fois avec un framework — ce qui vous place dans une bonne position pour effectuer cette appel vous-même. C’était l’objectif de passer en revue les deux versions.
LangChain s’avère utile lorsque vous assemblez de nombreuses intégrations existantes — quelques chargeurs de documents, plusieurs bases de données vectorielles, plus d’un fournisseur de modèles — et que vous ne souhaitez pas développer manuellement la logique de streaming, de batchage, de tentative répétée et de suivi pour chacune d’elles. Il est également avantageux lorsque vous prévoyez de changer fréquemment les composants et que vous souhaitez une interface stable pour les remplacer, ou encore lorsque vous développez un agent et que vous préférez ne pas gérer vous-même la boucle de raisonnement.
Écrire à la main est souvent la meilleure solution lorsque l’application est suffisamment petite pour que l’apprentissage des abstractions de LangChain prenne plus de temps que d’écrire simplement les cinquante lignes environ que vous savez déjà rédiger. C’est également la meilleure option lorsque l’on a besoin d’une visibilité totale sur ce qui s’exécute — parcourir les couches du framework pour déboguer un problème constitue une véritable source de friction, et cette plainte est justifiée — ou encore lorsque l’ajout d’une couche d’indirection cacherait une logique qui est en réalité plus claire en Python pur. Le pipeline RAG ainsi que l’agent que vous avez construit manuellement dans les tutoriels précédents sont tout à fait adaptés à un usage en production ; l’utilisation d’un framework ne rend en rien le code écrit manuellement inférieur.
Il n’y a pas de réponse unique et correcte ici. La raison pour laquelle vous avez d’abord appris la version manuelle est que choisir d’adopter ce framework constitue une décision réfléchie prise en connaissant parfaitement ce qu’il remplace, et non un choix par défaut auquel on recourt parce que ses mécanismes internes restent obscurs.
Étape 8 — Où aller ensuite
- Si votre configuration locale semble trop lente, des versions gratuites hébergées sont disponibles chez Groq et Google Gemini. Le changement consiste en une seule modification : remplacer
ChatOllamaparChatGroq, ou utiliserinit_chat_model(“gemini-...”, model_provider=“google_genai”)— car tout le reste fonctionne via la même interface standard. Vous aurez besoin d’une clé API pour l’un ou l’autre, mais leurs versions gratuites ne coûtent rien.
AgentExecutor, initialize_agent ou LLMChain, des éléments qui ont depuis été déplacés ou rendus obsolètes. Le modèle mental à retenir
LangChain est essentiellement un ensemble de composants que vous construisez vous-même, standardisés derrière une seule interface — Runnable — et reliés par |. Rien à l’intérieur n’est véritablement une idée nouvelle une fois que vous avez vous-même conçu ces éléments :
- Une chaîne correspond au flux prompt-modèle-parseur que vous avez déjà écrit, simplement mis en série.
- Un retriever représente votre logique d’incorporation de données et de recherche cosinus, encapsulée dans une interface commune.
- Un outil est une fonction que vous avez écrite accompagnée d’un schéma généré automatiquement, permettant au modèle de l’appeler directement sans que vous ayez à parser son résultat texte.
- Un agent, via
create_agent, correspond à tout votre cycle raisonner-agir-observer, regroupé en une seule appel.
Lorsqu’un problème survient, vous le déboguez de la même manière que d’habitude : vous isolez le composant défaillant. Vous testez le récupérateur séparément, vous affichez les valeurs de .args d’une fonction ou vous suivez pas à pas les étapes intermédiaires de l’agent. Le framework ne change que la quantité de code à taper — il n’affecte pas ce qui se passe réellement, et vous comprenez déjà ce qui se produit.
Résolution de problèmes
- Si vous rencontrez une erreur
ImportErroraveccreate_agentoulangchain_ollama, c’est probablement dû à une installation antérieure à la version 1.0 ou à l’absence d’un paquet nécessaire. Exécutezpip install -U langchain langchain-ollamaet vérifiez quelangchain.__version__commence par1..
AgentExecutor ou initialize_agent, il s’agit de l’API ancienne. Dans la version 1.x, ces fonctions ont été déplacées dans langchain-classic ; le nouveau code doit utiliser create_agent à la place.ollama serve ou ouvrez l’application, et assurez-vous que votre modèle apparaît dans ollama list.qwen2.5.HuggingFaceEmbeddings semble lent la première fois que vous l’utilisez, car il télécharge le modèle d’incorporation (environ 80 MB) et le met en cache localement. La récupération des données est ensuite rapide.Vous avez maintenant construit des systèmes RAG, des agents, ainsi que le framework qui les intégre — d’abord manuellement, puis avec LangChain. Vous comprenez la couche que la plupart des gens n’accèdent qu’indirectement. Amusez-vous à l’utiliser.
Lectures complémentaires
- Comprendre les agents IA : objectifs, outils, mémoire et la boucle de l’agent — Une explication adaptée aux débutants sur les différences entre les agents IA et les chatbots, abordant les composants fondamentaux, la boucle de décision, les niveaux d’autonomie et des cas d’usage concrets.
- Garde-fous structuraux pour les agents IA : à l’intérieur du pipeline ResolveFlow — Explique comment un agent basé sur LangGraph assure la séparation entre le raisonnement et l’exécution grâce à des vérifications au niveau du code plutôt qu’à des instructions dans les prompts, y compris une erreur de récupération qui est survenue au cours du processus.