LangGraph
API en mouvement. Le cœur —
StateGraph, nœuds, arêtes conditionnelles, checkpointer — est stable. Vérifier les détails sur docs.langchain.com.
Orchestration d'agents comme graphe d'états. Là où une chaîne LCEL est un pipeline linéaire, LangGraph autorise les cycles, les branchements et la reprise après interruption.
L'idée
Un état partagé, des nœuds qui le transforment, des arêtes qui décident du nœud suivant. Chaque nœud reçoit l'état et renvoie les clés qu'il modifie, pas l'état entier.
uv add langgraph langchain-anthropic
Graphe minimal
from typing import Annotated, TypedDict
from operator import add
from langgraph.graph import StateGraph, START, END
class State(TypedDict):
site: str
steps: Annotated[list[str], add] # les mises à jour s'accumulent
verdict: str | None
def navigate(state: State) -> dict:
return {"steps": [f"ouverture de {state['site']}"]}
def judge(state: State) -> dict:
return {"verdict": "findable" if len(state["steps"]) < 5 else "unreachable"}
builder = StateGraph(State)
builder.add_node("navigate", navigate)
builder.add_node("judge", judge)
builder.add_edge(START, "navigate")
builder.add_edge("navigate", "judge")
builder.add_edge("judge", END)
graph = builder.compile()
print(graph.invoke({"site": "versace.com", "steps": [], "verdict": None}))
{'site': 'versace.com', 'steps': ['ouverture de versace.com'], 'verdict': 'findable'}
Annotated[list, add] est le mécanisme central : sans le réducteur, chaque nœud
écraserait steps. Avec, les listes se concatènent. Pour les messages,
langgraph.graph.message.add_messages gère aussi la déduplication par id.
Branchement conditionnel
def should_retry(state: State) -> str:
if state["verdict"] == "unreachable" and len(state["steps"]) < 20:
return "navigate"
return END
builder.add_conditional_edges("judge", should_retry, ["navigate", END])
La fonction renvoie le nom du nœud suivant. C'est ce qui crée les cycles, et donc les boucles d'agent.
Boucle agent avec outils
from langgraph.prebuilt import create_react_agent
from langchain_core.tools import tool
@tool
def click(selector: str) -> str:
"""Clique sur un élément et retourne le nouvel état de la page."""
return f"cliqué sur {selector}"
agent = create_react_agent(llm, tools=[click])
out = agent.invoke({"messages": [("user", "Trouve Najim 100 ml sur versace.com")]})
print(out["messages"][-1].content)
create_react_agent monte la boucle standard : le modèle propose un appel, un nœud
ToolNode l'exécute, le résultat repart au modèle, jusqu'à une réponse sans tool call.
Pour tout contrôle fin — budget d'étapes, vérification, sous-agents — écrire le graphe à la
main.
Persistance et reprise
from langgraph.checkpoint.memory import MemorySaver
graph = builder.compile(checkpointer=MemorySaver())
config = {"configurable": {"thread_id": "session-42"}}
graph.invoke({"site": "versace.com", "steps": [], "verdict": None}, config)
graph.invoke({"site": "dior.com"}, config) # reprend le même fil
print(graph.get_state(config).values["steps"])
Le thread_id identifie une conversation. En production, remplacer MemorySaver par un
checkpointer SQLite ou Postgres pour survivre au redémarrage.
Interruption humaine
graph = builder.compile(checkpointer=MemorySaver(), interrupt_before=["judge"])
graph.invoke(initial, config) # s'arrête avant "judge"
state = graph.get_state(config)
graph.update_state(config, {"verdict": "override"})
graph.invoke(None, config) # None = reprendre où on s'est arrêté
C'est le mécanisme des portes d'approbation avant une action irréversible — indispensable dès qu'un agent écrit quelque part.
Suivre l'exécution
for event in graph.stream(initial, config, stream_mode="values"):
print(event["steps"][-1] if event["steps"] else "…")
stream_mode : values (l'état complet à chaque étape), updates (seulement les deltas),
messages (les tokens du LLM).
Budget d'étapes
graph.invoke(initial, {"recursion_limit": 25, **config})
Au-delà, GraphRecursionError. Un agent qui boucle sans progresser est le mode d'échec par
défaut — le budget est une sécurité, pas une optimisation.
Visualiser
print(graph.get_graph().draw_mermaid())
graph TD;
__start__ --> navigate;
navigate --> judge;
judge -.-> navigate;
judge -.-> __end__;
Utile en démo client : le diagramme se colle tel quel dans un document.
LangChain ou LangGraph
Chaîne linéaire, un aller-retour, pas d'état : LCEL suffit. Cycles, outils, reprise après échec, validation humaine : LangGraph. Les deux se composent — un nœud de graphe peut être une chaîne LCEL.