of LLMs’ reasoning capabilities with memory, planning, and tool use (creating what we call agents) has expanded the range of tasks LLMs can perform.
However, a single agent alone has its limitations. When coupled with too many tools or an overly large context, it often leads to poor decisions and subpar responses.
This is why multi-agent systems have grown in popularity, as they allow us to tackle use cases of increasing complexity.
Multi-agent systems connect numerous specialized agents that work together, each focusing on a specific task, while the system routes queries to the right expert.
Example of a multi-agent system for customer support | Image used under MIT License
Think of it as a team of experts collaborating, each contributing their own specialized skills through a “divide-and-conquer” approach.
In this article, we will clearly explore one of the key concepts in multi-agent systems: how agents transfer control to one another.
Contents
(1) Primer to LangGraph
(2) Definition of Agentic Handoffs
(3) Example Scenario
(4) Handoffs in LangGraph
Here is the link to the accompanying GitHub repo.
(1) Primer to LangGraph
[Optional Reading]
LangGraph is an open-source orchestration framework for building stateful, LLM-based agentic systems that reliably handle complex tasks.
It allows developers to design workflows as graphs, where each graph consists of nodes (representing tasks or LLM calls) and edges (representing control flow).
LangGraph is my framework of choice for building agentic systems because of its key strengths:
- Low-level controllability that offers precise control over transitions, states, and how each agent executes.
- Transparent and intuitive graph-based workflows that make complex logic easy to understand, set up, and trace.
- Flexible non-chat workflows that support agentic orchestration beyond conversational agents (e.g., frameworks like AutoGen)
The image below shows what a graph-based workflow designed for retrieval augmented generation looks like:
Example of LangGraph graph for retrieval augmented generation | MIT License
(2) Definition of Agentic Handoffs
First, let’s understand what a handoff means.
An agentic handoff is the moment when an agent directly and dynamically passes control to another agent after finishing its work.
This is important because we want tasks to be routed to the agent best equipped to provide a context-aware response.
In technical terms, a handoff occurs when one agent transfers control, responsibility, or conversational context to another agent to ensure continuity and relevance in the interaction.
The image below illustrates a three-agent architecture based on the supervisor pattern, in which a central agent coordinates the specialized worker agents (a research agent and a document-authoring agent).
Image used under MIT License
In this case, handoffs can occur in both directions between the supervisor and each worker agent.
Each worker gains its specialization through integration with a specific set of tools and customized prompts.
Suppose the user query is “Research how social media usage affects adolescent mental health”.
The supervisor agent, being aware of the nature of the user query and the worker agents at its disposal, will hand off the task to the research agent to carry out the next turn.
Here is the flow:
- Supervisor agent analyzes user intent and decides that it needs assistance from the research agent
- Supervisor passes control (and state*) to the research agent
- The research agent performs the task and decides whether to handoff back to the supervisor agent or end the conversation.
* State is the multi-agent system’s short-term memory, capturing recent conversations and key information so each agent can act appropriately based on prior context and information.
(3) Example Scenario
Let’s look at the example scenario to anchor our walkthrough.
We will set up a real estate assistant capable of answering queries related to properties in Singapore. It is designed as a three-agent system based on the popular supervisor pattern.
In this scenario, we have a real estate manager (supervisor) with access to two specialized worker agents:
- Property profile agent: Handles queries related to housing property details.
- Transaction history agent: Handles queries related to property transactions and market trends.
The routing has been simplified to be one-way i.e. once the worker agent completes its task, the conversation ends.
Graph diagram of the three-agent supervisor architecture | Image by author
For the coordination to work, the supervisor agent must be aware of its role, overall workflow, and agents at its disposal. We do this with a prompt like this:
Notice that the instructions for the handoff criteria are explicitly defined in the prompt.
The code for the supervisor node for conditional routing is as follows:
While multi-agent systems can follow different design patterns and scale to far more nodes, this simple example allows us to concentrate on the idea of agent handoffs.
The following screenshot shows the output of our real estate multi-agent system for a user query:
As we will focus on agent handoffs, I will not be detailing the full LangGraph setup code (e.g., prompts, nodes, LLM calls). However, you can find the code implementation in this GitHub repo.
(4) Handoffs in LangGraph
There are two mechanisms for agent handoffs in LangGraph:
- Conditional edges
- Command object
(4.1) Conditional Edges (Static Routing-Based Handoff)
A conditional edge is the classic graph-routing method for handing off control between agents.
In a graph, nodes do the work while edges inform what to do next.
Edges are functions that decide the routing logic (i.e., which node to execute next). This routing can be direct fixed transitions or based on specific conditions (aka conditional edges).
Put simply, the flow in a conditional edge is as follows:
- A node generates an output
- Output is passed to the conditional edge as input
- The function in the conditional edge evaluates it and chooses the next node to run
Conditional edge in the real estate assistant example scenario | Image by author
In LangGraph, we define conditional edges by calling add_conditional_edges on an StateGraph instance:
graph.add_conditional_edges(source=”start_node”, path=routing_function)
- source argument refers to the starting node. It means that after this node finishes, the conditional routing kicks in.
- path argument takes the conditional function, and its return value controls which node the graph moves to next.
Let us first explore the routing function (should_continue) of our real estate example:
Here is what the routing function is doing:
- Read the supervisor’s latest response and decide what to do next.
- Check whether the supervisor explicitly asked to hand the task off to either of the two worker agents.
- When the supervisor names a worker agent, the function returns that agent’s name as a string, triggering a handoff to that agent.
- If the supervisor did not request any worker agent, the function returns “end”, meaning the supervisor has responded and the workflow ends.
With the routing function set up, we next define the conditional edges:
- The supervisornode serves as the source entry point of the flow, where it first receives and analyzes the user query.
- After the supervisor completes processing, the routing function should_continue comes into play, examining the supervisor’s response to determine the handoff decision.
- The path_map dict translates the routing function’s return values into graph targets. This is needed as should_continue may return “end”, which path_map converts into END, LangGraph’s stop signal.
The above essentially shows how agentic handoffs work: the supervisor outputs specific strings that the conditional function uses to route to the next agent or terminate.
(4.2) Command Object (Dynamic Handoff)
Conditional edges work well for simple, predictable flows, but once the logic becomes more complex, wiring together many conditional edges can become tedious and unintuitive.
To make multi-agent workflows more flexible and easier to design, the Command type was introduced to combine state updates and control flow.
It simplifies things by letting nodes return a Command object that updates the graph state and specifies the next node to execute.
Instead of relying on predefined edges, the node can itself directly and dynamically determine the next step based on its own logic at runtime.
This enables edgeless graphs, where routing lives within agents rather than in a clutter of conditional rules, resulting in a cleaner, more flexible way to orchestrate handoffs.
Here is a minimal code for using Command in a router node:
In the above, the router agent node reads the state, decides what should run next, and returns a Command that updates the graph state and points to the next node.
Since the node chooses the next step using the goto argument, there is no need to define conditional edges with add_conditional_edges.
Command makes it such that the handoff logic sits in the nodes rather than the edges. Hence, we expect the code in our supervisor node to be more lengthy:
- The supervisor node calls an LLM to return aSupervisorDecision structured output object containing two key things: which agent to hand off to, and any relevant context, like the property name extracted from the user’s message.
- If no worker agent is needed, the supervisor responds directly. The node returns a Command that updates the messages with the response and ends the graph.
- If a handoff is needed, the node builds an update dictionary. It includes a routing message from the supervisor and the extracted context (e.g., the property name) in the graph state, so that the next agent can use it immediately.
- Finally, the node returns a Command that specifies the next agent using goto and applies state updates (i.e., update property_name).
The Literal[“transaction_history_agent”, “property_profile_agent”] type hint allows us to generate the complete Mermaid graph diagram even when we did not explicitly define the edges. The actual handoff flow is handled by the goto parameter.
Real estate multi-agent system with edges shown (even with Command being used) | Image by author
With Command, the nodes directly decide which agent runs next and what to pass along. It eliminates separate routing rules and keeps the handoff logic clean.
(4.3) When to use conditional edges or Command?
Here is how to choose conditional edges versus Command for handoffs:
Use conditional edges when:
- You only need to decide which node runs next based on the current graph state, without changing it.
Use Command when:
- Your node needs to modify its state and determine the next node simultaneously.
- This is useful in multi-agent handoffs where routing to another agent usually requires passing some information to that agent.
In my work, I have largely switched to using Command instead of conditional edges given that many multi-agent systems require coordinated graph state updates alongside routing decisions.
Wrapping It Up
Agent handoffs are the core mechanism that makes a multi-agent system work effectively. In this article, we covered how those handoffs work in practice, with LangGraph serving as the implementation layer to express them using conditional routing or the Command object.
Whatever framework we use, the idea remains the same: clear, consistent handoffs are what enable agents to work together.
Check out this GitHub repo for the code implementation.

