A single agent might struggle if it needs to specialize in multiple domains or manage many tools. To tackle this, you can break your agent into smaller, independent agents and composing them into a multi-agent system. In multi-agent systems, agents need to communicate between each other. They do so via handoffs — a primitive that describes which agent to hand control to and the payload to send to that agent. This guide covers the following: To get started with building multi-agent systems, check out LangGraph prebuilt implementations of two of the most popular multi-agent architectures — supervisor and swarm.

Handoffs

To set up communication between the agents in a multi-agent system you can use handoffs — a pattern where one agent hands off control to another. Handoffs allow you to specify:
  • destination: target agent to navigate to (e.g., name of the LangGraph node to go to)
  • payload: information to pass to that agent (e.g., state update)

Create handoffs

To implement handoffs, you can return Command objects from your agent nodes or tools:
import { tool } from "@langchain/core/tools";
import { Command, MessagesZodState } from "@langchain/langgraph";
import { z } from "zod";

function createHandoffTool({
  agentName,
  description,
}: {
  agentName: string;
  description?: string;
}) {
  const name = `transfer_to_${agentName}`;
  const toolDescription = description || `Transfer to ${agentName}`;

  return tool(
    async (_, config) => {
      // (1)!
      const state = config.state;
      const toolCallId = config.toolCall.id;

      const toolMessage = {
        role: "tool" as const,
        content: `Successfully transferred to ${agentName}`,
        name: name,
        tool_call_id: toolCallId,
      };

      return new Command({
        // (3)!
        goto: agentName,
        // (4)!
        update: { messages: [...state.messages, toolMessage] },
        // (5)!
        graph: Command.PARENT,
      });
    },
    {
      name,
      description: toolDescription,
      schema: z.object({}),
    }
  );
}
  1. Access the state of the agent that is calling the handoff tool through the config parameter.
  2. The Command primitive allows specifying a state update and a node transition as a single operation, making it useful for implementing handoffs.
  3. Name of the agent or node to hand off to.
  4. Take the agent’s messages and add them to the parent’s state as part of the handoff. The next agent will see the parent state.
  5. Indicate to LangGraph that we need to navigate to agent node in a parent multi-agent graph.
If you want to use tools that return Command, you can either use prebuilt create_react_agent / ToolNode components, or implement your own tool-executing node that collects Command objects returned by the tools and returns a list of them, e.g.:
const callTools = async (state) => {
  // ...
  const commands = await Promise.all(
    toolCalls.map(toolCall => toolsByName[toolCall.name].invoke(toolCall))
  );
  return commands;
};
This handoff implementation assumes that:
  • each agent receives overall message history (across all agents) in the multi-agent system as its input. If you want more control over agent inputs, see this section
  • each agent outputs its internal messages history to the overall message history of the multi-agent system. If you want more control over how agent outputs are added, wrap the agent in a separate node function:
    const callHotelAssistant = async (state) => {
      // return agent's final response,
      // excluding inner monologue
      const response = await hotelAssistant.invoke(state);
      // highlight-next-line
      return { messages: [response.messages.at(-1)] };
    };
    

Control agent inputs

You can use the Send() primitive to directly send data to the worker agents during the handoff. For example, you can request that the calling agent populate a task description for the next agent:
import { tool } from "@langchain/core/tools";
import { Command, Send, MessagesZodState } from "@langchain/langgraph";
import { z } from "zod";

function createTaskDescriptionHandoffTool({
  agentName,
  description,
}: {
  agentName: string;
  description?: string;
}) {
  const name = `transfer_to_${agentName}`;
  const toolDescription = description || `Ask ${agentName} for help.`;

  return tool(
    async (
      { taskDescription },
      config
    ) => {
      const state = config.state;
      
      const taskDescriptionMessage = {
        role: "user" as const,
        content: taskDescription,
      };
      const agentInput = {
        ...state,
        messages: [taskDescriptionMessage],
      };
      
      return new Command({
        // highlight-next-line
        goto: [new Send(agentName, agentInput)],
        graph: Command.PARENT,
      });
    },
    {
      name,
      description: toolDescription,
      schema: z.object({
        taskDescription: z
          .string()
          .describe(
            "Description of what the next agent should do, including all of the relevant context."
          ),
      }),
    }
  );
}
See the multi-agent supervisor example for a full example of using Send() in handoffs.

Build a multi-agent system

You can use handoffs in any agents built with LangGraph. We recommend using the prebuilt agent or ToolNode, as they natively support handoffs tools returning Command. Below is an example of how you can implement a multi-agent system for booking travel using handoffs:
import { createReactAgent } from "@langchain/langgraph/prebuilt";
import { StateGraph, START, MessagesZodState } from "@langchain/langgraph";
import { z } from "zod";

function createHandoffTool({
  agentName,
  description,
}: {
  agentName: string;
  description?: string;
}) {
  // same implementation as above
  // ...
  return new Command(/* ... */);
}

// Handoffs
const transferToHotelAssistant = createHandoffTool({
  agentName: "hotel_assistant",
});
const transferToFlightAssistant = createHandoffTool({
  agentName: "flight_assistant",
});

// Define agents
const flightAssistant = createReactAgent({
  llm: model,
  // highlight-next-line
  tools: [/* ... */, transferToHotelAssistant],
  // highlight-next-line
  name: "flight_assistant",
});

const hotelAssistant = createReactAgent({
  llm: model,
  // highlight-next-line
  tools: [/* ... */, transferToFlightAssistant],
  // highlight-next-line
  name: "hotel_assistant",
});

// Define multi-agent graph
const multiAgentGraph = new StateGraph(MessagesZodState)
  // highlight-next-line
  .addNode("flight_assistant", flightAssistant)
  // highlight-next-line
  .addNode("hotel_assistant", hotelAssistant)
  .addEdge(START, "flight_assistant")
  .compile();

Multi-turn conversation

Users might want to engage in a multi-turn conversation with one or more agents. To build a system that can handle this, you can create a node that uses an interrupt to collect user input and routes back to the active agent. The agents can then be implemented as nodes in a graph that executes agent steps and determines the next action:
  1. Wait for user input to continue the conversation, or
  2. Route to another agent (or back to itself, such as in a loop) via a handoff
import { interrupt, Command } from "@langchain/langgraph";

function human(state: MessagesState): Command {
  const userInput: string = interrupt("Ready for user input.");

  // Determine the active agent
  const activeAgent = /* ... */;

  return new Command({
    update: {
      messages: [{
        role: "human",
        content: userInput,
      }]
    },
    goto: activeAgent,
  });
}

function agent(state: MessagesState): Command {
  // The condition for routing/halting can be anything, e.g. LLM tool call / structured output, etc.
  const goto = getNextAgent(/* ... */); // 'agent' / 'anotherAgent'

  if (goto) {
    return new Command({
      goto,
      update: { myStateKey: "myStateValue" }
    });
  }

  return new Command({ goto: "human" });
}

Prebuilt implementations

LangGraph comes with prebuilt implementations of two of the most popular multi-agent architectures:
  • supervisor — individual agents are coordinated by a central supervisor agent. The supervisor controls all communication flow and task delegation, making decisions about which agent to invoke based on the current context and task requirements. You can use langgraph-supervisor library to create a supervisor multi-agent systems.
  • swarm — agents dynamically hand off control to one another based on their specializations. The system remembers which agent was last active, ensuring that on subsequent interactions, the conversation resumes with that agent. You can use langgraph-swarm library to create a swarm multi-agent systems.