Duration: 4 hours | Difficulty: Advanced | Prerequisites: Modules 08–09
Learning Objectives
By the end of this module, you will be able to:
- Explain why LangGraph adds state machines on top of LangChain runnables
- Build graphs with nodes, edges, and conditional routing
- Implement checkpointing for durable agent runs
- Design human-in-the-loop approval steps
- Run parallel branches and subgraphs when tasks fork
1. Why LangGraph?
Chains are DAGs of runnables. Agents need cycles (retry, revisit tools) and mutable state across turns. LangGraph models your workflow as a graph with explicit state—easier to pause, resume, and audit than a raw while loop.
| LangChain LCEL | LangGraph |
|---|---|
| Great for linear pipes | Great for loops + branches |
| You manage memory manually | First-class State + checkpointers |
| Hard to “pause here” | Built for human approvals |
Fun Fact: “Compile” on a graph is like building a tiny virtual machine your LLM steps through.
2. Core Concepts: State, Nodes, and Edges
- State: Typed dict (often
TypedDict) merged after each node. - Node: Python callable
state -> partial state update. - Edge: Deterministic transition.
- Conditional edge: Function returns next node name.
Key Example: Three-node creative pipeline with a review loop cap—shows
add_messages, conditional routing, andEND.
[object Object], typing ,[object Object], Annotated, TypedDict
,[object Object], langgraph.graph ,[object Object], StateGraph, START, END
,[object Object], langgraph.graph.message ,[object Object], add_messages
,[object Object], langchain_openai ,[object Object], ChatOpenAI
llm = ChatOpenAI(model=,[object Object],, temperature=,[object Object],, api_key=,[object Object],)
,[object Object], ,[object Object],(,[object Object],):
messages: Annotated[,[object Object],, add_messages]
next_step: ,[object Object],
draft: ,[object Object],
iteration: ,[object Object],
,[object Object], ,[object Object],(,[object Object],) -> ,[object Object],:
resp = llm.invoke(
state[,[object Object],]
+ [{,[object Object],: ,[object Object],, ,[object Object],: ,[object Object],}]
)
,[object Object], {,[object Object],: [resp], ,[object Object],: resp.content}
,[object Object], ,[object Object],(,[object Object],) -> ,[object Object],:
resp = llm.invoke(
[
{,[object Object],: ,[object Object],, ,[object Object],: ,[object Object],},
{,[object Object],: ,[object Object],, ,[object Object],: state.get(,[object Object],, ,[object Object],)},
]
)
,[object Object], {,[object Object],: resp.content, ,[object Object],: [resp]}
,[object Object], ,[object Object],(,[object Object],) -> ,[object Object],:
draft = state.get(,[object Object],, ,[object Object],)
resp = llm.invoke(
[
{,[object Object],: ,[object Object],, ,[object Object],: ,[object Object],},
{,[object Object],: ,[object Object],, ,[object Object],: draft},
]
)
it = state.get(,[object Object],, ,[object Object],) + ,[object Object],
revise = ,[object Object], ,[object Object], resp.content.upper() ,[object Object], it < ,[object Object],
,[object Object], {,[object Object],: [resp], ,[object Object],: ,[object Object], ,[object Object], revise ,[object Object], ,[object Object],, ,[object Object],: it}
,[object Object], ,[object Object],(,[object Object],) -> ,[object Object],:
,[object Object], ,[object Object], ,[object Object], s.get(,[object Object],) == ,[object Object], ,[object Object], END
g = StateGraph(AgentState)
g.add_node(,[object Object],, researcher)
g.add_node(,[object Object],, writer)
g.add_node(,[object Object],, reviewer)
g.add_edge(START, ,[object Object],)
g.add_edge(,[object Object],, ,[object Object],)
g.add_edge(,[object Object],, ,[object Object],)
g.add_conditional_edges(,[object Object],, route_review, {,[object Object],: ,[object Object],, END: END})
app = g.,[object Object],()
out = app.invoke(
{
,[object Object],: [{,[object Object],: ,[object Object],, ,[object Object],: ,[object Object],}],
,[object Object],: ,[object Object],,
,[object Object],: ,[object Object],,
,[object Object],: ,[object Object],,
}
)
,[object Object],(out[,[object Object],][:,[object Object],])3. Conditional Routing
Same pattern as support bots: classify → specialist nodes. Keep class labels in an enum-like set so your graph doesn’t sprawl.
| Pattern | Use when |
|---|---|
| LLM router | Fuzzy intents |
| Rules router | Cheap, deterministic |
4. Checkpointing and Persistence
Compile with a checkpointer (memory, SQLite, Postgres) to save state after each super-step. Enables:
| Feature | User-visible win |
|---|---|
| Resume after crash | No duplicate charges / emails |
| Time travel | Debug “what did state look like before tool X?” |
Concept: Checkpointing turns agents from scripts into durable workflows.
5. Human-in-the-Loop
Insert interrupt_before / interrupt_after on nodes so execution pauses until an operator approves (API webhook, CLI, internal dashboard).
| Good HITL moment | Bad HITL moment |
|---|---|
| Send email / transfer funds | Every trivial retrieval |
6. Parallel Execution
Fan-out with Send API (per docs) or run independent nodes whose outputs merge in state reducers—great for “research three sources in parallel.”
| Parallel | Watch |
|---|---|
| Faster wall clock | Rate limits + duplicate work |
7. Subgraphs
Embed a graph as a node in a parent graph—useful for “billing sub-flow” vs “technical sub-flow” each with internal complexity.
Try This! Sketch your subgraph boundaries on paper before you nest—deep graphs are hard to trace.
Practice Exercises
Exercise 1: Simple StateGraph (Beginner)
Two-node linear graph logging state after each step.
Exercise 2: Intent Router (Intermediate)
Three handlers + fallback node.
Exercise 3: Human Approval Node (Intermediate)
Pause before send_notification.
Exercise 4: Parallel Research (Advanced)
Three retrievers → merge → single writer.
Exercise 5: Nested Subgraphs (Advanced)
Outer “project” graph, inner “ticket” graph.
Mini-Project: Content Generation Pipeline
Research → draft → legal-lite review → optional human gate → publish stub. Persist with SQLite checkpointer.
Key Takeaways
Key Takeaway
- LangGraph = explicit state machine for LLM workflows.
- Conditional edges replace fragile string parsing in agent loops.
- Checkpointing enables resume, audit, and HITL.
- Parallel + subgraph patterns match how teams actually ship.
- If you can’t draw it as a graph, code will fight you—draw first.