LangGraph Multi-Agent Workflows: Building Stateful AI Systems with Graph-Based Orchestration
LangGraph has become a go‑to framework for developers who need more than a simple prompt‑response loop. By treating each AI agent as a node in a directed graph and managing shared state through edges, LangGraph lets you create workflows that branch, loop, pause for human input, and recover from failures—all while keeping the underlying logic clear and testable. In this guide we’ll walk through the core concepts, show why a multi‑agent approach often beats a monolithic agent, and give you a practical blueprint you can adapt to your own projects.
What “multi‑agent” really means
A multi‑agent system consists of independent actors, each powered by a language model (or any other computational unit), that collaborate to achieve a goal. The two questions that shape any design are:
- Who are the agents? – Each agent can have its own prompt, model, tools, and custom code.
- How are they connected? – The connections define how information flows, when control passes from one agent to another, and what state is shared.
When you view agents as nodes and their connections as edges, the problem naturally maps onto a graph. LangGraph’s StateGraph abstraction captures exactly this: nodes are Python functions that read and update a shared state object; edges are routing decisions that determine which node runs next. Because the graph can contain cycles, an agent can revisit a previous step based on new information—a capability that pure linear chains lack.
Why split work among multiple agents?
Putting every capability into a single LLM call often leads to bloated prompts, conflicting tool selections, and fragile error handling. Separating concerns brings several tangible benefits:
- Focused expertise – An agent that only searches the web or only formats a chart can be tuned with a dedicated prompt and toolset, increasing success rates.
- Independent iteration – You can improve the planner’s roadmap generation without touching the explanation or grading logic.
- Clear debugging – When something goes wrong, you know exactly which node produced the offending output.
- Flexible scaling – Adding a new specialist (e.g., a legal reviewer) only requires adding a node and wiring the appropriate edges; existing agents remain unchanged.
- Fault isolation – If a tool‑calling agent fails, the rest of the graph can continue or follow a fallback path rather than crashing the whole workflow.
These advantages become especially valuable when the workflow involves conditional branching, retries, or human‑in‑the‑loop checkpoints—scenarios where a monolithic agent would need complex internal logic to manage.
Core building blocks in LangGraph
Before diving into patterns, it helps to understand the four pieces that LangGraph stitches together:
| Piece | Role | Typical implementation |
|---|---|---|
| State | A shared dictionary that travels with the graph execution. Each node receives the full state, modifies the fields it owns, and returns a partial update. LangGraph merges updates automatically. | TypedDict with Annotated[list[BaseMessage], add_messages] for conversation history, plus domain‑specific fields (e.g., roadmap, quiz_results). |
| Nodes | Pure Python functions that embody an agent’s behavior. They read state, call LLMs or tools, and return the updated slice of state. | Functions like curriculum_planner_node, explainer_node, quiz_generator_node. |
| Edges | Define how execution moves from one node to another. Edges can be static (always follow) or conditional (choose based on state). | add_edge for fixed transitions; add_conditional_edges for routing logic. |
| Checkpointer | Persists the state after each node so the workflow can survive crashes, pauses, or resumptions. | SqliteSaver for local dev, PostgresSaver or RedisSaver for production. |
Because the state is explicit and versioned, LangGraph also supports advanced features like streaming (token‑by‑token output), human‑in‑the‑loop via interrupt(), and time‑travel debugging through checkpoint snapshots.
Common multi‑agent patterns
LangGraph does not enforce a single architecture; instead, it gives you primitives to compose the pattern that fits your problem. Three recurring designs appear in the official examples and community projects.
1. Collaborative agents with a shared scratchpad
All agents read from and write to a single list of messages (the “scratchpad”). This gives every participant full visibility into what others have done, which is useful for tasks that benefit from transparency—like peer review or iterative refinement. The downside is potential verbosity: if each step appends a long trace, the context window can fill quickly. In practice you often combine this pattern with a summarizing node that condenses the scratchpad before passing it along.
2. Supervisor‑worker (agent‑supervisor) model
A supervisor node holds the overall goal and decides which specialist should act next. Each worker maintains its own private state (or scratchpad) and returns a result that the supervisor aggregates into a global scratchpad. This mirrors a team where a project manager delegates work to specialists and then synthesizes their outputs. The supervisor can also be viewed as an agent whose “tools” are the other agents, making it easy to nest supervisors for hierarchical teams.
3. Hierarchical agent teams
Here the workers themselves are LangGraph sub‑graphs. This enables reusable components: a “document processing” sub‑graph might contain nodes for extraction, classification, and summarization, and can be dropped into a larger workflow as a single node. Hierarchical teams give you the flexibility to treat complex sub‑workflows as black‑box agents while still preserving internal state and control flow.
A concrete end‑to‑end example
To see how these pieces fit together, consider a study‑assistant workflow that helps a user learn a new topic:
- Curriculum Planner – Generates a structured roadmap (weeks, topics, estimated time) from a user‑provided goal.
- Human Approval – Pauses the graph so the user can accept or regenerate the plan.
- Explainer – For each topic, calls MCP‑based tools to fetch study notes, searches for relevant sections, and crafts an explanation grounded in the source material.
- Quiz Generator – Creates multiple‑choice or short‑answer questions from the explanation, then grades the user's responses using an LLM‑as‑judge.
- Progress Coach – Reviews the quiz score, updates the topic status (completed / needs review), gives encouraging feedback, and decides whether to move to the next topic or end the session.
The graph wires these nodes in a loop: after the Progress Coach updates the topic index, a conditional edge routes back to the Explainer if more topics remain, otherwise to an END node. Checkpointing after each node means that if the process crashes mid‑quiz, resuming with the same session ID picks up exactly where it left off—no lost progress, no duplicate work.
Comparing LangGraph to other frameworks
While LangGraph is not the first to support multi‑agent orchestration, its design choices give it a distinct feel:
- Autogen treats the system as a conversation where agents take turns speaking. This works well for chat‑like interactions but makes it harder to enforce explicit routing probabilities or to visualize the workflow as a graph.
- CrewAI offers a higher‑level, role‑based abstraction (agents belong to crews with tasks). It speeds up prototyping but hides the low‑level control flow that LangGraph exposes, which can be limiting when you need custom conditional logic or fine‑grained error handling.
- LangGraph sits in the middle: you define the graph explicitly, giving you deterministic control over transitions, yet you still reap the benefits of the LangChain ecosystem (tools, memory, observability). The graph representation also makes it straightforward to apply concepts like checkpointing, interrupts, and sub‑graph reuse.
In short, if you need predictable routing, durable state, and the ability to pause for human decisions, LangGraph’s graph‑first approach often provides a clearer development experience.
Building your own LangGraph multi‑agent workflow
Below is a step‑by‑step outline you can follow to turn a idea into a working graph. The code snippets are intentionally concise; the focus is on the concepts rather than a copy‑paste solution.
1. Define the shared state
Start by listing the pieces of information that need to survive across nodes. Use a TypedDict and, for fields that should accumulate (like chat history), apply the add_messages reducer.
from typing import Annotated, List, TypedDict
from langchain_core.messages import BaseMessage
from langgraph.graph.message import add_messages
class AgentState(TypedDict):
messages: Annotated[List[BaseMessage], add_messages]
goal: str
roadmap: dict | None
current_topic: int
quiz_results: List[dict]
weak_areas: List[str]
approved: bool
2. Implement agent nodes
Each node is a pure function that receives state, performs its task, and returns a dict with only the keys it changed.
def planner_node(state: AgentState) -> AgentState:
# call LLM, produce roadmap
return {"roadmap": new_roadmap, "messages": state["messages"] + [aimsg]}
def explainer_node(state: AgentState) -> AgentState:
# retrieve notes via MCP tools, generate explanation
return {"messages": state["messages"] + [explanation_msg]}
Keep the functions testable in isolation—this makes it easy to swap LLMs or tools later without rewiring the graph.
3. Wire the graph with edges
Use StateGraph to register nodes, add static edges for fixed sequences, and add conditional edges for branching logic.
from langgraph.graph import StateGraph, END
builder = StateGraph(AgentState)
builder.add_node("planner", planner_node)
builder.add_node("explainer", explainer_node)
builder.add_node("quiz", quiz_node)
builder.add_node("coach", progress_coach_node)
# Fixed flow
builder.add_edge("planner", "explainer")
builder.add_edge("explainer", "quiz")
builder.add_edge("quiz", "coach")
# Conditional routing from coach
def after_coach(state):
return "explainer" if state["current_topic"] < len(state["roadmap"]["topics"]) else END
builder.add_conditional_edges("coach", after_coach, {"explainer": "explainer", "END": END})
4. Add checkpointing and human‑in‑the‑loop
Choose a checkpointer that matches your deployment target. For local testing, InMemorySaver works; for production, use PostgresSaver.
from langgraph.checkpoint.postgres import PostgresSaver
checkpointer = PostgresSaver.from_conn_string("postgresql://user:pw@host/db")
graph = builder.compile(checkpointer=checkpointer)
To pause for approval, insert an interrupt() call inside a node (e.g., after the planner). The caller then uses Command(resume=value) to continue.
from langgraph.types import interrupt, Command
def human_approval_node(state):
decision = interrupt({"prompt": "Approve plan? (yes/no)"})
approved = decision.lower().strip() == "yes"
return {"approved": approved, **state} # forward needed fields
5. Run and observe
Invoke the graph with an initial state and a config that supplies the thread_id (used by the checkpointer) and any observability callbacks.
config = {"configurable": {"thread_id": str(uuid.uuid4())}}
result = graph.invoke(initial_state, config=config)
while "__interrupt__" in result:
# show prompt, get user input, resume
result = graph.invoke(Command(resume=user_input), config=config)
Production‑grade considerations
Moving from a demo to a service that runs at scale introduces a few extra layers of concerns. Addressing them early saves headaches later.
State persistence
- Use a durable backend (PostgreSQL or Redis‑backed checkpointer) so that workflows survive pod restarts and can be shared across multiple instances.
- Version your
AgentStateschema: add new fields as optional with defaults, and deprecate old fields over a release cycle before removing them.
Observability & debugging
- LangGraph’s built‑in checkpointing enables “time‑travel” debugging: you can replay a workflow from any saved state.
- Pair this with a tracing solution (Langfuse, Jaeger, or a custom logger) that records LLM inputs/outputs, tool calls, and node timings.
- In production, sample traces (e.g., 10‑20 %) to keep overhead low while still capturing errors.
Error handling & retries
- Wrap external calls (LLM APIs, third‑party services) with retry logic and circuit breakers.
- Define fallback edges: if a specialist node fails repeatedly, route to a generic handler or a human‑review node.
- Surface structured error information in the state so downstream agents can decide whether to proceed, retry, or abort.
Cost control
- Every LLM call and billable tool invocation should emit usage metadata (tokens, latency, cost).
- Enforce per‑session or per‑user token budgets at the orchestrator level; reject or throttle further calls once the budget is exhausted.
- For expensive tools (search APIs, vector DB queries), track call counts and apply quotas.
Security & governance
- Treat the state as potentially sensitive; avoid logging raw user data.
- Authenticate requests to any exposed A2A or MCP services; use short‑lived tokens or mTLS.
- Keep audit logs of decisions that result in external actions (e.g., sending an email, updating a database) for compliance review.
Scaling the graph itself
- Because each agent is a stateless function, you can horizontally scale them by deploying each node as its own service behind a load balancer, while the orchestrator remains a single source of truth for routing.
- In Kubernetes, this often looks like a microservice per agent, with the LangGraph orchestration layer running as a lightweight control plane that pushes state to and pulls updates from each service.
Extending the pattern
The modular nature of LangGraph makes it straightforward to grow your system:
- Add a new specialist – Write a node function, register it, and connect it with the appropriate edges. Existing nodes need no changes.
- Swap the LLM backend – Point all
ChatOllama(orChatOpenAI) instances at a LiteLLM gateway; the gateway can route to different providers without touching agent code. - Expose an agent as an A2A service – Wrap the node’s logic in an
AgentExecutor, serve it over HTTP, and let other frameworks call it via the Agent‑to‑Agent protocol. - Integrate additional MCP tools – Add a new
@mcp.tool()to your server, import it into the agent’s tool list, and update the system prompt to describe when to use it.
Each of these steps respects the underlying contract: agents communicate exclusively through the typed state and the well‑defined tool or A2A interfaces.
Wrap‑up
LangGraph turns the vague idea of “multiple AI agents working together” into a concrete, testable, and operable engineering artifact. By modeling agents as nodes in a state as the shared context, and edges as the routing logic, you gain:
- Deterministic control flow that can branch, loop, and pause for human input.
- Fault‑tolerant execution thanks to checkpointing and time‑travel debugging.
- A clean separation of concerns that simplifies debugging, testing, and incremental improvement.
Whether you’re building a study assistant, a compliance‑checking pipeline, or a customer‑support triage bot, the multi‑agent pattern in LangGraph gives you the scaffolding to orchestrate complex, real‑world workflows while keeping the individual agents focused, replaceable, and easy to reason about. Start small, validate each node in isolation, let the graph handle the coordination, and iterate from there. The result is a system that behaves like a team of specialists—each doing what it does best, with a reliable manager making sure the whole effort moves forward.
