StateGraph: Blaupause für deklarative Zustandsautomaten
Verantwortung
StateGraph ist die Klasse, mit der LangGraph-Nutzer am häufigsten direkt zu tun haben – sie ist ein Builder (builder), keine Laufzeit. Man registriert an ihr das State-Schema, die Knotenfunktionen, Kanten und bedingten Kanten und ruft dann .compile() auf, um sie in ein CompiledStateGraph (das von Pregel erbt) zu übersetzen. Sie selbst hat kein invoke / stream; um den Graphen laufen zu lassen, muss vorher kompiliert werden (Dokumentwarnung:139-144).
In der Architektur sitzt sie zwischen der Nutzer-API und der Pregel-Engine: Der Nutzer schreibt StateGraph(State).add_node(...).add_edge(...).compile(), und StateGraph ist dafür verantwortlich, jedes State-Feld in eine Channel-Instanz (channel) zu übersetzen, jeden Knoten in ein StateNodeSpec zu wickeln und jede Kante in den Sets edges / waiting_edges / branches abzulegen, bis beim Kompilieren CompiledStateGraph.attach_node / attach_edge / attach_branch die Übersetzung in PregelNode-Abonnements übernimmt (StateGraph Felder:201-213).
Die Kernkonvention von StateGraph ist: Die Signatur eines Knotens ist State -> Partial<State>, und an jedem State-Feld kann optional über Annotated[type, reducer] eine Reduce-Funktion angegeben werden; wenn mehrere Knoten dasselbe Feld schreiben, wird über reducer zusammengeführt statt überschrieben (Klassen-Docstring:131-138). Dieser reducer-Mechanismus ist der Ursprung der beiden Channel-Typen LastValue (Default: überschreiben) und BinaryOperatorAggregate (z. B. operator.add).
Entwurfsmotivation
Warum nicht einfach Funktionsaufrufketten schreiben, sondern der Umweg über «Zustandsautomat + Channel»?
- Knoten sind entkoppelt: Ein Knoten kennt nur den State, nicht andere Knoten; wer wann läuft, wird durch Kanten bestimmt – eine Änderung des Ablaufs erfordert keine Änderung des Knotencodes. Das ist der zentrale Gewinn eines Zustandsautomaten (state machine).
- reducer gibt parallelen Schreibvorgängen eine Definition: Schreiben mehrere Knoten im selben Superstep in das Feld
messagesund ist es alsAnnotated[list, operator.add]markiert, weiß die Engine, dass+anzuwenden ist statt «der spätere Write überschreibt den früheren» (reducer Doku:135-137). Felder ohne reducer verwenden den ChannelLastValue; das Verhalten ist «mehrere Schreibvorgänge im selben Superstep werfen einen Fehler» oder «überschreiben», je nach Channel-Typ. - Validierung zur Build-Zeit: Beim compile führt
validate()(validate:1116-1162) Prüfungen durch – «Start- und Endpunkt jeder Kante sind in nodes vorhanden», «START muss Startpunkt einer Kante sein», «Interrupt-Knoten existieren» – und fängt Fehler vor dem Lauf ab. - Schema-Trennung input/output/state: Derselbe Graph kann
input_schema ≠ state_schema ≠ output_schemahaben (schema Eingaben:217-221); eine schmale Außenschnittstelle bei breitem internen State ist ein gängiges Muster für Agenten, bei denen das LLM-gerichtete Eingabe-Schema nicht dem intern akkumulierten State entspricht. - Method Chaining:
add_node/add_edge/add_conditional_edgesgeben alleSelfzurück (Returns Self:749) – verkettete Aufrufe werden unterstützt, und der Aufbau eines Graphen liest sich wie eine Konfigurationsdatei statt wie eine imperative Sequenz.
Schlüsseldateien
StateGraph Klassendefinition:130-144—Generic[StateT, ContextT, InputT, OutputT]; der Docstring stellt klar «Builder, nicht direkt invoke-fähig».Klassenfelder:201-213— Die sieben zentralen Containeredges/nodes/branches/channels/managed/schemas/waiting_edges.__init__:215-269— Empfängtstate_schema/context_schema/input_schema/output_schema; alte Namenconfig_schema/input/outputwerden in neue Namen umgewandelt und mit Warnung versehen; über_addSchemawerden die drei Schemas state/input/output inchannels/managedregistriert._add_schema:342-372— Nutzt_get_channels, um aus einem Schema Channels + Managed Values abzuleiten; bei Konflikten ist alles außerLastValueein Fehler.validate:1116-1162— Validierung vor dem compile: iteriert über alle Edge-Quellen/-Ziele, prüft das Vorhandensein von START, prüft, ob Interrupt-Knoten existieren; setzt am Endeself.compiled = True.set_node_defaults:271-334— Setzt Default-Policies für retry / cache / error_handler / timeout für den gesamten Graphen; niedrigere Priorität als explizite Parameter anadd_node.compile Signatur:1164-1217— Empfängtcheckpointer/store/cache/interrupt_before/interrupt_after/nameetc. und gibt einCompiledStateGraphzurück.CompiledStateGraph:1391-1409— Erbt vonPregel; fügt lediglich die Felderbuilder/schema_to_mapperund input/output-JSON-Schema-Methoden hinzu.attach_node:1431-1470— Übersetzt zur Compile-Zeit denStateNodeSpecin einenPregelNodeund definiert_get_updates, das entscheidet, welche Channels aus dem Rückgabewert des Knotens beschrieben werden.BranchSpec.from_path:83-120— Übersetztpath(Runnable) undpath_mapvonadd_conditional_edgesin ein Dict «Bedingung → Zielknoten»; ohnepath_mapwird versucht, aus dem RückgabetypLiteral[...]abzuleiten.
Datenfluss
Nachstehend der zentrale Abschnitt, in dem StateGraph.__init__ das Schema als Channels registriert – hier findet die Übersetzung «State-Feld → Channel-Instanz» statt:
self.nodes = {}
self.edges = set()
self.branches = defaultdict(dict)
self.schemas = {}
self.channels = {}
self.managed = {}
self.compiled = False
self.waiting_edges = set()
self.state_schema = state_schema
self.input_schema = cast(type[InputT], input_schema or state_schema)
self.output_schema = cast(type[OutputT], output_schema or state_schema)
self.context_schema = context_schema
self._node_defaults: _NodeDefaults = _NodeDefaults()
self._add_schema(self.state_schema)
self._add_schema(self.input_schema, allow_managed=False)
self._add_schema(self.output_schema, allow_managed=False)Jedes Schema wird von _add_schema in das Tripel (channels, managed, type_hints) zerlegt; channels geht ins Dict self.channels, managed ins self.managed. Bei wiederholter Registrierung desselben Keys ist nur LastValue kompatibel:
self.schemas[schema] = {**channels, **managed}
for key, channel in channels.items():
if key in self.channels:
if self.channels[key] != channel:
if isinstance(channel, LastValue):
pass
else:
raise ValueError(
f"Channel '{key}' already exists with a different type"
)
else:
self.channels[key] = channel(_add_schema Registrierlogik:353-364)
Grenzen und Fehler
StateGraphist nicht direktinvoke-fähig (warning:139-144); es muss.compile()aufgerufen werden; die direkte Nutzung als Runnable lässt Laufzeitfelder wienodesvermissen.- Konflikte bei State-Feldnamen werfen (
channel Konflikt:360-362), es sei denn, beide sindLastValue– das verhindert inkonsistentes implizites Verhalten, wenn derselbe Key in zwei Schemas unterschiedliche reducer hat. input_schema/output_schemadürfen keine Managed Channels haben (managed Prüfung:346-352); managed ist dem State vorbehalten, da diese Channels keine reinen Wert-Kanäle sind, sondern Objekte mit Lebenszyklus wieContextManager.- Der alte Name
config_schemaist veraltet (config_schema deprecated:224-231); seit v1.0 wird aufcontext_schemaverwiesen, in 2.0 wird er entfernt. compile()auf einem bereits kompilierten Graphen fügt nur eine Warnung hinzu, keinen Fehler (compiled warning:932-936);add_node/add_edgegebenAdding ... to a graph that has already been compiledaus, ohne die bereits kompilierte Instanz zu beeinflussen – eine häufige Falle bei falscher Reihenfolge in verketteten Aufrufen.- validate verlangt mindestens eine Kante, die von START ausgeht (
entrypoint Prüfung:1129-1132);Graph must have an entrypoint, sonst ist nicht klar, wo die Ausführung beginnen soll.
Zusammenfassung
StateGraph ist eine deklarative Blaupause für Zustandsautomaten: Man übergibt Schema, Knoten und Kanten, und es übersetzt sie in PregelNode + Channel-Abonnements, die Pregel ausführen kann. Seine Existenz erspart es dem Nutzer, direkt mit dem Actor-Modell von Pregel konfrontiert zu werden; er kümmert sich nur um drei Dinge – State-Felder, Knotensignaturen und Kanten.
Weiter geht es mit add_node / add_edge / add_conditional_edges, wie diese Blaupause mit Inhalt gefüllt wird, sowie mit compile, wie sie zu Pregel kompiliert wird. Das gesamte Ausführungsmodell steht in Pregel 引擎.
Siehe offizielle Dokumentation: LangGraph 文档 · README.