LangGraph Agents

Course Content

LangGraph Agents

7 sections · 49 lessons

What makes LangGraph “stateful,” and why is state central to its design?


What you need to know

Python
import operatorfrom typing import Annotated, TypedDictfrom langgraph.graph.message import add_messagesclass ClaimState(TypedDict):    messages: Annotated[list, add_messages]    # append, match by message id    documents: Annotated[list, operator.add]   # concatenate lists    fraud_score: float                          # no reducer: overwrite    attempts: int

A node that returns {"fraud_score": 0.12} changes only that key. A node that returns {"documents": ["bill.pdf"]} adds to the list instead of replacing it, because that key has operator.add as its reducer.

Why the design is built on state

  • Loops need memory. A revise loop must know how many times it has run; that counter lives in state.
  • Routing is data. A conditional edge reads state["fraud_score"] and picks the next node. The decision is visible in the saved state, not hidden in Python control flow.
  • Persistence saves state. After every super-step the checkpointer serialises the whole state. That is what lets a run pause for a human, recover after a crash, or be replayed from an earlier step.
  • Nodes stay simple. A node is a plain function from state to an update. It can be unit-tested with a dictionary.

What should not go in state

State is saved to a database many times per run. Keep it small and serialisable: store a document id, not a 20 MB PDF; never store database connections, API clients or secrets. Pass those through the runtime context or config instead.

A real-life example

A health insurer's claim workflow runs over three days: intake, document check, fraud scoring, a human adjuster's decision, then payout. The state holds claim_id, a list of document ids, fraud_score, adjuster_decision and status. On day one the run pauses at the adjuster step. On day three a different server loads the saved state by thread_id="claim-88213", sees fraud_score = 0.12 and the three document ids, and continues with the payout node. Nothing had to be recomputed, because everything the next step needed was in state, not in a process's memory.

Follow-up questions to expect

  • "Can the state be a Pydantic model?" — Yes. TypedDict, dataclasses and Pydantic models all work. Pydantic validates input at runtime but is slower; TypedDict is the common default.
  • "What happens if a node returns a key that is not in the schema?" — In LangGraph 1.x it is silently dropped, with no error. So a typo such as fraud_socre loses data quietly; unit tests on node outputs catch it.
  • "Where do secrets and clients go?" — In the runtime context (context_schema) or config, never in state, because state is written to the checkpoint store.