LangGraph
LangGraph is a framework for building stateful, multi-step agent applications using graph-based orchestration. It is the recommended way to build production agents in the LangChain ecosystem.
What is LangGraph?
LangGraph models agent workflows as directed graphs. Each node is a computation step (LLM call, tool execution, data processing), and edges define the flow between steps. Unlike simple chains, LangGraph supports cycles, conditional branching, and persistent state.
pip install langgraph
LangGraph vs AgentExecutor
| Feature | AgentExecutor | LangGraph |
|---|---|---|
| Control | Black-box loop | Full control over every step |
| Cycles | Fixed think-act loop | Custom cycles and loops |
| Branching | Limited | Conditional routing |
| State | Basic message history | Rich typed state with persistence |
| Human-in-the-loop | Not supported | Built-in support |
| Multi-agent | Not supported | First-class support |
Core Concepts: StateGraph
A StateGraph defines the state schema and computation graph:
from langgraph.graph import StateGraph, START, END from typing import TypedDict, Annotated from langgraph.graph.message import add_messages # 1. Define the state schema class AgentState(TypedDict): messages: Annotated[list, add_messages] # Chat messages (auto-appended) next_step: str # Custom state field # 2. Create the graph graph = StateGraph(AgentState)
Nodes and Edges
Nodes are Python functions that read and update state. Edges define the flow:
from langchain_openai import ChatOpenAI from langchain_core.messages import HumanMessage llm = ChatOpenAI(model="gpt-4o-mini") # Define node functions def chatbot(state: AgentState): """Call the LLM with current messages.""" response = llm.invoke(state["messages"]) return {"messages": [response]} # Add nodes to the graph graph.add_node("chatbot", chatbot) # Add edges graph.add_edge(START, "chatbot") # Start → chatbot graph.add_edge("chatbot", END) # chatbot → End # Compile the graph into a runnable app = graph.compile() # Run it result = app.invoke({ "messages": [HumanMessage(content="Hello!")] }) print(result["messages"][-1].content)
Conditional Routing
Use conditional edges to route to different nodes based on state:
def should_use_tools(state: AgentState) -> str: """Decide whether to use tools or end.""" last_message = state["messages"][-1] # If the LLM made tool calls, route to tools node if last_message.tool_calls: return "tools" # Otherwise, end the conversation return "end" # Add conditional edge from chatbot graph.add_conditional_edges( "chatbot", should_use_tools, { "tools": "tool_node", # Route to tool execution "end": END, # Route to end }, )
Building a ReAct Agent with LangGraph
A complete ReAct agent that uses tools in a think-act loop:
from langgraph.graph import StateGraph, START, END from langgraph.prebuilt import ToolNode from langchain_openai import ChatOpenAI from langchain_core.tools import tool from typing import TypedDict, Annotated from langgraph.graph.message import add_messages # State class State(TypedDict): messages: Annotated[list, add_messages] # Tools @tool def search(query: str) -> str: """Search the web for information.""" return f"Results for '{query}': LangGraph is a framework by LangChain..." @tool def calculate(expr: str) -> str: """Calculate a math expression.""" return str(eval(expr)) tools = [search, calculate] # LLM with tools bound llm = ChatOpenAI(model="gpt-4o-mini").bind_tools(tools) # Nodes def agent(state: State): response = llm.invoke(state["messages"]) return {"messages": [response]} tool_node = ToolNode(tools) # Router def should_continue(state: State) -> str: if state["messages"][-1].tool_calls: return "tools" return "end" # Build graph graph = StateGraph(State) graph.add_node("agent", agent) graph.add_node("tools", tool_node) graph.add_edge(START, "agent") graph.add_conditional_edges("agent", should_continue, { "tools": "tools", "end": END, }) graph.add_edge("tools", "agent") # Loop back after tool execution # Compile and run app = graph.compile() result = app.invoke({ "messages": [("human", "Search for LangGraph and calculate 42 * 17")] }) print(result["messages"][-1].content)
Human-in-the-Loop
Pause execution and wait for human approval before continuing:
from langgraph.checkpoint.memory import MemorySaver # Compile with checkpointer and interrupt checkpointer = MemorySaver() app = graph.compile( checkpointer=checkpointer, interrupt_before=["tools"], # Pause before tool execution ) # Run until interrupt config = {"configurable": {"thread_id": "user-123"}} result = app.invoke( {"messages": [("human", "Delete all files in /tmp")]}, config=config, ) # Agent pauses here before executing the tool # Review the pending tool call, then resume print("Pending action:", result["messages"][-1].tool_calls) # Resume execution (approve) result = app.invoke(None, config=config)
Persistence and Checkpointing
LangGraph can save and restore state across sessions:
from langgraph.checkpoint.memory import MemorySaver from langgraph.checkpoint.sqlite import SqliteSaver # In-memory (development) checkpointer = MemorySaver() # SQLite (persists across restarts) checkpointer = SqliteSaver.from_conn_string("checkpoints.db") # Compile with checkpointer app = graph.compile(checkpointer=checkpointer) # Each thread_id maintains its own conversation config = {"configurable": {"thread_id": "user-alice"}} app.invoke({"messages": [("human", "Hi, I'm Alice")]}, config) # Later, same thread remembers the conversation app.invoke({"messages": [("human", "What's my name?")]}, config)
Multi-Agent Workflows
Coordinate multiple specialized agents working together:
# Supervisor pattern: one agent routes to specialists def supervisor(state): """Decide which specialist agent should handle the task.""" response = supervisor_llm.invoke(state["messages"]) return {"messages": [response], "next": "researcher"} def researcher(state): """Research agent with search tools.""" ... def writer(state): """Writing agent that drafts content.""" ... # Build multi-agent graph graph = StateGraph(State) graph.add_node("supervisor", supervisor) graph.add_node("researcher", researcher) graph.add_node("writer", writer) graph.add_edge(START, "supervisor") graph.add_conditional_edges("supervisor", route_to_agent) graph.add_edge("researcher", "supervisor") graph.add_edge("writer", "supervisor")
langgraph.prebuilt.create_react_agent(model, tools) which creates a complete ReAct agent graph in one line. Build custom graphs only when you need specialized control flow.What's Next?
The next lesson covers LangSmith - how to trace, debug, evaluate, and monitor your LangChain and LangGraph applications.
Ready to Go Deeper?
Live instructor-led courses from our partners. Affiliate disclosure.
AI & ML Courses - 30% Off
Live instructor-led AI, machine learning, data science, and cloud courses for working professionals. Use code Limited30 at checkout.
EdurekaDataCamp - AI & Data Science
Hands-on Python, machine learning, and AI courses with interactive exercises and real projects.
DataCampedX - Top AI Courses
University-level AI courses from MIT, Harvard, Stanford. Earn certificates that employers recognize.
edX