~/wiki

LangGraph

Mis à jour le 2026-08-07Confiance : medium
langgraphagentsstate-machinellmorchestrationcheckpointerhuman-in-the-loop

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.

See also