LangGraph

LangGraph is LangChain’s extension for building stateful, multi-step agent workflows. Where a LangChain chain is a linear sequence, LangGraph adds cycles, branching, persistence, and human-in-the-loop.

You need LangGraph when:

  • An agent must loop until a condition is met (tool calls, retries)
  • A workflow needs human approval before destructive actions
  • State must survive across requests (checkpointers)
  • Multiple agents work in parallel (fan-out/fan-in)

What you already know

If you’ve worked through LangChain, these concepts carry over directly:

LangChainLangGraph
ChatOpenAIsame
@toolsame
ChatPromptTemplatesame
Runnablethe StateGraph is a Runnable
FakeListChatModelsame

LangGraph takes the same building blocks and adds a graph execution model on top.

What’s new in LangGraph

  1. State — a TypedDict with optional reducers, not a plain dict
  2. Nodes — functions that read and write state
  3. Edges — unconditional (add_edge) or conditional (add_conditional_edges)
  4. Checkpointer — persists state across calls (MemorySaver, PostgresSaver)
  5. Command — update state and route to a specific node
  6. interrupt() — pause the graph for human-in-the-loop
  7. Send — fan-out to multiple nodes (map-reduce)

Learning path

Work through these files in order. Each builds on the previous:

#FileWhat you learn
101-mental-modelThe four concepts, the agent loop, why cycles need LangGraph
202-state-and-reducersTypedDict state, add_messages, custom reducers
303-nodes-and-edgesadd_node, add_edge, conditional routing, Send
404-tools-and-routingToolNode, tools_condition, bind_tools
505-command-and-interruptsCommand, interrupt(), Command(resume=...)
606-subgraphsSubgraphs, Send fan-out/fan-in
707-streamingstream_mode="messages", astream_events
808-checkpointersMemorySaver, SqliteSaver, PostgresSaver
909-memory-storeInMemoryStore, PostgresStore, cross-thread memory
1010-human-in-the-loopinterrupt() + approval UI, resume
1111-productionCompilation, recursion limits, error handling, deployment
1212-testingFakeListChatModel, graph assertions, no-network

Quick start

from typing import TypedDict
from langgraph.graph import StateGraph, START, END
from langgraph.graph.message import add_messages
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
 
class AgentState(TypedDict):
    messages: Annotated[list, add_messages]
 
llm = ChatOpenAI(model="gpt-4o")
 
def call_model(state: AgentState) -> dict:
    response = llm.invoke(state["messages"])
    return {"messages": [response]}
 
builder = StateGraph(AgentState)
builder.add_node("call_model", call_model)
builder.add_edge(START, "call_model")
builder.add_edge("call_model", END)
graph = builder.compile()
 
result = graph.invoke({"messages": [HumanMessage(content="hi")]})
print(result["messages"][-1].content)

Prerequisite knowledge

  • Python async (async def, await, async for)
  • LangChain core concepts: BaseMessage, AIMessage, ToolMessage, HumanMessage, @tool, ChatOpenAI, Runnable
  • See LangChain to learn these first