Why LangGraph?
Most agent frameworks chain LLM calls linearly: call LLM, parse output, call tool, repeat. This breaks for complex tasks requiring loops, branching, or manual approval. LangGraph models agents as state graphs where each node is a computation step and edges define control flow.
The key innovations are state persistence across steps, conditional edges that route based on output content, and built-in checkpointing for pause-and-resume.
Installing and Setup
pip install langgraph langchain langchain-openai
Python 3.10+ is required. LangGraph runs entirely locally — no external server needed.
Defining Your State Graph
Every LangGraph application starts with a state definition. The state is a typed dictionary that flows through all nodes:
from typing import TypedDict, Literal
from langgraph.graph import StateGraph, END
class AgentState(TypedDict):
input: str
messages: list
output: str
steps: int
This state carries the user's input, the conversation history, the final output, and a step counter for loop control.
Building Nodes
Nodes are Python functions that receive the state and return updates. Each node focuses on one task:
call_llm— evaluates the current state and decides the next actionexecute_tool— runs external API calls (search, calculator, database)should_continue— a conditional edge function that routes tocontinueorend
Conditional Routing
Conditional edges are what make LangGraph powerful. A routing function inspects the state and returns the next node name:
def route(state):
if 'SEARCH' in state['messages'][-1]:
return 'search_tool'
elif 'CODE' in state['messages'][-1]:
return 'code_executor'
else:
return END
graph.add_conditional_edges('call_llm', route)
The agent dynamically chooses paths based on LLM output.
Adding Memory and Checkpointing
LangGraph supports persistent memory via checkpointing. This enables pause-and-resume, human-in-the-loop approvals, and debugging:
from langgraph.checkpoint import MemorySaver
memory = MemorySaver()
graph = builder.compile(checkpointer=memory)
config = {'configurable': {'thread_id': 'session_1'}}
for event in graph.stream({'input': 'Analyze this data'}, config):
print(event)
Each checkpoint saves the full state so you can replay or inspect any step.
Human-in-the-Loop Patterns
A common pattern is pausing execution for human approval before executing destructive tools:
def human_approval(state):
print(f'About to execute: {state["next_action"]}')
approval = input('Approve? (y/n): ')
if approval.lower() != 'y':
return 'revise_prompt'
return 'execute_tool'
Wrap the node with interrupt_before to pause before sensitive steps. Essential for production agents that might issue API calls or modify databases.
Parallel Execution
LangGraph supports fan-out patterns where multiple nodes run in parallel:
graph.add_node('search_web')
graph.add_node('search_docs')
graph.add_node('search_vector_db')
graph.add_edge('call_llm', 'parallel_search')
Each search node runs concurrently. A merge function combines results into a unified state update.
Performance Tips
- Keep node functions pure — avoid side effects beyond the state update
- Use
checkpointer=Nonefor simple stateless chains to reduce overhead - For production, use
SQLiteSaverinstead ofMemorySaverto survive restarts - Limit graph depth to under 20 nodes for predictable latency
Real-World Example
A customer support agent built with LangGraph processes incoming tickets through classification, knowledge base search, escalation decision, and response generation — all with manual override at each stage. A startup using this pattern reduced ticket resolution time by 60% while maintaining human oversight on sensitive issues.
Summary
LangGraph transforms agent building from fragile linear chains into robust state machines. The graph model handles complex control flow naturally, and checkpointing makes production deployment safer.