StateGraph : le workflow comme graphe d'états
L'idée : une machine à états explicite
LangGraph modĂ©lise un workflow comme un graphe : des nodes (fonctions) qui transforment un state partagĂ©, reliĂ©s par des edges (dont certains conditionnels). LĂ oĂč une fonction gĂ©ante enchaĂźnerait des if/else opaques, le graphe rend la topologie dĂ©clarĂ©e, visualisable et streamable.
Le state : un TypedDict, contrat de tout le pipeline
from typing_extensions import TypedDict
class UnifiedState(TypedDict, total=False):
# INPUT
context: ContextMetadata
raw_document: str
# EXTRACTION
structured_order: StructuredOrder | None
# MATCHING
match_results: list[MatchResult]
# GLOBAL
status: WorkflowStatus
errors: list[str]
total=False : chaque node ne remplit que sa section. Le state est le contrat central â c'est lui qu'on lit pour comprendre le pipeline (le projet utilise un state « plat » unique partagĂ© par tous les subgraphs, section par section).
Nodes et edges : la topologie du matcher
workflow = StateGraph(UnifiedState)
workflow.add_node("extractor", extract_node) # un FICHIER par node (rĂšgle projet)
workflow.add_node("structurer", structure_node)
workflow.add_node("validator", validate_node)
workflow.add_node("matcher_fast", fast_match_node)
workflow.add_node("matcher_deep", deep_match_node)
workflow.add_edge(START, "extractor")
workflow.add_edge("extractor", "structurer")
workflow.add_conditional_edges(
"matcher_fast",
_should_deep_match, # fonction PURE : lit le state, renvoie une clé
{"deep": "matcher_deep", "done": END},
)
graph = workflow.compile()
Un node = une fonction async qui reçoit le state et retourne un delta (return {"match_results": results}) â LangGraph fusionne. Les dĂ©cisions de routage sont des fonctions pures (_should_deep_match lit le score et renvoie "deep" ou "done") : testables unitairement sans LLM ni DB.
Pourquoi un graphe et pas des appels de fonctions ?
- ObservabilitĂ© : chaque node est une frontiĂšre naturelle de trace/timing (Langfuse, module 7) et d'Ă©vĂ©nement SSE (« matcher_fast terminĂ© » â barre de progression) ;
- ĂvolutivitĂ© de topologie : ajouter un node « OCR si scannĂ© » = un edge conditionnel, pas une réécriture ;
- Testabilité : chaque node se teste isolément avec un state d'entrée fabriqué ;
- Persistance : le checkpointer (leçon 3) sauvegarde le state Ă chaque Ă©tape â impossible avec une pile d'appels.
Un node LangGraph bien conçu retourneâŠ