Why LangGraph
Start here. The mistake most people make is treating LangGraph as “LangChain but newer”. It is not a chain library — it is a state machine runtime for LLM applications, and everything else follows from that.
Verified against LangGraph 1.3.x / LangChain 1.3.x, 2026-08.
The problem it solves
A chain is a fixed pipeline: A then B then C. That works until you need one of these, and then it does not work at all:
| You need | A chain cannot |
|---|---|
| Loop until done | repeat a step |
| Branch on a result | choose the next step |
| Pause for a human | stop and resume later |
| Survive a restart | remember where it was |
| Stream partial state | expose intermediate steps |
Every one of those is a control-flow requirement. LangGraph’s answer is to make control flow the thing you declare: nodes are work, edges are the transitions between them, and the runtime owns execution.
The three ideas
State a typed dict, passed to every node
Nodes functions: state in, state update out
Edges what runs next — fixed or conditionalThat is the entire model. A node never calls the next node; it returns an update and the runtime decides what runs. This indirection is what buys you checkpointing, resumption, streaming and time travel — the runtime can pause between any two nodes because it owns the transition.
All three, in the smallest graph that a chain could not express:
from typing import Annotated, TypedDict
from langgraph.graph import END, START, StateGraph
class State(TypedDict):
tries: Annotated[int, lambda a, b: a + b]
def work(state: State) -> dict:
return {"tries": 1} # an update, not a write
def more(state: State) -> str:
return "work" if state["tries"] < 3 else END
g = StateGraph(State)
g.add_node("work", work)
g.add_edge(START, "work")
g.add_conditional_edges("work", more)
app = g.compile()work returns {"tries": 1} every time and the counter still reaches 3,
because the reducer adds rather than overwrites. And more is what a chain has
no place to put: the decision about what runs next, written as data.
Where it sits
| Layer | What it is |
|---|---|
| LangChain | model, tool and prompt abstractions |
| LangGraph | the runtime: state, control flow, durability |
create_agent |
a prebuilt graph for the common case |
LangGraph does not depend on LangChain, which is the fact people get wrong. You can run a graph whose nodes call the raw provider SDK, or call no model at all. It is a general orchestration runtime that happens to be convenient for LLM work.
create_agent from langchain.agents is a graph someone already built for
you — the tool-calling loop. Reach for it first; drop to StateGraph when the
shape stops fitting. See
create_agent and middleware.
The honest framing for an interview
“A chain is a pipeline I wrote the order of. An agent is a loop where the model picks the order. LangGraph is the runtime underneath both — it lets me put the control flow on a spectrum instead of choosing between a rigid pipeline and a free-running loop.”
That spectrum is the point. Most production “agents” are a graph with two or three explicit edges and one routing decision — cheaper, faster and testable, with the model deciding only where it genuinely must. See What is an agent.
When not to use it
Say this unprompted; it is a seniority signal.
- One model call. Call the SDK. A graph adds a dependency and a mental model for nothing.
- A fixed three-step pipeline that never branches. Three functions and two
awaits are clearer than a graph, and easier to test. - You need cross-provider portability above all. LangGraph is a real commitment — see The agent framework landscape.
- The team cannot debug it. A graph you cannot reason about is worse than procedural code that is merely ugly.
The rule: adopt it when you need durability, human-in-the-loop, or genuine branching. Those three are hard to retrofit and are exactly what the runtime gives you for free.
What 1.0 changed
The API stabilised in October 2025 and the vocabulary moved with it. Two things matter for anyone reading older material:
create_react_agentis the pre-1.0 name. The front door is nowcreate_agentfromlangchain.agents. Saying the old one out loud dates your knowledge.- Middleware replaced subclassing as the way to customise the agent loop.
Anything importing from langchain.llms or from langchain.text_splitter is
pre-1.0 material; integrations live in their own packages now
(langchain-openai, langchain-anthropic).
The reading order
- State and reducers — the data model
- Nodes, edges and routing — control flow
- create_agent and middleware — the shortcut
- Persistence and threads — memory
- Human in the loop — pausing
- Streaming — showing progress
- Multi-agent and subgraphs — composition
- Production and debugging — shipping it
Related
Interview angle 5
- “What is LangGraph?” - a state machine runtime for LLM applications, not a chain library. You declare state, nodes and edges; the runtime owns execution, which is what makes checkpointing, resumption and streaming possible at all.
- “Why not just write the loop yourself?” - for a simple loop, do. LangGraph earns its place when you need durability, human-in-the-loop, or real branching — those three are painful to retrofit and are what the runtime provides for free.
- “Does it require LangChain?” - no. LangGraph is the runtime and can orchestrate nodes that call raw provider SDKs or no model at all. LangChain supplies model and tool abstractions on top.
- “Chain, agent or graph?” - a chain is an order I wrote, an agent is an order the model picks, and a graph lets me put the control flow anywhere on that spectrum. Most production agents are a graph with explicit edges and one routing decision.
- “What changed at 1.0?” -
create_agentreplacedcreate_react_agentas the front door, middleware replaced subclassing for customisation, and integrations moved into their own packages.