多智能体与A2A
多智能体定义:
多智能体不是“多开几个模型调用”这么简单。它指的是:把复杂任务拆给多个专精的 Agent,让它们分工、路由、协作,再共同完成整体任务。
多智能体的核心变化不是“数量变多”,而是:角色开始分工、上下文开始隔离、控制流开始显式编排
A2A协议定义:
全称是 Agent-to-Agent。它是一种面向 Agent 系统互操作的开放协议,目标是让不同 Agent 能以更标准化的方式发现彼此、发送任务、交换消息、返回结果。
A2A 里面几个很核心的概念包括:
- Agent Card:相当于 Agent 的“名片 / 能力说明”
- Task:一项被发给远程 Agent 的任务
- Message:围绕任务交换的消息
- Artifact:任务过程或结果产出的内容
如果把它们串成一条最小调用链,可以这样记:
- 先发现 Agent:调用方先读取
Agent Card,确认对方会什么、支持什么输入输出。 - 再提交 Task:把任务目标、上下文消息、必要参数发给远程 Agent。
- 过程中跟状态:长任务通常不是一次就结束,调用方会通过轮询、流式更新或通知拿到任务进度。
- 最后取结果:读取最终
Message/Artifact,把它当成另一套 Agent 的产出继续接到自己的系统里。
A2A和MCP的区别:
- MCP:Agent / 模型怎么接工具、资源、上下文
- A2A:Agent 和 Agent 怎么协作
多智能体模式
- Subagents(子代理):主 Agent 把子 Agent 当工具来调
- Handoffs(交接):不同 Agent 之间可以交接控制权
- Skills(技能):单 Agent 按需加载专业上下文 / 技能包
- Route(路由):先做路由,再把任务交给更合适的 Agent
- Custom workflow(自定义工作流):直接用 LangGraph 自定义工作流,把上述模式混合起来
从教学角度看,可以把它们分成两大类:
- 一个主控中心在调别人:Subagents、Router
- 控制权本身会转移:Handoffs
多智能体常见形态
- 单智能体(Single Agent):一个 Agent 负责整条任务链路,适合简单任务和教程起步。
- Supervisor(主管型):一个中心主管负责决定调用哪个子 Agent,适合统一入口和集中调度。
- Handoff(交接型):当前 Agent 可以把控制权交给别的 Agent,更适合角色切换和会话延续。
- Router(路由型):先判断任务属于哪类,再把任务交给某个专门 Agent。
- Network / Peer-to-peer(网络型):多个 Agent 更平等地交换信息,没有单一主管,适合研究、协作式问题求解。
- Hierarchical(层级型):多层主管和子主管分层拆任务,适合复杂组织结构。
使用场景:
| 场景 | 更适合的模式 |
|---|---|
| 单领域、小任务、统一控制 | 单智能体 / Skills |
| 多工具、多专业角色、统一入口 | Supervisor / Subagents |
| 用户与不同角色来回切换 | Handoffs |
| 先分类再交给不同专家 | Router |
| 复杂系统、强流程编排 | Custom workflow(LangGraph) |
SuperVisor:
Supervisor(主管型)是最适合初学者入门的一种。原因很简单:有一个中心主管,结构更好理解;控制流更集中;更接近“项目经理分配任务”的直觉。
Supervisor 结构里,最核心的不是“子 Agent 有几个”,而是:
- 主管是不是唯一调度中心
- 子 Agent 是否专注自己的狭窄领域
- 用户是否主要和主管交互
这个模式特别适合:企业助手、旅行预订、客服分流、多部门协作场景
案例:
# 子 Agent 用 langchain.agents.create_agent,主管用 langgraph_supervisor.create_supervisor;交互式输入 + 流式输出 + 简单中文过滤
# 用 create_agent 定义子 Agent,再由 create_supervisor 统一调度,形成更贴近当前主流写法的多智能体结构
# 这里的“主管调子 Agent”本质上对应官方多智能体文档里的 Subagents 模式;主管负责统一入口与路由,子 Agent 负责狭窄领域任务
# pip install langgraph-supervisor;子 Agent 的工具函数必须具备清晰 docstring,便于模型绑定工具模式
# create_supervisor(...).compile() 得到可 stream/invoke 的图;主管 prompt 不只是提示词,更是在约束整个调度流程与角色边界
#
import os
import re
from langchain.agents import create_agent
from langchain_openai import ChatOpenAI
from langgraph_supervisor import create_supervisor
from dotenv import load_dotenv
load_dotenv(encoding="utf-8")
# 1. 初始化大语言模型
def init_llm_model() -> ChatOpenAI:
return ChatOpenAI(
model="qwen-plus",
api_key=os.getenv("aliQwen-api"),
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
temperature=0.1,
max_tokens=1024,
)
# 2. Tools(必须有 docstring)
def book_flight(from_airport: str, to_airport: str) -> str:
"""预订航班工具。根据出发机场和到达机场预订一张机票,并返回预订结果。"""
return f"✅ 成功预订了从 {from_airport} 到 {to_airport} 的航班"
def book_hotel(hotel_name: str) -> str:
"""预订酒店工具。根据酒店名称完成酒店预订,并返回预订结果。"""
return f"✅ 成功预订了 {hotel_name} 的住宿"
# 3. 子 Agent
flight_assistant = create_agent(
model=init_llm_model(), tools=[book_flight], name="flight_assistant"
)
hotel_assistant = create_agent(
model=init_llm_model(), tools=[book_hotel], name="hotel_assistant"
)
# 4. 创建 Supervisor,协调者主管
supervisor = create_supervisor(
agents=[flight_assistant, hotel_assistant],
model=init_llm_model(),
prompt=(
"你是旅行预订系统的调度主管,负责协调航班预订和酒店预订。\n\n"
"当用户提出航班和酒店预订请求时,你的工作流程是:\n"
"1. 首先调用flight_assistant来预订航班\n"
"2. 然后调用hotel_assistant来预订酒店\n"
"3. 收到两个助手的结果后,汇总并向用户报告\n"
"4. 完成后结束对话\n\n"
"重要规则:\n"
"- 每个助手只能调用一次\n"
"- 不要重复任何内容\n"
"- 不要输出任何英文\n"
"- 所有通信都使用中文\n"
),
).compile()
# 5. 消息过滤器:只服务于教学演示,帮助更清楚地观察主管和子 Agent 的有效中文输出
def filter_messages(chunk: dict) -> str:
"""提取并过滤消息,只返回中文内容,去除重复和英文"""
output = ""
if isinstance(chunk, dict):
for role, payload in chunk.items():
if isinstance(payload, dict) and "messages" in payload:
for msg in payload["messages"]:
if hasattr(msg, "content") and msg.content:
content = msg.content.strip()
# 过滤英文系统消息
if (
content
and not content.startswith("Successfully")
and not content.startswith("Transferring")
and "Successfully transferred" not in content
and "transferred back to" not in content
and not content.startswith("帮我预订从")
):
# 只保留中文内容
chinese_content = re.sub(
r'[^\u4e00-\u9fff,。!?:;""、\s\d✅]', "", content
)
if chinese_content and len(chinese_content.strip()) > 5:
output += f"{role}: {chinese_content.strip()}\n"
return output
# 6. 主程序
def main():
print("=" * 60)
print(
"智能旅行预订系统,由于大模型每次调用,可能出现预定不成功情况,这是正常反馈,主要是2026.2.8千问赠送奶茶活动,调用失败"
)
print("=" * 60)
print()
# 收集用户信息
print("请按顺序提供以下信息:")
print("-" * 40)
# 1. 询问出发机场
from_airport = input("1. 您的出发机场是哪里?: ").strip()
while not from_airport:
print("请输入有效的出发机场名称")
from_airport = input("1. 您的出发机场是哪里?: ").strip()
# 2. 询问到达机场
to_airport = input("\n2. 您的到达机场是哪里?: ").strip()
while not to_airport:
print("请输入有效的到达机场名称")
to_airport = input("2. 您的到达机场是哪里?: ").strip()
# 3. 询问酒店名称
hotel_name = input("\n3. 您要预订的酒店名称是什么?: ").strip()
while not hotel_name:
print("请输入有效的酒店名称")
hotel_name = input("3. 您要预订的酒店名称是什么?: ").strip()
# 构造更明确的用户请求
user_request = (
f"请帮我预订以下旅行安排:\n"
f"1. 航班:从 {from_airport} 飞往 {to_airport}\n"
f"2. 酒店:{hotel_name}\n"
f"请完成这两个预订。"
)
print("\n" + "=" * 60)
print("正在处理您的预订请求...")
print("=" * 60)
print()
# 准备输入数据:Supervisor 图和普通 Agent 一样,入口仍然是 messages
input_data = {"messages": [{"role": "user", "content": user_request}]}
# 使用流式处理,便于观察主管如何依次调度两个子 Agent
try:
# 记录已打印内容,避免在演示时重复刷屏
seen_contents = set()
for chunk in supervisor.stream(input_data):
filtered_output = filter_messages(chunk)
if filtered_output:
lines = filtered_output.strip().split("\n")
for line in lines:
if line and line not in seen_contents:
print(line)
seen_contents.add(line)
# 如果流式输出过少,就给一个兜底总结,避免读者误以为程序没有完成
if len(seen_contents) < 2:
print("\n" + "=" * 60)
print("预订已完成!")
print(f"航班:从 {from_airport} 到 {to_airport}")
print(f"酒店:{hotel_name}")
print("=" * 60)
except Exception as e:
print(f"\n处理过程中出现错误: {e}")
# 教学兜底:即使多智能体流程异常,也能直接调用工具帮助理解业务目标
print("\n正在直接执行预订...")
flight_result = book_flight(from_airport, to_airport)
hotel_result = book_hotel(hotel_name)
print(flight_result)
print(hotel_result)
print("\n感谢使用智能旅行预订系统!")
# 7. 运行主程序
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
print("\n\n程序被用户中断。")
except Exception as e:
print(f"\n系统出现错误: {e}")
Handoff定义
Supervisor 更像“主管一直在调度别人”,Handoff 更像“当前角色把控制权正式交给下一个角色”。也就是说:Supervisor 的重心是“中心调度”;Handoff 的重心是“控制权转移”。
使用场景:
- 会话中角色真正切换
- 下一位 Agent 需要接着当前上下文继续和用户互动
- 不只是内部调用工具,而是“换一个会说话的角色接手”
例如:
- 先由总客服接待,再把问题交给技术支持
- 先由通用顾问判断,再交给航班专家
- 先由一个 Agent 完成分析,再把控制权交给执行型 Agent
案例:
这个案例非常值得保留,因为它展示的是:
- 不只是“主管调用子 Agent”
- 而是如何显式构造交接
- 如何把状态和任务说明一起转给下一个 Agent
# 用 Command + Send 把控制权与消息状态交给指定 Agent;create_task_description_handoff_tool 生成「移交」工具,子 Agent 可互相转接
# Handoff 与“把子 Agent 当工具调”不同:这里显式构造下一跳输入 state,并用 Command(goto=[Send(...)], graph=Command.PARENT) 跳转到兄弟节点
# InjectedState 把当前 MessagesState 注入工具,便于携带对话历史;task_description 充当“交给下一位的工单说明”,这正是 Handoff 里最值得关注的上下文工程
# flight_assistant / hotel_assistant 由 create_agent 构建并作为节点加入同一 StateGraph,START 指向默认入口 Agent;这说明 Agent 完全可以作为 LangGraph 图中的节点来组织
#
import os
from typing import Annotated
from langchain.agents import create_agent
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
from langchain_core.tools import tool
from langgraph.graph import StateGraph, START
from langgraph.graph.message import MessagesState
from langgraph.prebuilt.tool_node import InjectedState
from langgraph.types import Command, Send
from dotenv import load_dotenv
load_dotenv(encoding="utf-8")
# ===============================
# 1. 初始化大语言模型
# ===============================
def init_llm_model() -> ChatOpenAI:
return ChatOpenAI(
model="qwen-plus",
api_key=os.getenv("aliQwen-api"),
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
temperature=0.1,
max_tokens=1024,
)
model = init_llm_model()
# 2. 通用 Handoff 工具工厂
def create_task_description_handoff_tool(
*, agent_name: str, description: str | None = None
):
name = f"transfer_to_{agent_name}"
description = description or f"移交给 {agent_name}"
@tool(name, description=description)
def handoff_tool(
task_description: Annotated[
str, "描述下一个 Agent 应该做什么,包括所有必要信息"
],
state: Annotated[MessagesState, InjectedState],
) -> Command:
task_description_message = {
"role": "user",
"content": task_description,
}
agent_input = {
**state,
"messages": [task_description_message],
}
return Command(
goto=[Send(agent_name, agent_input)],
graph=Command.PARENT,
)
return handoff_tool
# 3. 业务工具(必须有 docstring)
# ===============================
@tool("book_flight")
def book_flight(from_airport: str, to_airport: str) -> str:
"""预订航班,根据出发地和目的地完成机票预订"""
print(f"✅ 成功预订了从 {from_airport} 到 {to_airport} 的航班")
return f"成功预订了从 {from_airport} 到 {to_airport} 的航班。"
@tool("book_hotel")
def book_hotel(hotel_name: str) -> str:
"""预订酒店,根据酒店名称完成预订"""
print(f"✅ 成功预订了 {hotel_name} 的住宿")
return f"成功预订了 {hotel_name} 的住宿。"
# 4. Handoff 工具
# ===============================
transfer_to_flight_assistant = create_task_description_handoff_tool(
agent_name="flight_assistant",
description="将任务移交给航班预订助手",
)
transfer_to_hotel_assistant = create_task_description_handoff_tool(
agent_name="hotel_assistant",
description="将任务移交给酒店预订助手",
)
# ===============================
# 5. 定义 Agent(create_agent 新接口)
# 这里不额外写长 prompt,而是更多依赖:
# 1. 工具 schema / 名称 / docstring
# 2. Handoff 工具本身描述的交接语义
# 3. MessagesState 中持续携带的历史消息
# ===============================
flight_assistant = create_agent(
model=model,
tools=[book_flight, transfer_to_hotel_assistant], # 包含移交工具
name="flight_assistant",
)
hotel_assistant = create_agent(
model=model,
tools=[book_hotel, transfer_to_flight_assistant], # 包含移交工具
name="hotel_assistant",
)
# ===============================
# 6. 构建多 Agent Graph
# ===============================
multi_agent_graph = (
StateGraph(MessagesState)
.add_node(flight_assistant)
.add_node(hotel_assistant)
.add_edge(START, "flight_assistant")
.compile()
)
# ===============================
# 7. 运行
# ===============================
if __name__ == "__main__":
result = multi_agent_graph.invoke(
{
"messages": [
HumanMessage(content="帮我预订从北京到上海的航班,并预订如家酒店")
]
}
)
print("\n====== 最终对话结果 ======")
for msg in result["messages"]:
if msg.type in ("human", "ai"):
print(msg.content)
Skills
Skill 是可复用能力包,通常包含提示词、流程、模板、脚本和参考资料。它回答的是:
遇到这类任务时,应该按什么方法做?
Agent 回答的是:
当前任务该怎么拆、先做什么、调用什么工具、什么时候交给谁?
什么时候需要多智能体
| 判断问题 | 更可能的选择 | 原因 |
|---|---|---|
| 只是复用一套流程、模板或检查清单 | Skill | 能力复用即可,不需要独立角色 |
| 同一个 Agent 的提示词太长 | Skill | 用按需加载减少主上下文压力 |
| 工具很多但任务角色仍然单一 | Skill + 工具治理 | 先整理能力和工具选择边界 |
| 已经有检索、分析、执行、审核分工 | 多智能体 | 角色职责不同,需要独立上下文 |
| 不同角色需要不同工具权限 | 多智能体 | 权限隔离比提示词复用更重要 |
| 需要显式交接控制权 | Handoff | 当前对话状态要由另一个 Agent 接手 |
| 需要中心化调度多个专家 | Supervisor | 主控 Agent 需要分发任务并汇总结果 |
可以把三者关系记成一句话:
Supervisor 负责调度,Handoff 负责交接,Skills 负责沉淀可复用能力。

浙公网安备 33010602011771号