第 16 章 多智能体 Multi-Agent
本章要解决的问题
一个 Agent 搞不定复杂任务——多个 Agent 分工协作,怎么避免它们互相抢上下文、任务冲突?
章节大纲
- 16.1 主从/对等/流水线拓扑
- 16.2 Sub-Agent 与角色分工
- 16.3 智能体间通信与任务编排
- 16.4 主流框架对照(LangGraph/AutoGen/CrewAI)
- 🛠 解决方案:上下文串扰与任务冲突解决
16.1 模式原理:多人协作 vs 一个人硬扛
16.1.1 一句话定义
多智能体(Multi-Agent)是让多个各司其职的 Agent 协作完成一个任务——每个 Agent 有自己的角色、目标、工具和上下文,通过编排器或互相通信协同工作。
先泼冷水:多智能体是被滥用最严重的模式。 市场上很多"多 Agent 系统"其实是把本可以用一个 Agent + 工具做好的事,强行拆成 5 个 Agent,结果上下文互相污染、调试地狱、成本爆炸。先用单 Agent 解决问题,单 Agent 明确搞不定时再上多智能体。
16.1.2 什么时候真的需要多智能体
三个"信号",至少满足一个再考虑:
| 信号 | 说明 | 例子 |
|---|---|---|
| 专业隔离 | 不同子任务需要不同的提示词/工具/模型,混在一起互相干扰 | 研究者(查资料)与写手(写报告)角色冲突 |
| 上下文隔离 | 各子任务的上下文太大,塞进一个 Agent 会溢出/互相污染 | 每个产品线的数据都很大,分 Agent 处理 |
| 并行收益 | 子任务可并行执行(呼应第 12 章) | 多维度独立分析 |
如果三个信号都不满足,你需要的可能是提示链(第 10 章)+ 路由(第 11 章),而不是多智能体。多智能体是最后的手段,不是默认选项。 判断标准:当子任务需要不同的工具权限、不同的上下文、不同的模型、不同角色提示词或可并行执行时,才适合多智能体。
16.1.3 三种拓扑结构
多智能体怎么组织,决定系统的复杂度与协作方式:
图 1:多智能体三拓扑
| 拓扑 | 结构 | 特点 | 适用 |
|---|---|---|---|
| 主从式(Supervisor) | 1 个主管 + N 个 worker,主管分配任务、汇总结果 | 职责清晰、可控、易调试 | 大多数业务场景(最推荐) |
| 对等式(Peer-to-peer) | 无主管,Agent 互相通信、自主协商 | 灵活但难控制、易发散 | 探索型、研究型任务 |
| 流水线式(Pipeline) | 链式传递,前一个 Agent 输出给下一个 | 简单、适合顺序处理 | 固定流程(提示链的多 Agent 版) |
工程结论:默认主从式。 主管(Supervisor)像项目经理:接任务 → 拆解 → 派给 worker → 汇总质检。对等式的"自由协商"在真实业务里 90% 的情况都会演变成失控聊天。
16.2 Sub-Agent 与角色分工
16.2.1 主管-工人模式(Supervisor-Worker)的实现
import json
from openai import OpenAI
client = OpenAI(base_url="https://api.deepseek.com", api_key="<你的Key>")
# ── 角色定义(每个 worker 一个角色 + 专属工具/提示词)──
WORKERS = {
"researcher": {
"role": "行业研究员:负责检索、阅读资料,输出事实与数据摘要",
"tools": ["search", "web_fetch"],
},
"analyst": {
"role": "数据分析师:负责财务/经营数据分析,输出指标与趋势判断",
"tools": ["calculator", "database_query"],
},
"writer": {
"role": "撰稿人:基于前两者产出,撰写结构化报告,语言精炼",
"tools": [],
},
}
def supervisor(goal):
"""主管:拆解任务 → 按序派给 worker → 汇总"""
plan = client.chat.completions.create(
model="deepseek-chat",
messages=[{"role": "user", "content": f"""你是项目主管。把目标拆成任务序列,每个任务指定一个 worker。
可选 worker:{list(WORKERS.keys())}
只输出 JSON:{{"tasks": [{{"worker": "researcher", "instruction": "做什么"}}]}}
目标:{goal}"""}],
temperature=0.2, response_format={"type": "json_object"},
).choices[0].message.content
try:
tasks = json.loads(plan)["tasks"]
except (json.JSONDecodeError, KeyError):
return "任务拆解失败,请人工介入"
results = {}
for t in tasks:
worker = WORKERS[t["worker"]]
out = client.chat.completions.create(
model="deepseek-chat",
messages=[{"role": "system", "content": worker["role"]},
{"role": "user", "content":
t["instruction"] + "\n已有上下文:" + json.dumps(results, ensure_ascii=False)}],
temperature=0.3,
).choices[0].message.content
results[t["worker"]] = out
# 主管汇总质检
final = client.chat.completions.create(
model="deepseek-chat",
messages=[{"role": "user", "content":
f"汇总以下各 worker 产出为最终报告:\n{json.dumps(results, ensure_ascii=False)}"}],
temperature=0.4,
).choices[0].message.content
return final
图 2:Supervisor-Worker
16.2.2 角色设计的四个原则
- 角色职责单一:一个 worker 只做一类事("研究者"别同时负责"写作"),否则回到单 Agent 的老问题。
- 角色要有工具边界:writer 不该有数据库权限(呼应第 22 章最小权限),工具按角色配置。注意:工具隔离需要在外层编排器中真正实现(只传给 worker 它的工具列表对应的 tools 参数),而不是只在 role 文本中声明。
- 角色提示词要"有性格":角色的 system prompt 写清职责、输出格式、与其他角色的协作关系。
- 上下文按角色隔离:worker 只拿到自己需要的上下文(见 16.3.2 上下文隔离),别把全量上下文塞给每个 worker。
16.2.3 Sub-Agent:作为工具的子智能体
一种轻量多智能体形态:把子 Agent 当"工具"调用(呼应第 14 章工具增强)。主管 Agent 遇到复杂子任务时,不是自己硬做,而是 spawn 一个临时 Sub-Agent 去执行,拿回结果。好处:子 Agent 有独立上下文、独立停止条件,用完即弃,不污染主管上下文。
def spawn_subagent(instruction, context):
"""临时子 Agent:独立上下文执行,返回结果"""
return client.chat.completions.create(
model="deepseek-chat",
messages=[{"role": "system", "content":
"你是临时子任务执行者,完成后只返回最终结果。"},
{"role": "user", "content": instruction + "\n参考:" + context}],
temperature=0.3,
).choices[0].message.content
16.3 智能体间通信与任务编排
16.3.1 两种通信模式
| 模式 | 机制 | 优点 | 缺点 |
|---|---|---|---|
| 结构化传递(推荐) | worker 之间只传结构化结果(JSON),不传原始聊天记录 | 上下文干净、可审计、易调试 | 需要设计数据契约 |
| 自由对话(群聊) | Agent 们像群聊一样互发消息(AutoGen group chat 风格) | 灵活、能协商 | 上下文爆炸、难控制、发散 |
图 3:两种通信模式
工程结论:默认结构化传递,慎用自由对话。 自由对话适合研究性讨论(比如让两个 Agent 辩论找漏洞),不适合生产流程。
通信成本提醒:多 Agent 的通信次数会增加 token 成本。例如 supervisor 拆解 + worker 执行 + 主管汇总,至少 3 轮调用;如果加质检则更多。多 Agent 成本 = 主管 + worker + 质检 + 汇总,必须与单 Agent 长链路对比后决定是否值得。
16.3.2 上下文隔离:多 Agent 的第一原则
多 Agent 系统 80% 的问题来自上下文串扰——A 的上下文混进了 B 的信息。隔离的三层手段:
图 4:上下文隔离三手段
- 输入隔离:每个 worker 只收到任务所需的数据(主管按需投喂,不广播)。
- 输出隔离:worker 之间不互相看原始对话,只交换最终结构化结果。
- 状态隔离:共享状态(数据库、缓存)按 worker 分区,避免写冲突。
# 反例:把全量上下文广播给所有 worker → 上下文串扰
for w in workers:
w.run(full_context) # ❌ 每个 worker 都被无关信息污染
# 正例:按需投喂
for w, needed in assignment.items():
w.run(extract(needed, full_context)) # ✅ 只给需要的部分
16.3.3 任务编排:主管的三个决策
主管编排任务时的关键决策:
- 串行还是并行:任务间有依赖串行,无依赖并行(呼应第 12 章)——主管应利用
depends_on信息并行派活。 - 失败怎么处理:worker 失败 → 重试该 worker → 换 worker → 降级跳过(呼应第 13、23 章)——编排器要有失败处理策略,不能一错全崩。
- 结果怎么校验:主管对 worker 产出做质检(呼应第 13 章反思、第 17 章评估),不过关打回重做,而不是直接采纳。
16.4 主流框架对照
| 框架 | 特点 | 适用 | 注意 |
|---|---|---|---|
| LangGraph | 图结构 + 状态管理,支持条件边/循环,最贴近"编排"概念 | 复杂编排、生产级 | 学习曲线较陡 |
| AutoGen | 群聊式多 Agent 对话(ConversableAgent),微软研究院开源(Chi Wang 等) | 研究、辩论、协商类 | 自由对话易失控,需强约束 |
| CrewAI | 角色/任务/工具声明式定义,上手快 | 快速原型、中等复杂度 | 封装程度高,定制复杂拓扑时不如 LangGraph 或自研可控 |
| 自研(本章主线) | 主管-工人 + 结构化传递,完全可控 | 教学、定制化 | 复杂拓扑要自己写编排 |
选型建议:教学与深度控制选自研/ LangGraph;快速原型选 CrewAI;研究型多 Agent 讨论选 AutoGen。无论哪个框架,上下文隔离和失败处理都要自己设计好——框架解决不了这两个问题。
🛠 解决方案:上下文串扰与任务冲突解决
常见问题
- "多个 Agent 抢同一个状态,结果互相覆盖":共享状态未隔离。对策:状态按 worker 分区(16.3.2),写操作加锁/版本号。
- "上下文串扰,worker 用错了数据":广播式投喂。对策:按需投喂 + 结构化传递(16.3.1/16.3.2)。
- "自由对话停不下来,成本爆炸":群聊无停止条件。对策:对话轮数上限 + 目标达成判定(呼应第 13 章停止条件);生产场景改结构化传递。
- "主管派活不合理,任务互相矛盾":主管提示词约束不足。对策:主管 system prompt 写明任务依赖规则;任务加
depends_on;必要时"规划 + 反思"双模型审计划(呼应第 15 章)。 - "一个 worker 挂了,整个系统崩":无失败隔离。对策:worker 级 try-catch + 降级策略(16.3.3),单 worker 失败不影响其他 worker 的结果。
解决方案速查表
| 现象 | 根因 | 解决方案 |
|---|---|---|
| 状态互相覆盖 | 未隔离 | 状态分区 + 锁 |
| 用错数据 | 广播投喂 | 按需投喂 + 结构化传递 |
| 对话失控 | 无停止条件 | 轮数上限 + 目标判定 |
| 任务矛盾 | 编排无约束 | 依赖规则 + 审计划 |
| 一错全崩 | 无失败隔离 | worker 级降级 |
实战提示
- 默认主从式,主管-工人是生产环境最稳的形态;对等/自由对话留给研究场景。
- 先证明单 Agent 不行,再上多智能体——多智能体是手段,不是目的。
- 上下文隔离是第一原则:按需投喂 + 结构化传递,能避免 80% 的诡异 bug。
- 每个 worker 都要有停止条件,编排器要有失败处理,否则就是无限烧钱。
- 可观测性加倍重要:多 Agent 系统比单 Agent 难调试 10 倍,trace 必须到"每个 worker 的每次调用"(呼应第 21 章)。
- 框架选型参考:本章框架对比仅作概览,详细参数和用法见附录 A《主流框架速查》。