LangGraph Setup Guide
Complete setup and configuration guide for LangGraph — LangChain's low-level orchestration framework for building stateful agents. Graph-based, durable execution, checkpointing, and human-in-the-loop.
LangGraph
LangGraph is LangChain's low-level framework for building stateful, long-running agents. Instead of role-based or conversation-based coordination, LangGraph models agents as directed graphs — nodes are steps, edges are transitions, and state flows through. Built-in checkpointing means agents survive crashes and resume from exactly where they left off.
Companies like Klarna, Replit, and Elastic run LangGraph in production. For a higher-level agent framework built on top of LangGraph, see Deep Agents — same graph engine, more opinionated defaults.
Note:
LangGraph is lower-level than CrewAI or AutoGen. You define nodes, edges, and state schemas explicitly. This gives you full control but more code. Use LangGraph when you need durable execution (agents that run for hours), complex conditional routing, or fine-grained state management. Use CrewAI/AutoGen for rapid prototyping.
Installation
Install LangGraph
Python 3.10+ required. Install the core package plus a model provider.
pip install langgraph langchain-openai
Configure API Keys
LangGraph is model-agnostic. Set keys for your preferred provider.
export OPENAI_API_KEY=sk-...
# or for Anthropic
export ANTHROPIC_API_KEY=sk-ant-...
Verify Installation
Build a minimal graph that routes based on LLM output.
from langgraph.graph import StateGraph, END
from typing import TypedDict
class State(TypedDict):
messages: list
def chat_node(state):
# Your LLM logic here
return {"messages": state["messages"] + [{"role": "ai", "content": "Hello"}]}
graph = StateGraph(State)
graph.add_node("chat", chat_node)
graph.set_entry_point("chat")
graph.add_edge("chat", END)
app = graph.compile()
Core Concepts
Architecture Overview
Values: StateGraph(StateSchema)
Values: graph.add_node(name, function)
Values: graph.add_edge(from, to) | graph.add_conditional_edges(from, router, mapping)
Values: MemorySaver (dev), SqliteSaver, PostgresSaver (prod)
Building a Graph
A simple agent that decides whether to call a tool or respond directly.
from typing import TypedDict, Literal, Annotated
from langgraph.graph import StateGraph, END, add_messages
from langgraph.checkpoint.memory import MemorySaver
from langchain_openai import ChatOpenAI
class AgentState(TypedDict):
messages: Annotated[list, add_messages]
llm = ChatOpenAI(model="gpt-4o")
def call_model(state: AgentState):
response = llm.invoke(state["messages"])
return {"messages": [response]}
def route_after_model(state: AgentState) -> Literal["call_tool", END]:
last_message = state["messages"][-1]
if hasattr(last_message, "tool_calls") and last_message.tool_calls:
return "call_tool"
return END
def execute_tool(state: AgentState):
last_message = state["messages"][-1]
# Execute tool calls and return results
results = []
for tool_call in last_message.tool_calls:
# ... tool execution logic
results.append(f"Tool {tool_call['name']} result: ...")
return {"messages": [{"role": "tool", "content": r} for r in results]}
# Build the graph
graph = StateGraph(AgentState)
graph.add_node("agent", call_model)
graph.add_node("tools", execute_tool)
graph.set_entry_point("agent")
graph.add_conditional_edges("agent", route_after_model, {"call_tool": "tools", END: END})
graph.add_edge("tools", "agent") # Loop back to agent after tools
Checkpointing: Durable Execution
A checkpointer persists graph state after every super-step. If your process crashes mid-execution, resume with the same thread ID and the graph picks up where it left off.
from langgraph.checkpoint.sqlite import SqliteSaver
# Dev: in-memory (lost on restart)
checkpointer = MemorySaver()
# Production: SQLite or Postgres (survives restarts)
checkpointer = SqliteSaver.from_conn_string("checkpoints.db")
app = graph.compile(checkpointer=checkpointer)
# First run
config = {"configurable": {"thread_id": "user-123"}}
result = app.invoke({"messages": [{"role": "user", "content": "Research AI trends"}]}, config)
# If the process crashes here, restart and resume:
result = app.invoke(None, config) # Picks up from last checkpoint
Human-in-the-Loop
Interrupt graph execution at a specific node and wait for human approval before continuing.
from langgraph.types import interrupt, Command
def sensitive_action(state: AgentState):
# This node requires human approval
approval = interrupt(f"Approve this action? State: {state}")
if approval != "yes":
return {"messages": [{"role": "ai", "content": "Action rejected by human."}]}
# ... proceed with sensitive action
# The graph pauses at interrupt(). Resume with:
app.invoke(Command(resume="yes"), config)
Memory
LangGraph supports two memory layers:
Memory Types
Values: StateGraph(StateSchema)
Values: Store (InMemoryStore for dev, PostgresStore for prod)
Model Wiring
LangGraph is model-agnostic — use any LangChain chat model.
# OpenAI
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-4o", temperature=0)
# Anthropic
from langchain_anthropic import ChatAnthropic
llm = ChatAnthropic(model="claude-sonnet-4-20250514")
# Google
from langchain_google_genai import ChatGoogleGenerativeAI
llm = ChatGoogleGenerativeAI(model="gemini-2.5-flash")
# Ollama (local)
from langchain_ollama import ChatOllama
llm = ChatOllama(model="llama3.2", base_url="http://localhost:11434")
# All are dropped into the same graph node
def call_model(state):
response = llm.invoke(state["messages"])
return {"messages": [response]}
Note:
Graph complexity. LangGraph's power comes at a cost. A graph with 5 nodes, conditional edges, a checkpointer, and memory is ~100 lines of setup code. For simple chatbots, this is overkill. LangGraph earns its keep when you need durable execution, complex routing, or human-in-the-loop at specific execution points.
Key Takeaway
LangGraph is the right choice when your agent needs to survive restarts or run for extended periods. The checkpointing system means crash recovery is automatic — no custom retry logic. Pair it with LangSmith for debugging: visualize every node transition, inspect state at each step, and trace token usage. The tradeoff is verbosity: you define every node and edge explicitly. CrewAI gives you a working agent in 30 lines; LangGraph gives you a production-grade durable agent in 150.
Related Articles
Building Voice-Enabled Agents with OpenAI WebRTC and Document Context
Step-by-step tutorial on using OpenAI's WebRTC Audio Session API with document context injection. Build a voice agent that references uploaded documents during realtime conversations — with streaming audio, context management, and interruption handling.
SkillOpt: Training Agent Skill Documents Like Neural Network Weights
Microsoft's SkillOpt treats a Markdown instruction document as a trainable parameter — applying gradient-free optimization to boost GPT-5.5 by +24.8 points. Here's how it works, when to use it, and how to run it yourself.
Research Agent Blueprint
Complete research agent blueprint with web search, content extraction, fact-checking, and citation. Ready-to-run Python implementation with OpenAI function calling.