LangGraph Quick Reference
The core concepts and control-flow patterns in LangGraph — nodes, edges, state, and the conditional routing that makes it different from a plain LangChain chain.
- LangGraph
- LangChain
- Agents
- Python
On this page
LangGraph models an agent as a graph rather than a linear chain. That distinction matters the moment an agent needs to loop, branch, or retry — behavior a plain sequential chain can't express cleanly.
Core building blocks
- State — a shared, typed object (usually a
TypedDictor Pydantic model) that flows through every node. Each node reads from it and returns a partial update, which LangGraph merges back in. This is what replaces passing ad-hoc dictionaries between chain steps. - Nodes — plain functions (or callables) that take the current state and return an update. A node can call an LLM, run a tool, hit an API, or just transform data — LangGraph doesn't care what's inside it.
- Edges — connections between nodes that define execution order. A normal edge always goes to the same next node; a conditional edge picks the next node at runtime based on the current state.
- Graph — the compiled assembly of nodes and edges, built with
StateGraph, which produces a runnable object with.invoke()/.stream().
Minimal skeleton
from typing import TypedDict
from langgraph.graph import StateGraph, END
class AgentState(TypedDict):
query: str
result: str | None
def retrieve(state: AgentState) -> dict:
# ... fetch context, set result
return {"result": "retrieved context"}
def should_continue(state: AgentState) -> str:
return "end" if state["result"] else "retrieve"
graph = StateGraph(AgentState)
graph.add_node("retrieve", retrieve)
graph.add_conditional_edges("retrieve", should_continue, {"retrieve": "retrieve", "end": END})
graph.set_entry_point("retrieve")
app = graph.compile()
app.invoke({"query": "...", "result": None})
Why not just a LangChain chain
A standard chain (prompt | model | parser) is a straight line — fine for "transform input, call the model, format output." It breaks down as soon as you need:
- Loops — e.g. retry a tool call if it errors, or keep refining an answer until a critic node approves it.
- Branching — e.g. route to a different tool node depending on what the model decided to call.
- Shared state across steps that isn't just "the output of the previous step" — e.g. accumulating a list of tool results across several iterations.
LangGraph's explicit state object and conditional edges make these patterns a first-class part of the graph definition instead of something bolted on with manual while loops around a chain.
Checkpointing
LangGraph supports checkpointers (e.g. in-memory, SQLite, Postgres) that persist state between invocations keyed by a thread_id. This is what makes multi-turn agent conversations and human-in-the-loop interrupts possible — the graph can pause mid-execution, return control to the caller, and resume later from the exact same state.
Practical gotchas
- Conditional edge functions must return a key that exists in the edge mapping passed to
add_conditional_edges— a typo there fails silently at the wrong place if you're not careful with typing. - Partial state updates are merged, not replaced — a node that forgets to return an unrelated field won't wipe it, but a node that returns the wrong shape (e.g. a list where a dict is expected) can break the merge for that key.
ENDis a sentinel, not a string — don't try to match on it as plain text in conditional routing logic.