learn.chetana.fr

StateGraph : le workflow comme graphe d'états

15 min readCore

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 ?

  1. 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) ;
  2. ÉvolutivitĂ© de topologie : ajouter un node « OCR si scannĂ© » = un edge conditionnel, pas une réécriture ;
  3. Testabilité : chaque node se teste isolément avec un state d'entrée fabriqué ;
  4. Persistance : le checkpointer (leçon 3) sauvegarde le state Ă  chaque Ă©tape — impossible avec une pile d'appels.
đŸ§© Quiz1/3

Un node LangGraph bien conçu retourne


🃏 Flashcards1/4