Skip to main content
Multi-agent systems break complex applications into coordinated components. Importantly, “multi-agent” doesn’t necessarily mean multiple distinct agents — a single agent with dynamic behavior can achieve similar capabilities.

Why multi-agent?

When developers say they need “multi-agent,” they’re usually looking for one or more of these capabilities:

Context management

Surface relevant knowledge without overwhelming the context window. Different tasks (agents) need different context.

Distributed development

Let different teams develop and maintain capabilities independently with clear boundaries.

Parallelization

Spawn specialized workers for subtasks and execute them concurrently for faster results.

Sequential constraints

Enforce step-by-step workflows. Unlock tools and actions only after preconditions are met.
Multi-agent patterns are particularly valuable when a single agent has too many tools and makes poor decisions about which to use, when tasks require specialized knowledge with extensive context (long prompts and domain-specific tools), or when you need to enforce sequential constraints that unlock capabilities only after certain conditions are met.
At the center of multi-agent design is context engineering—deciding what information each agent sees. The quality of your system depends on ensuring each agent has access to the right data for its task.

Patterns

Here are the main patterns for building multi-agent systems, each suited to different use cases: Tool calling is the primary coordination mechanism across all patterns. Tools can:
  • Invoke sub-agents (subagents)
  • Update state to trigger routing or configuration changes (handoffs)
  • Load context on-demand (skills)
  • Invoke entire multi-agent systems (wrapping a router as a tool)

Choosing a pattern

Use this table to match your requirements to the right pattern:
  • Distributed development: Can different teams maintain components independently?
  • Parallelization: Can multiple agents execute concurrently?
  • Multi-hop: Does the pattern support multiple hops between agents?
  • Direct user interaction: Can subagents converse directly with the user?
You can mix patterns! For example, a subagents pattern can manage workflow sub-graphs or use the router pattern as a tool (querying multiple knowledge bases in parallel, then synthesizing results). A state machine can invoke skills at specific stages (loading specialized context only when reaching certain steps). The one tool for all agents approach can work within a custom workflow to parallelize independent tasks while maintaining deterministic overall structure.

Subagents

In the subagents architecture, a central main agent (often referred to as a supervisor) coordinates subagents by calling them as tools. The main agent decides which subagent to invoke, what input to provide, and how to combine results. Subagents are stateless—they don’t remember past interactions, with all conversation memory maintained by the main agent. This provides context isolation: each subagent invocation works in a clean context window, preventing context bloat in the main conversation. Key characteristics:
  • Centralized control: All routing passes through the main agent
  • No direct user interaction: Subagents return results to the main agent, not the user
  • Subagents via tools: Subagents are invoked via tools
  • Parallel execution: The main agent can invoke multiple subagents in a single turn
Use the subagents pattern when you have multiple distinct domains (e.g., calendar, email, CRM, database), subagents don’t need to converse directly with users, or you want centralized workflow control. For simpler cases with just a few tools, use a single agent.

Tutorial: Build an agent with subagents

Learn how to build a personal assistant using the subagents pattern, where a central main agent (supervisor) coordinates specialized worker agents.

Sync vs async

By default, subagent calls are synchronous—the main agent waits for each subagent to complete before continuing. This is simple and works well for most cases. For long-running tasks (reviewing contracts, conducting research, auditing code), use asynchronous execution. The main agent kicks off a background job and continues conversing with the user while the work completes.
Key characteristics:
  • Three-tool pattern: Kick off job (returns job ID), check status, get results
  • Asynchronous execution: Work proceeds in the background while main agent remains responsive
  • User-initiated checks: Main agent checks job status when the user asks, not on a polling schedule
Handling job completion: When a job finishes, your application needs to notify the user. One approach: surface a notification that, when clicked, sends a HumanMessage like “Check job_123 and summarize the results.”

Tool patterns

There are two main ways to expose subagents as tools:

Tool per agent

The key idea is wrapping subagents as tools that the main agent can call:
The main agent invokes the subagent tool when it decides the task matches the subagent’s description, receives the result, and continues orchestration. See Context engineering for fine-grained control.

Single dispatch tool

An alternative approach uses a single parameterized tool to spawn ephemeral sub-agents for independent tasks. Unlike the tool per agent approach where each sub-agent is wrapped as a separate tool, this uses a convention-based approach with a single task tool: the task description is passed as a human message to the sub-agent, and the sub-agent’s final message is returned as the tool result. Key characteristics:
  • Single task tool: One parameterized tool that can invoke any registered sub-agent by name
  • Convention-based invocation: Agent selected by name, task passed as human message, final message returned as tool result
  • Team distribution: Different teams can develop and deploy agents independently
  • Agent discovery: Sub-agents can be discovered via system prompt (listing available agents) or through progressive disclosure (loading agent information on-demand via tools)
Use this approach when you want to distribute agent development across multiple teams, need to isolate complex tasks into separate context windows, need a scalable way to add new agents without modifying the coordinator, or prefer convention over customization. This approach trades flexibility in context engineering for simplicity in agent composition and strong context isolation.
An interesting aspect of this approach is that sub-agents may have the exact same capabilities as the main agent. In such cases, spawning a sub-agent is really about context isolation as the primary reason—allowing complex, multi-step tasks to run in isolated context windows without bloating the main agent’s conversation history. The sub-agent completes its work autonomously and returns only a concise summary, keeping the main thread focused and efficient.

Context engineering

Control how context flows between the main agent and its subagents:

Subagent specs

The name and description you give a subagent tool determine when the main agent decides to invoke it. These are prompting levers—choose them carefully.
  • Name: How the main agent refers to the sub-agent. Keep it clear and action-oriented (e.g., research_agent, code_reviewer).
  • Description: What the main agent knows about the sub-agent’s capabilities. Be specific about what tasks it handles and when to use it.

Subagent inputs

Customize what context the subagent receives to execute its task. Add input that isn’t practical to capture in a static prompt—full message history, prior results, or task metadata—by pulling from the agent’s state.

Subagent outputs

Customize what the main agent receives back so it can make good decisions. Two strategies:
  1. Prompt the sub-agent: Specify exactly what should be returned. A common failure mode is that the sub-agent performs tool calls or reasoning but doesn’t include results in its final message—remind it that the supervisor only sees the final output.
  2. Format in code: Adjust or enrich the response before returning it. For example, pass specific state keys back in addition to the final text using a Command.

Handoffs

In the handoffs architecture, behavior changes dynamically based on state. The core mechanism: tools update a state variable (e.g., current_step or active_agent) that persists across turns, and the system reads this variable to adjust behavior—either applying different configuration (system prompt, tools) or routing to a different agent. This pattern supports both handoffs between distinct agents and dynamic configuration changes within a single agent.
The term handoffs was coined by OpenAI for using tool calls (e.g., transfer_to_sales_agent) to transfer control between agents or states.
Key characteristics:
  • State-driven behavior: Behavior changes based on a state variable (e.g., current_step or active_agent)
  • Tool-based transitions: Tools update the state variable to move between states
  • Direct user interaction: Each state’s configuration handles user messages directly
  • Persistent state: State survives across conversation turns
Use the handoffs pattern when you need to enforce sequential constraints (unlock capabilities only after preconditions are met), the agent needs to converse directly with the user across different states, or you’re building multi-stage conversational flows. This pattern is particularly valuable for customer support scenarios where you need to collect information in a specific sequence — for example, collecting a warranty ID before processing a refund.

Tutorial: Build a customer support agent using handoffs

Learn how to build a customer support agent using the handoffs pattern, where a single agent transitions between different configurations.
There are two ways to implement handoffs: single agent with middleware (one agent with dynamic configuration) or multiple agent subgraphs (distinct agents as graph nodes).

Single agent with middleware

A single agent changes its behavior based on state. Middleware intercepts each model call and dynamically adjusts the system prompt and available tools. Tools update the state variable to trigger transitions:

Multiple agent subgraphs

Multiple distinct agents exist as separate nodes in a graph. Handoff tools navigate between agent nodes using Command.PARENT to specify which node to execute next:
This example shows a multi-agent system with separate sales and support agents. Each agent is a separate graph node, and handoff tools allow agents to transfer conversations to each other.
Use single agent with middleware for most handoffs use cases—it’s simpler. Only use multiple agent subgraphs when you need bespoke agent implementations (e.g., a node that’s itself a complex graph with reflection or retrieval steps).
Implementation considerations:
  • Conversation history: Decide what conversation history each agent/state receives—full history, filtered portions, or summaries.
  • Tool semantics: Clarify whether handoff tools only update routing state or also perform actions (e.g., should transfer_to_sales() also create a ticket?).

Skills

In the skills architecture, specialized capabilities are packaged as invokable “skills” that augment an agent’s behavior. Skills are primarily prompt-driven specializations that an agent can invoke on-demand. Key characteristics:
  • Prompt-driven specialization: Skills are primarily defined by specialized prompts
  • Progressive disclosure: Skills become available based on context or user needs
  • Team distribution: Different teams can develop and maintain skills independently
  • Lightweight composition: Skills are simpler than full sub-agents
Use the skills pattern when you want a single agent with many possible specializations, you don’t need to enforce specific constraints between skills, or different teams need to develop capabilities independently. Common examples include coding assistants (skills for different languages or tasks), knowledge bases (skills for different domains), and creative assistants (skills for different formats).
This pattern is conceptually identical to llms.txt (introduced by Jeremy Howard), which uses tool calling for progressive disclosure of documentation. The skills pattern applies the same approach to specialized prompts and domain knowledge rather than just documentation pages.

Extending the pattern

When writing custom implementations, you can extend the basic skills pattern in several ways: Dynamic tool registration: Combine progressive disclosure with state management to register new tools as skills load. For example, loading a “database_admin” skill could both add specialized context and register database-specific tools (backup, restore, migrate). This uses the same tool-and-state mechanisms used across multi-agent patterns—tools updating state to dynamically change agent capabilities. Hierarchical skills: Skills can define other skills in a tree structure, creating nested specializations. For instance, loading a “data_science” skill might make available sub-skills like “pandas_expert”, “visualization”, and “statistical_analysis”. Each sub-skill can be loaded independently as needed, allowing for fine-grained progressive disclosure of domain knowledge. This hierarchical approach helps manage large knowledge bases by organizing capabilities into logical groupings that can be discovered and loaded on-demand.

Tutorial: Build an agent with on-demand skill loading

Learn how to implement skills with progressive disclosure, where the agent loads specialized prompts and schemas on-demand rather than upfront.

Router

In the router architecture, a routing step classifies input and directs it to specialized agents. This is useful when you have distinct verticals—separate knowledge domains that each require their own agent. Key characteristics:
  • Router decomposes the query
  • Zero or more specialized agents are invoked in parallel
  • Results are synthesized into a coherent response
Two approaches:

Stateless

Each request is routed independently—no memory between calls. For multi-turn conversations, see Stateful routers.
Stateless router vs Subagents: The subagents pattern can also route to multiple agents. Use the stateless router when you need specialized preprocessing or custom routing logic. Use the subagents pattern when you want the LLM to decide which agents to call dynamically.
Your organization’s knowledge lives in multiple places: GitHub repositories, Notion wikis, and Slack conversations. These are three distinct verticals, each requiring specialized tools and context. When users ask questions like “How do I authenticate API requests?”, the answer may require information from multiple sources. This example builds a router that decomposes queries, identifies which verticals to consult, queries them in parallel, and synthesizes results.

Stateful

For multi-turn conversations, you need to maintain context across invocations.

Tool wrapper

The simplest approach: wrap the stateless router as a tool that a conversational agent can call. The conversational agent handles memory and context; the router stays stateless. This avoids the complexity of managing conversation history across multiple parallel agents.

Full persistence

If you need the router itself to maintain state, use persistence to store message history. When routing to an agent, fetch previous messages from state and selectively include them in the agent’s context—this is a lever for context engineering.
Stateful routers require custom history management. If the router switches between agents across turns, conversations may not feel fluid to end users when agents have different tones or prompts. With parallel invocation, you’ll need to maintain history at the router level (inputs and synthesized outputs) and leverage this history in routing logic. Consider the handoffs pattern or subagents pattern instead—both provide clearer semantics for multi-turn conversations.

Custom workflow

In the custom workflow architecture, you define your own bespoke execution flow using LangGraph. You have complete control over the graph structure—including sequential steps, conditional branches, loops, and parallel execution. Use custom workflows when:
  • Standard patterns (subagents, skills, etc.) don’t fit your requirements
  • You need to mix deterministic logic with agentic behavior
  • Your use case requires complex routing or multi-stage processing
Each node in your workflow can be a simple function, an LLM call, or an entire agent with tools. You can also compose other architectures within a custom workflow—for example, embedding a multi-agent system as a single node. The router pattern is an example of a custom workflow.
Calling a LangChain agent from a LangGraph node: The main insight when mixing LangChain and LangGraph is that you can call a LangChain agent directly inside any LangGraph node. This lets you combine the flexibility of custom workflows with the convenience of pre-built agents:
Example: RAG pipeline — A common use case is combining retrieval with an agent. This example builds a WNBA stats assistant that retrieves from a knowledge base and can fetch live news.
The workflow demonstrates three types of nodes:
  • Model node (Rewrite): Rewrites the user query for better retrieval using structured output.
  • Deterministic node (Retrieve): Performs vector similarity search — no LLM involved.
  • Agent node (Agent): Reasons over retrieved context and can fetch additional information via tools.
You can use LangGraph state to pass information between workflow steps. This allows each part of your workflow to read and update structured fields, making it easy to share data and context across nodes.

Connect these docs programmatically to Claude, VSCode, and more via MCP for real-time answers.