A plain LLM call is a straight line: prompt in, text out. An agent is a loop — it plans, takes an action, observes the result, and decides what to do next. LangGraph models that loop as a state graph with explicit nodes and edges, including cycles.
Why a graph and not a while-loop
You can write the loop by hand, but you quickly want: persistence across steps, the ability to pause for a human, streaming of intermediate state, and a way to see what happened. A graph gives you all of that because every transition is first-class and inspectable.
The core loop
The classic control loop maps cleanly onto graph nodes:
┌──────── plan ◀──────── reflect ◀───┐
▼ │
act ───────▶ observe ──────────────────┘
- plan — decide the next step from the current state
- act — call a tool (search, retriever, API)
- observe — write the tool result back into state
- reflect — check progress; loop again or finish
State is the whole game
Every node reads and writes a shared, typed state object. In Python that’s often
a TypedDict; the graph merges each node’s return into it.
from typing import TypedDict, Annotated
import operator
class AgentState(TypedDict):
question: str
steps: Annotated[list, operator.add] # appended, not overwritten
answer: str | None
A conditional edge inspects the state and routes: keep looping, or stop.
Where this connects to RAG
Static RAG always retrieves once, up front. An
agentic RAG loop can decide whether it needs to retrieve, issue a better
query after reading the first results, and stop when it has enough — which is
exactly the Ask-My-Notes agent I’m building.
Open questions
- How much reflection is worth the extra latency and tokens?
- Good stop conditions that avoid infinite loops.
- Checkpointing so a run can resume after a failure.