LangChain Multi-Agent
When a task is too complex for a single Agent to handle, you can create multiple Agents with distinct responsibilities and let them collaborate like a team.
Why Do You Need Multi-Agent
Problems with a Single Agent:
- An overly long system_prompt can cause the model's attention to scatter
- Too many tools increase the probability of the model choosing the wrong tool
- Different types of tasks require different expertise and behavioral styles
The multi-agent approach: each Agent focuses on one domain, and complex tasks are completed through collaboration.
Method 1: Sub-Agent as a Tool
Compile the Agent into a CompiledStateGraph, then register it as a tool with the parent Agent:
Example
load_dotenv()
from langchain.tools import tool
from langchain.agents import create_agent
from langchain.chat_models import init_chat_model
from langchain.messages import HumanMessage
model = init_chat_model("deepseek:deepseek-v4-flash", temperature=0)
# Sub-Agent 1: Weather Expert
@tool
def get_weather(city: str) -> str:
"""Query the weather"""
data = {"Hangzhou": "Sunny, 25°C", "Beijing": "Cloudy, 18°C"}
return data.get(city, f"{city}: data temporarily unavailable")
weather_agent = create_agent(
model=model,
tools=[get_weather],
name="weather_expert", # The name is used for identification and logging
system_prompt="You are a weather expert, specializing in answering weather-related questions. Keep answers concise.",
)
# Sub-Agent 2: Calculation Expert
@tool
def calculate(expression: str) -> str:
"""Calculate mathematical expressions"""
result = eval(expression, {"__builtins__": {}}, {})
return f"{expression} = {result}"
math_agent = create_agent(
model=model,
tools=[calculate],
name="math_expert",
system_prompt="You are a math expert, specializing in mathematical calculations. Keep answers concise.",
)
# Parent Agent: Coordinator
# Register sub-agents as tools
@tool
def ask_weather_expert(question: str) -> str:
"""Consult the weather expert about weather-related questions.
Args:
question: Questions about the weather
"""
result = weather_agent.invoke(
{"messages": [HumanMessage(content=question)]}
)
return result["messages"][-1].content
@tool
def ask_math_expert(question: str) -> str:
"""Consult the math expert about mathematical calculation problems.
Args:
question: Mathematical calculation problems
"""
result = math_agent.invoke(
{"messages": [HumanMessage(content=question)]}
)
return result["messages"][-1].content
coordinator = create_agent(
model=model,
tools=[ask_weather_expert, ask_math_expert],
system_prompt="""You are the coordination assistant. Choose the appropriate expert based on the user's question:
- Weather-related questions → use ask_weather_expert
- Mathematical calculation problems → use ask_math_expert
- If multiple domains are involved at the same time, consult each expert in sequence""",
)
# Test compound question
result = coordinator.invoke({
"messages": [HumanMessage(
content="How's the weather in Hangzhou today? If the temperature is 25 degrees, what is it in Fahrenheit?"
"(Formula: Fahrenheit = Celsius × 9/5 + 32)"
)]
})
print(result["messages"][-1].content)
Execution result:
根据天气专家的查询,杭州今天晴天,气温25°C。 换算成华氏度:25 × 9/5 + 32 = 77°F。 所以杭州今天25°C,相当于77°F,天气晴好。
Method 2: Distinguish Agents with the name Parameter
When embedding a sub-agent as a tool, setting the name parameter helps track the source of messages:
Example
# 1. The name is used in the compiled graph
# 2. The name is used when embedding as a subgraph node into the parent graph
# 3. All AI messages are labeled with this name
agent = create_agent(
model=model,
tools=[...],
name="customer_service", # Name the Agent
)
Method 3: Agent Routing with Middleware
More complex multi-agent scenarios can achieve dynamic routing through Middleware:
Example
# Define the tool sets used by different experts
general_tools = [tool_a, tool_b]
admin_tools = [tool_c, tool_d]
@before_model
def route_by_user_role(state, runtime):
"""Dynamically switch available tools based on user role"""
context = runtime.context
if context is None:
return None
user_role = context.get("user_role", "user")
# Different roles see different tools
if user_role == "admin":
available_tools = general_tools + admin_tools
else:
available_tools = general_tools
# Note: before_model cannot directly modify tools,
# It needs to be implemented together with wrap_model_call or request.override
return None
Multi-Agent Architecture Patterns
| Pattern | Structure | Applicable Scenario |
|---|---|---|
| Coordinator Pattern | One parent Agent → multiple sub-agent tools | Tasks that are clearly classifiable by type |
| Relay Pattern | Agent A's output → Agent B's input | Pipeline-style processing (generate → review → polish) |
| Debate Pattern | Multiple Agents output in parallel → summarize and make decisions | Problems that require multi-perspective analysis |
Other ExtensionsA multi-agent system increases complexity and Token consumption. Don't use multi-agent just for the sake of "multi-agent" — first try to solve the problem with a single Agent + a well-designed system_prompt and Middleware. Only introduce multi-agent when you truly need domain isolation or independent context.