Agents LangChain : le guide technique complet pour 2026

20 juin 2026
14 min de lecture

20 juin 2026
14 min de lecture
Agents LangChainHover to exploreUn LLM qui répond à des questions, c'est utile. Un LLM capable de faire des choses — interroger votre base de données, envoyer un message Slack, déclencher un remboursement puis vous en rendre compte — c'est un produit. Les agents LangChain sont la façon standard de câbler cette boucle en 2026. Ce guide couvre tout le parcours, du modèle mental au code de production : la boucle de l'agent, l'écriture des outils, la mémoire et l'état, la sortie structurée, le streaming, la gestion des erreurs, et ce qui marche vraiment selon r/LangChain, r/LocalLLaMA et la communauté X.
Ce guide s'appuie sur la documentation des agents LangChain v1, la documentation LangGraph et les discussions récurrentes sur r/LangChain et @LangChainAI sur X.
Tous les agents LangChain exécutent la même boucle, quel que soit le modèle utilisé :
ToolMessage.C'est tout. La sophistication tient aux outils que vous fournissez et à la façon dont vous contraignez la boucle, pas à une quelconque magie interne au framework.
Avec create_agent de LangChain v1, le code répétitif se réduit au minimum :
from langchain.agents import create_agent
from langchain.tools import tool
@tool
def search_orders(order_id: str) -> str:
"""Look up an order by ID and return its current status."""
# Replace with your real DB call
return f"Order {order_id}: Shipped, arriving 2026-06-23."
@tool
def issue_refund(order_id: str, reason: str) -> str:
"""Issue a full refund for an order given a reason."""
return f"Refund issued for order {order_id}. Reason: {reason}."
agent = create_agent(
model="anthropic:claude-sonnet-4-6",
tools=[search_orders, issue_refund],
system_prompt=(
"You are a helpful customer support agent. "
"Always look up the order before issuing a refund."
),
)
result = agent.invoke({
"messages": [{"role": "user", "content": "Refund order #4821 — it arrived broken."}]
})
print(result["messages"][-1].content)
En coulisses, l'agent appelle search_orders("4821"), lit le résultat, appelle issue_refund("4821", "arrived broken") puis renvoie une confirmation à l'utilisateur — le tout dans un seul invoke, sans orchestration manuelle.
Le levier le plus déterminant sur la qualité d'un agent, c'est la conception des outils, pas le choix du modèle. Le modèle décide quel outil appeler uniquement à partir du nom de la fonction, du docstring et du schéma des arguments. Ratez cela et aucun prompt engineering ne vous sauvera.
Des règles qui tiennent en pratique :
search_and_refund() est un piège : séparez-le. Le modèle doit pouvoir appeler chaque étape indépendamment."Error: order not found" plutôt que de lever une exception : l'agent peut alors réessayer ou expliquer l'échec au lieu de planter.from langchain.tools import tool
from pydantic import BaseModel, Field
class SearchInput(BaseModel):
order_id: str = Field(description="The numeric order ID, e.g. '4821'")
include_history: bool = Field(
default=False,
description="Set True to include the full shipment history"
)
@tool(args_schema=SearchInput)
def search_orders(order_id: str, include_history: bool = False) -> str:
"""
Look up an order's current status by order ID.
Call this FIRST before any action that modifies the order.
Returns: status string, or an error message if not found.
"""
try:
order = db.get_order(order_id)
if not order:
return f"Error: order {order_id} not found."
base = f"Order {order_id}: {order.status}, ETA {order.eta}."
if include_history:
base += f" History: {order.shipment_history}"
return base
except Exception as e:
return f"Error fetching order: {str(e)}"
Par défaut, chaque appel à agent.invoke() est sans état : l'agent oublie le tour précédent dès qu'il a répondu. Pour des conversations multi-tours, il faut transmettre l'état explicitement. LangChain propose deux approches :
Approche A — checkpointing par thread avec LangGraph (recommandé en production)
from langchain.agents import create_agent
from langgraph.checkpoint.memory import MemorySaver
# MemorySaver keeps state in RAM; swap for PostgresSaver in production
checkpointer = MemorySaver()
agent = create_agent(
model="anthropic:claude-sonnet-4-6",
tools=[search_orders, issue_refund],
checkpointer=checkpointer,
)
# Same thread_id = same conversation memory
config = {"configurable": {"thread_id": "user-123-session-456"}}
# Turn 1
agent.invoke(
{"messages": [{"role": "user", "content": "What is the status of order 4821?"}]},
config=config,
)
# Turn 2 — agent remembers turn 1
agent.invoke(
{"messages": [{"role": "user", "content": "Go ahead and refund it."}]},
config=config,
)
Approche B — résumé automatique pour les contextes longs
Quand un thread dépasse la fenêtre de contexte du modèle, SummarizationMiddleware compresse automatiquement les anciens messages en un résumé cumulatif avant chaque appel. L'agent perd l'historique mot pour mot mais conserve le sens — suffisant pour la plupart des usages de support ou d'assistance.
Souvent, vous voulez que l'agent collecte des informations et renvoie un objet validé, pas un résumé en texte libre. Passez un modèle Pydantic à response_format et l'agent produit un objet typé dans la même boucle, sans étape de parsing supplémentaire :
from pydantic import BaseModel
from langchain.agents import create_agent
class SupportTicket(BaseModel):
order_id: str
issue_type: str # "refund" | "late_delivery" | "wrong_item"
recommended_action: str
confidence: float # 0.0 – 1.0
agent = create_agent(
model="anthropic:claude-sonnet-4-6",
tools=[search_orders],
response_format=SupportTicket,
system_prompt=(
"Classify the customer's issue and recommend an action. "
"Always search the order before classifying."
),
)
result = agent.invoke({"messages": [
{"role": "user", "content": "My order 4821 never arrived — it's been 3 weeks."}
]})
ticket: SupportTicket = result["structured_response"]
print(ticket.issue_type) # "late_delivery"
print(ticket.recommended_action) # "escalate to carrier"
print(ticket.confidence) # 0.92
Le principal problème d'expérience utilisateur avec un agent, c'est la latence : l'utilisateur ne voit rien tant que la boucle n'est pas terminée. Le streaming corrige cela en exposant les tokens et les événements d'outils au fil de l'eau. LangChain propose deux modes :
# Mode 1 — stream final output tokens only
for chunk in agent.stream(
{"messages": [{"role": "user", "content": "Status of order 4821?"}]},
stream_mode="messages",
):
if chunk[1].get("langgraph_node") == "agent":
print(chunk[0].content, end="", flush=True)
# Mode 2 — stream every event (tool calls, results, tokens)
for event in agent.stream(
{"messages": [{"role": "user", "content": "Status of order 4821?"}]},
stream_mode="updates",
):
kind = list(event.keys())[0]
if kind == "tools":
print(f"[tool] {event['tools']['messages'][0].name}")
elif kind == "agent":
for msg in event["agent"]["messages"]:
print(msg.content, end="", flush=True)
En pratique, utilisez stream_mode="updates" dans toute interface affichant un panneau « en cours de réflexion » : vous pouvez montrer quel outil l'agent appelle sans attendre la réponse finale.
Tout agent capable de dépenser de l'argent, d'envoyer un message ou d'écrire en base a besoin d'une validation humaine pour les actions irréversibles. LangChain v1 offre deux approches : un middleware pour les cas simples, les interruptions LangGraph pour un contrôle total.
# Simple approach — middleware
from langchain.agents.middleware import HumanInTheLoopMiddleware
agent = create_agent(
model="anthropic:claude-sonnet-4-6",
tools=[search_orders, issue_refund, send_email],
middleware=[
HumanInTheLoopMiddleware(
interrupt_on={"issue_refund": True, "send_email": True}
)
],
)
# Advanced approach — LangGraph interrupt node
from langgraph.types import interrupt
def human_approval_node(state):
last_tool_call = state["messages"][-1]
# Pause execution and surface the tool call to your UI
decision = interrupt({
"tool": last_tool_call.name,
"args": last_tool_call.tool_input,
"prompt": "Approve this action?",
})
if decision["approved"]:
return state # continue
# Inject a rejection message back into the graph
return {"messages": [ToolMessage(content="Action rejected by user.", ...)]}
Le middleware se met en place plus vite. L'interruption LangGraph est plus souple : elle permet de modifier les arguments, pas seulement d'approuver ou de refuser. Sur les projets clients, nous commençons presque toujours par le middleware et ne passons aux interruptions que lorsqu'il faut laisser l'utilisateur modifier un appel avant son exécution.
Cette distinction déroute beaucoup de monde. Dans le LangChain de 2022–2023, ReAct (Reason + Act) était le pattern principal : on demandait au modèle d'écrire un brouillon « Thought / Action / Observation » en texte brut, que LangChain parsait pour savoir quoi appeler. Cela fonctionnait, mais restait fragile : le moindre écart de format cassait le parser.
En 2026, create_agent utilise le tool calling natif : le modèle émet un appel structuré dans la réponse de l'API plutôt que dans du texte libre. C'est plus fiable, moins coûteux (pas de double prompt) et pris en charge par tous les grands fournisseurs. ReAct devient un repli pour les modèles sans tool calling natif, plus la voie par défaut.
| Critère | ReAct (historique) | Tool calling natif (défaut v1) |
|---|---|---|
| Format | Brouillon en texte libre | Réponse structurée de l'API |
| Fiabilité | Sensible au format | Validé par schéma |
| Appels d'outils parallèles | Non | Oui (là où c'est pris en charge) |
| Idéal pour | Modèles locaux sans tool calling | Tout le reste |
LANGSMITH_API_KEY et LANGSMITH_TRACING=true. Chaque invoke, chaque appel d'outil, chaque token est tracé automatiquement. Vous ne le regretterez pas à deux heures du matin, quand quelque chose cassera en production.MemorySaver convient au développement local, mais remplacez-le par PostgresSaver ou RedisSaver avant la mise en ligne : sinon, un redémarrage du serveur efface tout l'état conversationnel.Après des mois de lecture des fils r/LangChain, r/LocalLLaMA et des recoins ingénierie IA de X, l'avis de la communauté tient en quelques thèmes récurrents :
langchain / langchain-core / langgraph) perd encore les débutants. » L'équipe LangChain le reconnaît. Le modèle mental est plus clair en v1, mais l'installation fait toujours trébucher au premier essai.« La question en 2026 n'est pas "dois-je utiliser LangChain ?" mais "ai-je besoin de checkpointing, d'observabilité et d'un tool calling portable entre fournisseurs — ou suis-je sur un seul fournisseur, trois étapes, et un appel direct suffit ?". Sachez quel problème vous avez avant de choisir un framework. »
Les agents LangChain sont le bon choix dès que vous avez besoin d'au moins deux de ces éléments :
Préférez le SDK du fournisseur quand :
En 2026, les agents LangChain ne sont plus un jouet de tutoriel. Avec create_agent, le tool calling natif, l'état avec checkpoints, la sortie structurée, le streaming et les middlewares, le framework couvre désormais tout ce dont un agent de production a besoin. La courbe d'apprentissage est réelle — surtout sur la conception des outils et le modèle de checkpoints de LangGraph — mais le résultat est un agent que vous pouvez observer, mettre en pause, confier à un humain et basculer sur un autre modèle sans réécrire votre code. Une base solide pour n'importe quel MVP en IA.
IdeaToMVP Academy
4-week live cohort for founders. Learn to ship AI agents, scope MVPs, and automate your business — taught by the same team that writes these guides.