Skip to content

01 · Magazine

LangGraph Examples for Version 1.x

Five runnable LangGraph examples for version 1.x: branching, agent with tools, custom loop, approval with interrupt and a supervisor team.

· Reviewed

This page shows five runnable examples for LangGraph 1.x in Python: from a minimal graph and an agent with tools to human approval and a small multi-agent system with a supervisor. The concepts behind them (state, nodes, edges, checkpointer) are explained on the LangGraph framework page.

Setup

pip install -U langgraph langchain "langchain[openai]"
export OPENAI_API_KEY=...
export MODEL="openai:<model-name>"   # e.g. a current model from your provider

Instead of OpenAI you can use any other provider, for example "langchain[anthropic]" and MODEL="anthropic:<model-name>". All examples read the model from the MODEL environment variable, so you don't have to change them when new models come out.

Example 1: Minimal graph with branching

No language model, just to see the mechanics: a node checks a number, and a conditional edge decides on the next step.

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

class State(TypedDict):
    betrag: float
    ergebnis: str

def pruefen(state: State) -> dict:
    return {}  # change nothing, just pass on

def automatisch(state: State) -> dict:
    return {"ergebnis": "approved automatically"}

def manuell(state: State) -> dict:
    return {"ergebnis": "sent for manual review"}

def route(state: State) -> str:
    return "automatisch" if state["betrag"] < 500 else "manuell"

builder = StateGraph(State)
builder.add_node("pruefen", pruefen)
builder.add_node("automatisch", automatisch)
builder.add_node("manuell", manuell)
builder.add_edge(START, "pruefen")
builder.add_conditional_edges("pruefen", route, ["automatisch", "manuell"])
builder.add_edge("automatisch", END)
builder.add_edge("manuell", END)

graph = builder.compile()
print(graph.invoke({"betrag": 1200}))
# {'betrag': 1200, 'ergebnis': 'sent for manual review'}

Example 2: Agent with tools via create_agent

For a standard agent with tools, use create_agent, available since LangChain 1.0. It replaces the deprecated create_react_agent from langgraph.prebuilt and runs internally as a LangGraph graph.

import os
from langchain.agents import create_agent
from langchain.tools import tool

@tool
def lagerbestand(artikelnummer: str) -> int:
    """Returns the current stock level for an item number."""
    return {"A-100": 12, "A-200": 0}.get(artikelnummer, 0)

agent = create_agent(
    model=os.environ["MODEL"],
    tools=[lagerbestand],
    system_prompt="You answer questions about stock levels briefly and factually.",
)

result = agent.invoke({"messages": [{"role": "user", "content": "Is A-200 available?"}]})
print(result["messages"][-1].content)

Example 3: Custom agent loop with StateGraph

If you need more control, for example additional review steps, you build the loop yourself. ToolNode executes the tool calls requested by the model, and tools_condition decides whether to continue or stop.

import os
from langchain.chat_models import init_chat_model
from langchain.tools import tool
from langgraph.graph import StateGraph, MessagesState, START
from langgraph.prebuilt import ToolNode, tools_condition

@tool
def wechselkurs(von: str, nach: str) -> float:
    """Returns a sample exchange rate between two currencies."""
    return 1.08 if (von, nach) == ("EUR", "USD") else 1.0

tools = [wechselkurs]
llm = init_chat_model(os.environ["MODEL"]).bind_tools(tools)

def modell(state: MessagesState) -> dict:
    return {"messages": [llm.invoke(state["messages"])]}

builder = StateGraph(MessagesState)
builder.add_node("modell", modell)
builder.add_node("tools", ToolNode(tools))
builder.add_edge(START, "modell")
builder.add_conditional_edges("modell", tools_condition)  # to "tools" or end
builder.add_edge("tools", "modell")                       # cycle back to the model

graph = builder.compile()
out = graph.invoke(
    {"messages": [{"role": "user", "content": "How much is 250 EUR in USD?"}]},
    {"recursion_limit": 10},
)
print(out["messages"][-1].content)

The recursion_limit caps the number of steps and prevents infinite loops.

Example 4: Human approval with interrupt

Before a critical action, the graph pauses. The state is stored in the checkpointer until someone approves or rejects.

from typing import TypedDict
from langgraph.graph import StateGraph, START, END
from langgraph.checkpoint.memory import InMemorySaver
from langgraph.types import interrupt, Command

class State(TypedDict):
    entwurf: str
    status: str

def entwerfen(state: State) -> dict:
    return {"entwurf": "Hello, your order is on its way."}

def freigabe(state: State) -> dict:
    entscheidung = interrupt({"frage": "Send this message?", "entwurf": state["entwurf"]})
    return {"status": "sent" if entscheidung == "yes" else "discarded"}

builder = StateGraph(State)
builder.add_node("entwerfen", entwerfen)
builder.add_node("freigabe", freigabe)
builder.add_edge(START, "entwerfen")
builder.add_edge("entwerfen", "freigabe")
builder.add_edge("freigabe", END)

graph = builder.compile(checkpointer=InMemorySaver())
config = {"configurable": {"thread_id": "kunde-42"}}

erster_lauf = graph.invoke({"entwurf": "", "status": ""}, config)
print(erster_lauf["__interrupt__"])          # shows question and draft

ergebnis = graph.invoke(Command(resume="yes"), config)
print(ergebnis["status"])                    # sent

In production, replace InMemorySaver with the Postgres or SQLite checkpointer so that approvals can resume even after a server restart.

Example 5: Supervisor with two specialists

A supervisor node uses structured output to decide which specialist works next. Here the specialists are simple model calls with their own role; in real projects they would be separate agents with tools.

import os
from typing import Literal
from pydantic import BaseModel
from langchain.chat_models import init_chat_model
from langgraph.graph import StateGraph, MessagesState, START, END
from langgraph.types import Command

llm = init_chat_model(os.environ["MODEL"])

class Auswahl(BaseModel):
    naechster: Literal["recherche", "text", "fertig"]

def supervisor(state: MessagesState) -> Command[Literal["recherche", "text", "__end__"]]:
    prompt = [{"role": "system", "content":
               "You coordinate a team. 'recherche' gathers facts, 'text' writes the piece. "
               "Answer 'fertig' once a finished text is available."}] + state["messages"]
    wahl = llm.with_structured_output(Auswahl).invoke(prompt).naechster
    return Command(goto=END if wahl == "fertig" else wahl)

def spezialist(rolle: str):
    def node(state: MessagesState) -> Command[Literal["supervisor"]]:
        antwort = llm.invoke([{"role": "system", "content": rolle}] + state["messages"])
        return Command(goto="supervisor", update={"messages": [antwort]})
    return node

builder = StateGraph(MessagesState)
builder.add_node("supervisor", supervisor)
builder.add_node("recherche", spezialist("You gather three verifiable facts on the topic."))
builder.add_node("text", spezialist("You write a short paragraph from the facts."))
builder.add_edge(START, "supervisor")

graph = builder.compile()
out = graph.invoke(
    {"messages": [{"role": "user", "content": "Write a paragraph about heat pumps."}]},
    {"recursion_limit": 12},
)
print(out["messages"][-1].content)

With Command, a node returns a state update and the next target at the same time. This is the usual form for handoffs between agents in LangGraph 1.x.

Common patterns in practice

Pattern Structure Example
Agentic RAG Search, relevance check, new search if needed, then answer Internal knowledge base with source citations
Text-to-SQL Generate SQL, run it, return errors to the model, retry Ad hoc analyses for business departments
Approval workflow Draft, interrupt, send Emails, quotes, social media posts
Supervisor team Supervisor plus two to four specialists Research and report, code and review

Common mistakes when moving to 1.x

  • Still using create_react_agent: It still works but is deprecated. Switch to langchain.agents.create_agent.
  • MemorySaver in production: It only stores data in memory. Use a persistent checkpointer.
  • No recursion_limit: Loops without an upper limit cost money and time.
  • Old tutorials: Many guides refer to "LangGraph Platform" or pre-1.0 APIs. Check the date.

Frequently asked questions

Which version do the examples run on?

On LangGraph 1.2 and LangChain 1.4 (as of October 2026). The examples only use building blocks of the stable 1.x API, so they should keep working without changes until LangGraph 2.0.

Can I use the examples with another model provider?

Yes. Install the matching package, for example "langchain[anthropic]", and set the MODEL environment variable, for example to anthropic:<model-name>. The code itself stays the same.

Which checkpointer should I use in production?

MemorySaver only stores data in memory and is meant for tests. In production you use a persistent checkpointer, for example for Postgres or SQLite, so that approvals and conversation histories survive a restart.

Should I use create_agent or my own graph?

For an agent with tools and no special workflow logic, create_agent is enough (example 2). Build your own graph as soon as you need branches, approvals or several agents (examples 3 to 5).

Sources

Last reviewed:

Market notes

Get the next analysis by email

New articles and changes in the directory, at most once a week.