// AI NATIVE STACK

AI Native › AI Agent › Agent Framework › LangGraph

CRASH COURSE · AI-NATIVE · intermediate · 18 min read · v0.3

LangGraph — build agents as explicit state machines.

agent-framework ai-native langgraph agents state-machine python

TL;DR — LangGraph is the low-level runtime underneath LangChain's create_agent(). Where LangChain gives you a one-liner agent, LangGraph lets you define the agent as an explicit graph — nodes are functions, edges are conditional transitions, state is typed and checkpointed. Use it when you need branching, parallelism, human-in-the-loop gates, or multi-agent coordination that a linear loop can't express.

What it is

LangGraph is a framework for building stateful, multi-step AI applications as directed graphs. Each node is a Python function (or coroutine); edges carry typed state between them; conditional edges let the model's output decide where to go next. The runtime handles persistence, streaming, fault tolerance, and time-travel debugging.

It sits in AI Agent › Agent Framework — the layer where you design the control flow of an agent, deciding exactly which steps happen, in what order, and under what conditions.

S call_model run_tools respond E has tools? no tools loop

Fig 1 — A basic ReAct agent as a LangGraph: call model → conditional branch → tools or respond.

Why it exists

Simple agents follow a loop: call model → run tools → repeat. But real-world agents need more: parallel tool execution, human approval before dangerous actions, sub-agents that coordinate, error recovery with fallback paths. A flat loop can't express these. LangGraph gives you a graph so every branch, gate, and retry is an explicit, visible node — not hidden inside callbacks.

Core concepts

  • State — a typed dict (usually a TypedDict or Pydantic model) that flows between nodes. The graph's "memory" for the current run.
  • Node — a function (state) → partial state update. Does one thing: calls a model, runs tools, formats output.
  • Edge — connects nodes. Normal edges always fire; conditional edges call a router function to pick the next node.
  • Checkpointer — persists state after each node, enabling conversation memory, time-travel, and human-in-the-loop interrupts.

Install & setup

pip install langgraph langchain-openai
export OPENAI_API_KEY=sk-...

Building a basic agent

from typing import Annotated, TypedDict
from langgraph.graph import StateGraph, START, END
from langgraph.graph.message import add_messages
from langchain_openai import ChatOpenAI
from langchain.tools import tool

# 1. Define state
class State(TypedDict):
    messages: Annotated[list, add_messages]

# 2. Define tools
@tool
def search(query: str) -> str:
    """Search the web."""
    return f"Results for: {query}"

# 3. Define nodes
model = ChatOpenAI(model="gpt-4o").bind_tools([search])

def call_model(state: State):
    response = model.invoke(state["messages"])
    return {"messages": [response]}

def run_tools(state: State):
    tool_map = {"search": search}
    last = state["messages"][-1]
    results = []
    for tc in last.tool_calls:
        result = tool_map[tc["name"]].invoke(tc["args"])
        results.append({"role": "tool", "content": result,
                        "tool_call_id": tc["id"]})
    return {"messages": results}

# 4. Build graph
def should_continue(state: State):
    if state["messages"][-1].tool_calls:
        return "tools"
    return END

graph = StateGraph(State)
graph.add_node("model", call_model)
graph.add_node("tools", run_tools)
graph.add_edge(START, "model")
graph.add_conditional_edges("model", should_continue, {"tools": "tools", END: END})
graph.add_edge("tools", "model")

agent = graph.compile()
result = agent.invoke({"messages": [("user", "Search for vLLM news")]})

Persistence & memory

Add a checkpointer and every node's output is saved. Pass a thread_id to maintain conversation history across calls:

from langgraph.checkpoint.memory import MemorySaver

agent = graph.compile(checkpointer=MemorySaver())
config = {"configurable": {"thread_id": "user-42"}}

agent.invoke({"messages": [("user", "My name is Shivam")]}, config=config)
r = agent.invoke({"messages": [("user", "What's my name?")]}, config=config)
# -> "Your name is Shivam"

Human-in-the-loop

Interrupt the graph before a dangerous node. The runtime pauses, waits for approval, then resumes from the checkpoint:

agent = graph.compile(
    checkpointer=MemorySaver(),
    interrupt_before=["tools"]   # pause before running tools
)

result = agent.invoke({"messages": [("user", "Delete old records")]}, config=config)
# graph pauses — inspect result, approve, then:
agent.invoke(None, config=config)   # resume from checkpoint

Subgraphs & multi-agent

A node can itself be a compiled graph. This is how you build multi-agent systems — each sub-agent is a subgraph with its own state, and a parent graph coordinates them:

researcher = build_researcher_graph().compile()
writer     = build_writer_graph().compile()

parent = StateGraph(ParentState)
parent.add_node("research", researcher)
parent.add_node("write", writer)
parent.add_edge(START, "research")
parent.add_edge("research", "write")
parent.add_edge("write", END)
app = parent.compile()

Streaming

for event in agent.stream({"messages": [("user", "Search AI news")]},
                           stream_mode="updates"):
    for node_name, update in event.items():
        print(f"[{node_name}]", update)

LangGraph Platform

For production deployment, LangGraph Platform (formerly LangGraph Cloud) gives you a managed runtime with built-in task queues, cron jobs, a REST API, and LangSmith integration. You deploy your graph; it handles scaling, persistence, and long-running background agents. Self-hosted option available.

When to use, when to skip

Use it when your agent needs branching logic, parallel paths, human gates, sub-agents, or any control flow that a linear tool-calling loop can't express. Also when you want full visibility into exactly what path the agent took.

Skip it for simple agents — create_agent() from LangChain wraps LangGraph and is simpler. If you don't need LangChain's ecosystem at all, consider lighter alternatives like Pydantic AI or raw provider SDKs.

vs the alternatives

ToolBest forTrade-off
LangGraphCustom graphs, branching, multi-agent, max controlMore wiring; steeper learning curve
LangChain create_agentSimple tool-calling agents, quick startLess control over flow
AutoGenMulti-agent conversations, researchDifferent paradigm (chat-based)
CrewAIRole-based agent teamsOpinionated, less low-level
Temporal / HatchetDurable workflow orchestrationNot AI-specific

Verified against the LangGraph docs (langchain-ai.github.io/langgraph), May 2026.

← AI Native Stack
© cvam — written in plaintext, served warm