LangGraph Tutorial: Build AI Agents with Graph-Based Workflows

LangGraph hit 23.7k GitHub stars and over 22 million monthly downloads in January 2026—and for good reason. While LangChain handles simple chains and RAG pipelines, LangGraph gives you graph-based workflows with explicit state management, conditional routing, and built-in human-in-the-loop patterns. It’s the framework enterprises like Uber, LinkedIn, and Klarna use for production AI agents. This tutorial walks you through building your first agentic workflow with LangGraph, from installation to a working ReAct agent that reasons, acts, and loops until it solves your problem.

What LangGraph Actually Does (And Why It’s Different)

LangGraph is a low-level orchestration framework for stateful, long-running AI agents. Built by LangChain Inc but usable independently, it models workflows as directed graphs rather than linear chains. The key insight: most real-world AI tasks aren’t linear. They involve loops (keep trying until you succeed), branches (do X if condition, else do Y), and human checkpoints (pause for approval before deleting everything).

The difference from plain LangChain matters. LangChain’s Expression Language handles sequential pipelines well—prompt goes in, response comes out. But try building an agent that reasons, calls a tool, evaluates the result, and decides whether to call another tool or respond. That’s a cycle, and cycles require explicit control flow. LangGraph provides that with three primitives:

  • State: A typed dictionary that flows through your graph, holding conversation history, intermediate results, and any data nodes need to share
  • Nodes: Python functions that receive state, do work (LLM calls, tool execution, pure logic), and return state updates
  • Edges: Connections between nodes—either fixed (“always go here next”) or conditional (“go here if X, there if Y”)

This architecture enables patterns that linear chains can’t express: retry loops, quality gates, multi-agent coordination, and durable execution that survives failures. The LangGraph repository continues to see rapid enterprise adoption.

Installation and Setup

LangGraph requires Python 3.10 or higher. Create a virtual environment and install the base package:

python -m venv venv
source venv/bin/activate  # macOS/Linux
pip install -U langgraph langchain langchain-openai

For Claude integration, swap langchain-openai for langchain-anthropic. Set your API key as an environment variable:

export OPENAI_API_KEY="sk-..."
# or
export ANTHROPIC_API_KEY="sk-ant-..."

Verify installation works:

python -c "import langgraph; print('LangGraph ready')"

Your First Graph: Hello World

Let’s build the simplest possible graph to understand the mechanics. This graph has two nodes that transform a string:

from langgraph.graph import StateGraph, START, END
from typing import TypedDict

class State(TypedDict):
    text: str

def greet(state: State) -> dict:
    return {"text": state["text"] + "Hello "}

def world(state: State) -> dict:
    return {"text": state["text"] + "World!"}

# Build the graph
graph = StateGraph(State)
graph.add_node("greet", greet)
graph.add_node("world", world)
graph.add_edge(START, "greet")
graph.add_edge("greet", "world")
graph.add_edge("world", END)

# Compile and run
app = graph.compile()
result = app.invoke({"text": ""})
print(result)  # {'text': 'Hello World!'}

Key observations: You define state as a TypedDict. Nodes are plain functions that receive state and return partial updates (just the fields they’re changing). You must call .compile() before invoking—this validates the graph structure. The START and END constants mark entry and exit points.

Building a ReAct Agent That Actually Works

The ReAct pattern (Reasoning + Acting) is where LangGraph shines. The agent reasons about what to do, calls tools, evaluates results, and loops until it has an answer. Here’s a complete implementation:

from typing import Annotated, Sequence, TypedDict
from langchain_core.messages import BaseMessage, HumanMessage
from langchain_openai import ChatOpenAI
from langgraph.graph import StateGraph, START, END
from langgraph.graph.message import add_messages
from langgraph.prebuilt import ToolNode, tools_condition

# State holds the conversation
class AgentState(TypedDict):
    messages: Annotated[Sequence[BaseMessage], add_messages]

# Define tools the agent can use
def search_web(query: str) -> str:
    """Search the web for information."""
    return f"Results for '{query}': AI adoption grew 40% in 2025..."

def calculate(expression: str) -> str:
    """Evaluate a math expression."""
    return str(eval(expression))

tools = [search_web, calculate]

# LLM with tools bound
llm = ChatOpenAI(model="gpt-4").bind_tools(tools)

def agent(state: AgentState) -> dict:
    response = llm.invoke(state["messages"])
    return {"messages": [response]}

# Build the graph
graph = StateGraph(AgentState)
graph.add_node("agent", agent)
graph.add_node("tools", ToolNode(tools))

graph.add_edge(START, "agent")
graph.add_conditional_edges(
    "agent",
    tools_condition,  # Routes to "tools" or END
    {"tools": "tools", END: END}
)
graph.add_edge("tools", "agent")  # Loop back

app = graph.compile()

# Run it
result = app.invoke({
    "messages": [HumanMessage(content="What's 25 * 4, and search for AI trends")]
})
print(result["messages"][-1].content)

The magic happens in add_conditional_edges. The tools_condition helper checks if the LLM’s response contains tool calls. If yes, route to the tools node. If no (meaning the LLM gave a final answer), route to END. After tool execution, we loop back to the agent node so it can process the results and decide what to do next.

This pattern—agent reasons, tools execute, agent evaluates, repeat—is the foundation of most production AI agents. If you’ve worked with Claude’s Agent SDK, you’ll recognize the similarity, but LangGraph gives you finer control over the execution flow.

Illustration: LangGraph tutorial

Adding Memory with Checkpointing

Real agents need memory. They should remember previous conversations and resume after failures. LangGraph’s checkpointing system handles this:

from langgraph.checkpoint.memory import InMemorySaver

# For development: in-memory persistence
memory = InMemorySaver()
app = graph.compile(checkpointer=memory)

# Each conversation needs a thread_id
config = {"configurable": {"thread_id": "user-123"}}

# First message
result = app.invoke(
    {"messages": [HumanMessage(content="My name is Alex")]},
    config
)

# Later: same thread_id = same conversation
result = app.invoke(
    {"messages": [HumanMessage(content="What's my name?")]},
    config
)
# Agent remembers: "Your name is Alex"

For production, swap InMemorySaver for PostgreSQL persistence:

pip install langgraph-checkpoint-postgres
from langgraph.checkpoint.postgres import PostgresSaver

memory = PostgresSaver.from_conn_string("postgresql://user:pass@localhost/db")
app = graph.compile(checkpointer=memory)

Checkpointing also enables human-in-the-loop workflows. You can pause execution at any node, let a human review or modify state, then resume. The human-in-the-loop documentation covers approval workflows, state editing, and input collection patterns.

The Quick Path: Pre-built Agents

If you don’t need custom graph logic, LangGraph offers a pre-built ReAct agent that handles the boilerplate:

from langgraph.prebuilt import create_react_agent

agent = create_react_agent(
    "openai:gpt-4",  # or "anthropic:claude-3-7-sonnet-latest"
    tools=[search_web, calculate],
    prompt="You are a helpful research assistant."
)

result = agent.invoke({
    "messages": [HumanMessage(content="Research AI hardware trends")]
})

Three lines of code, working agent. Use this for prototyping, then graduate to custom graphs when you need more control.

When to Use LangGraph (And When Not To)

LangGraph isn’t always the right tool. Here’s how it compares to alternatives:

Use CaseBest FrameworkWhy
Simple RAG pipelineLangChainLinear flow, no cycles needed
Complex agent with toolsLangGraphCycles, conditional routing
Quick multi-agent prototypeCrewAIRole-based teams, fast setup
Production agent with complianceLangGraphAudit trails, human approval
Code generation focusAutoGenMicrosoft ecosystem, research

Choose LangGraph when you need explicit state management, cycles (retry loops, quality checks), human-in-the-loop approvals, or production-grade durability. If you’re building MCP server integrations or complex multi-step workflows, LangGraph’s graph model makes the logic explicit rather than buried in callback chains.

Common Pitfalls to Avoid

After reviewing enterprise deployments, these mistakes appear repeatedly:

  1. Forgetting to compile: You must call .compile() before .invoke(). The graph builder is not the runnable.
  2. Missing thread_id: Checkpointing requires a thread_id in config. Without it, there’s no persistence key.
  3. Infinite cycles: Always add a termination condition. Check iteration counts or timeout limits in your routing logic.
  4. Mutating state directly: Return new values, don’t modify the state dict. Nodes should be pure functions.
  5. Missing reducers: Use Annotated[list, add_messages] for message lists. Without the reducer, new messages replace old ones instead of appending.

Next Steps

You now have a working LangGraph agent with tool calling, memory, and the foundation for production deployment. To go deeper:

  • Free course: LangChain Academy’s Intro to LangGraph covers advanced patterns with video walkthroughs
  • Multi-agent systems: The langgraph-supervisor package adds supervisor nodes that coordinate multiple specialized agents
  • Debugging: Enable LangSmith tracing (LANGCHAIN_TRACING_V2=true) to visualize your graph execution and spot bottlenecks

LangGraph’s v1.0 release in late 2025 marked its transition from experimental to production-ready. With companies like Uber saving 21,000 developer hours and Klarna cutting resolution time by 80%, the framework has proven itself at scale. The graph-based mental model takes adjustment if you’re coming from linear pipelines, but the payoff is agents that actually work in production—with the control flow, durability, and human oversight that real applications demand.

Get the Daily Pulse

Sharp analysis on what's actually moving in AI. No hype, no filler, no weekly digest.

Get the Daily Pulse

Sharp AI analysis, daily. Two minutes, every morning.

Get the Daily PulseTwo minutes, every morning