What is LangGraph?
LangGraph is a framework built on top of LangChain for creating stateful, multi-actor AI applications. Unlike traditional chains that follow linear flows, LangGraph enables the construction of complex workflows using cyclic graphsโessential for building agents that can loop, branch, and make dynamic decisions.
"LangGraph models agent workflows as cyclic graphs, enabling persistent state, cycles for iterative processes, and human-in-the-loop interactionsโcrucial for production-grade AI agents."
Cyclic Graphs
Loops & branches
Persistent State
Memory across calls
Human-in-Loop
Approval workflows
Streaming
Real-time output
Core Concepts
State
The State is a shared data structure that represents the current snapshot of
your
application. It's passed between nodes and updated as the workflow progresses. Define it using
TypedDict or Pydantic
models.
from typing import TypedDict, Annotated
from operator import add
class AgentState(TypedDict):
messages: Annotated[list, add] # Append new messages
next_step: str # Control flow
Nodes
Nodes are functions that represent individual steps in your workflow. Each node receives the current state, performs an action (LLM call, tool execution, data processing), and returns an updated state. Think of them as the "actions" in your agent.
Edges
Edges define the flow between nodes. LangGraph supports two types:
Simple Edges
Direct transition: A โ B
Conditional Edges
Dynamic routing based on state
StateGraph
StateGraph is the container that holds your nodes and edges. You add nodes, define edges between them, set an entry point, and compile it into an executable graph.
LangGraph vs LangChain Agents
| Aspect | LangChain Agents | LangGraph |
|---|---|---|
| Flow Control | LLM decides next step | Developer defines graph structure |
| Cycles | Limited (think-act-observe loop) | Full support for cycles & loops |
| State Management | Basic memory | Persistent, typed state |
| Debugging | Can be unpredictable | Explicit, auditable flow |
| Best For | Rapid prototyping, simple tasks | Production, complex workflows |
Example: Simple Chatbot Graph
Here's a minimal example of a chatbot built with LangGraph. It has one node that calls the LLM and loops back to handle follow-up messages:
# Simple Chatbot with LangGraph
from typing import TypedDict, Annotated
from operator import add
from langgraph.graph import StateGraph, START, END
from langchain_openai import ChatOpenAI
# 1. Define the State
class ChatState(TypedDict):
messages: Annotated[list, add]
# 2. Create the LLM
llm = ChatOpenAI(model="gpt-4")
# 3. Define the Node
def chat_node(state: ChatState) -> dict:
response = llm.invoke(state["messages"])
return {"messages": [response]}
# 4. Build the Graph
graph = StateGraph(ChatState)
graph.add_node("chat", chat_node)
graph.add_edge(START, "chat")
graph.add_edge("chat", END)
# 5. Compile and Run
app = graph.compile()
result = app.invoke({
"messages": [{"role": "user", "content": "Hello! What is LangGraph?"}]
})
print(result["messages"][-1].content)
Expected Output
LangGraph is a framework for building stateful, multi-actor AI applications using graph structures. It extends LangChain by enabling cyclic workflows, persistent state management, and human-in-the-loop interactions...
Example: ReAct Agent with Tools
This example shows a ReAct-style agent that can use tools to answer questions. It loops between calling the LLM and executing tools until the task is complete:
# ReAct Agent with Tools
from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
from langgraph.prebuilt import create_react_agent
# Define tools
@tool
def multiply(a: int, b: int) -> int:
"""Multiply two numbers together."""
return a * b
@tool
def add_numbers(a: int, b: int) -> int:
"""Add two numbers together."""
return a + b
# Create the agent
llm = ChatOpenAI(model="gpt-4")
tools = [multiply, add_numbers]
agent = create_react_agent(llm, tools)
# Run the agent
result = agent.invoke({
"messages": [{
"role": "user",
"content": "What is 15 multiplied by 7, then add 50?"
}]
})
# Print the final answer
print(result["messages"][-1].content)
Expected Output
# Agent execution flow: [1] LLM decides to call: multiply(15, 7) [2] Tool returns: 105 [3] LLM decides to call: add_numbers(105, 50) [4] Tool returns: 155 [5] LLM generates final answer: "15 multiplied by 7 equals 105, and adding 50 gives you 155."
Example: Conditional Routing
This example shows how to use conditional edges to route to different nodes based on state:
# Conditional Routing Example
from typing import TypedDict, Literal
from langgraph.graph import StateGraph, START, END
class RouterState(TypedDict):
query: str
category: str
response: str
# Classifier node
def classify(state: RouterState) -> dict:
query = state["query"].lower()
if "weather" in query:
return {"category": "weather"}
elif "calculate" in query or "math" in query:
return {"category": "math"}
return {"category": "general"}
# Handler nodes
def handle_weather(state): return {"response": "๐ค๏ธ Weather service called!"}
def handle_math(state): return {"response": "๐งฎ Calculator service called!"}
def handle_general(state): return {"response": "๐ฌ General assistant called!"}
# Router function
def route_query(state) -> Literal["weather", "math", "general"]:
return state["category"]
# Build graph
graph = StateGraph(RouterState)
graph.add_node("classify", classify)
graph.add_node("weather", handle_weather)
graph.add_node("math", handle_math)
graph.add_node("general", handle_general)
graph.add_edge(START, "classify")
graph.add_conditional_edges("classify", route_query)
graph.add_edge("weather", END)
graph.add_edge("math", END)
graph.add_edge("general", END)
app = graph.compile()
# Test it
result = app.invoke({"query": "What's the weather today?"})
print(result["response"])
Expected Output
# Query: "What's the weather today?" category: weather ๐ค๏ธ Weather service called! # Query: "Calculate 10 plus 5" category: math ๐งฎ Calculator service called! # Query: "Tell me a joke" category: general ๐ฌ General assistant called!
Graph Visualization
LangGraph can generate a visual representation of your graph to help understand the flow:
# Generate graph visualization
from IPython.display import Image, display
# Get the graph image (requires graphviz)
graph_image = app.get_graph().draw_mermaid_png()
display(Image(graph_image))
Tip: Use get_graph().draw_ascii()
for terminal output or draw_mermaid() for Mermaid
diagrams.
Key Features
Persistence
Save graph state to a database and resume later. Essential for long-running workflows and fault tolerance.
Human-in-the-Loop
Pause execution for human approval before sensitive actions. Use
interrupt_before.
Streaming
Stream both tokens and intermediate states in real-time using
stream() or
astream().
Multi-Agent
Build systems with multiple specialized agents that communicate and collaborate through the shared state.