In the last section, we mainly used Command to implement the transfer of multiple agents. In this section, we will learn how to use tools to achieve this functionality.
Tool for Implementing Transfer
We have clearly defined custom transfers in each agent node. Another pattern is to create a special handoff tool that directly returns a Command object.
When an agent calls such a tool, it hands over control to another agent. Specifically, the tool execution node in the agent will recognize the command object returned by the tool and route the control flow accordingly.
Note: Unlike the previous example, the tool call agent is not a single node but can be added as a subgraph node to another graph in the multi-agent graph.
Here are some important points regarding implementation:
-
Since each agent is a subgraph node in another graph, and the tool will be called within one of the agent subgraph nodes (e.g., tool executor), we need to specify graph=Command.PARENT in the command so that LangGraph knows the path outside the agent subgraph.
-
We can choose to specify state updates that will be applied to the parent graph state before calling the next agent. These state updates can be used to control the amount of chat message history visible to the target agent. For example, you might choose to share only the last AI message from the current agent, or its complete internal chat history, etc. In the example below, we will share the complete internal chat history.
-
We can choose to populate the following parameters for the tool:
Graph State: via injectedState; Graph Long-term Memory (using InjectedStore); Current Tool Call ID (using InjectedToolCallId)
These are not required but are useful for creating state updates passed to the next agent.
from typing import Annotated
from langchain_core.tools.base import InjectedToolCallId
from langgraph.prebuilt import InjectedState
# This method is just a wrapper for code reuse
def make_handoff_tool(*, agent_name: str):
"""Create a tool that can return a handoff through Command"""
tool_name = f"transfer_to_{agent_name}"
# Here the parameters use annotations so that they can be automatically injected during the call, instead of manually checked and set as before
@tool(tool_name)
def handoff_to_agent(
# Optionally pass the current graph state to the tool (will be ignored by LLM)
state: Annotated[dict, InjectedState],
# Optionally pass the current tool call ID (will be ignored by LLM)
tool_call_id: Annotated[str, InjectedToolCallId],
):
"""Request help from another agent."""
tool_message = ToolMessage(content=f"Successfully transferred to {agent_name}",
name=tool_name,
tool_call_id=tool_call_id)
return Command(
# Navigate to another agent node in the PARENT graph
goto=agent_name,
graph=Command.PARENT,
# This is the state update that the agent `agent_name` will see when called.
# We pass the complete internal message history of the agent and add a tool message to ensure the resulting chat history is valid.
update={"messages": state["messages"] + [tool_message]},
)
return handoff_to_agent
Let’s define the mathematical tools we will provide for the agents:
from langchain_core.messages import ToolMessage
from langchain_core.tools import tool
from langgraph.graph import MessagesState, StateGraph, START
from langgraph.types import Command
@tool
def add(a: int, b: int) -> int:
"""Add two numbers."""
return a + b
@tool
def multiply(a: int, b: int) -> int:
"""Multiply two numbers."""
return a * b
from langchain_ollama import ChatOllama
import base_conf
model = ChatOllama(base_url=base_conf.base_url,
model=base_conf.model_name,
temperature=0)
from langgraph.prebuilt import create_react_agent
# Create two agents, one is an addition expert, the other is a multiplication expert
addition_expert = create_react_agent(
model,
[add, make_handoff_tool(agent_name="multiplication_expert")],
state_modifier="You are an addition expert, you can ask the multiplication expert for help with multiplication.",
)
multiplication_expert = create_react_agent(
model,
[multiply, make_handoff_tool(agent_name="addition_expert")],
state_modifier="You are a multiplication expert, you can ask an addition expert for help with addition.",
)
Then build our graph and try it out
builder = StateGraph(MessagesState)
builder.add_node("addition_expert", addition_expert)
builder.add_node("multiplication_expert", multiplication_expert)
builder.add_edge(START, "addition_expert")
graph = builder.compile()
from langchain_core.messages import convert_to_messages
def pretty_print_messages(update):
if isinstance(update, tuple):
ns, update = update
# Skip parent graph updates in the print output
if len(ns) == 0:
return
graph_id = ns[-1].split(":")[0]
print(f"Update from subgraph {graph_id}:")
print("\n")
for node_name, node_update in update.items():
print(f"Update from node {node_name}:")
print("\n")
for m in convert_to_messages(node_update["messages"]):
m.pretty_print()
print("\n")
for chunk in graph.stream({"messages": [("user", "what's (3 + 5) * 12")]}) :
pretty_print_messages(chunk)
Update from node addition_expert:
================================ Human Message =================================
what's (3 + 5) * 12
================================== Ai Message ==================================
Tool Calls: add (d6bbf9e9-235e-40ec-8970-48e7adbff070) Call ID: d6bbf9e9-235e-40ec-8970-48e7adbff070 Args:
a: 3
b: 5
================================= Tool Message =================================
Name: add
8
================================== Ai Message ==================================
Tool Calls: transfer_to_multiplication_expert (5a851781-4cf3-4bf9-8b30-347736c8a7f5) Call ID: 5a851781-4cf3-4bf9-8b30-347736c8a7f5 Args:
================================= Tool Message =================================
Name: transfer_to_multiplication_expert
Successfully transferred to multiplication_expert
Update from node multiplication_expert:
================================ Human Message =================================
what's (3 + 5) * 12
================================== Ai Message ==================================
Tool Calls: add (d6bbf9e9-235e-40ec-8970-48e7adbff070) Call ID: d6bbf9e9-235e-40ec-8970-48e7adbff070 Args:
a: 3
b: 5
================================= Tool Message =================================
Name: add
8
================================== Ai Message ==================================
Tool Calls: transfer_to_multiplication_expert (5a851781-4cf3-4bf9-8b30-347736c8a7f5) Call ID: 5a851781-4cf3-4bf9-8b30-347736c8a7f5 Args:
================================= Tool Message =================================
Name: transfer_to_multiplication_expert
Successfully transferred to multiplication_expert
================================== Ai Message ==================================
Tool Calls: multiply (aa714a78-e60f-469e-bed7-dad9d2a73e50) Call ID: aa714a78-e60f-469e-bed7-dad9d2a73e50 Args:
a: 8
b: 12
================================= Tool Message =================================
Name: multiply
96
================================== Ai Message ==================================
The result of (3 + 5) * 12 is 96.
The core idea is that the information that was previously manually judged and set is replaced with the method of Injecte.