首页/Agent 核心/多 Agent 与选型策略
Agent 核心 · 第 12 章

多 Agent 与选型策略

上一章看完了 MCP 的全景,工具箱里已经有了本地工具、Skill、MCP 三类能力。能力多了,新问题随之而来:怎么组织它们?本章分两层回答:前半是工具层的组织——Skill(第 10 章)和 MCP(第 11 章)经常…

约 18 分钟7,399 字11 个代码示例

上一章看完了 MCP 的全景,工具箱里已经有了本地工具、Skill、MCP 三类能力。能力多了,新问题随之而来:怎么组织它们?本章分两层回答:前半是工具层的组织——Skill(第 10 章)和 MCP(第 11 章)经常被放在一起比较,但它们其实不在同一个维度上竞争,一个是"知识怎么进上下文",一个是"工具怎么跨进程",这一半给出清晰的分工边界和组合原则;后半是执行层的组织——当任务大到单个 Agent 吃不消,用子代理分而治之。这是第四章「怎么扩展它」的收官一章:扩展的终点不是把能力堆多,而是把能力组织好。

1. 先说结论:一句话分工

一句话分工:

Skill 分发的是"知道怎么做"(文档),MCP 分发的是"能动手做"(服务)。

它们解决的是两个不相交的问题:

Skill MCP
分发物 文档(怎么做事的方法论) 工具(可执行的能力)
进入系统的方式 作为文本注入上下文 作为进程/服务被连接
消耗的资源 使用时的 token(正文进入窗口) 连接的进程 + schema 常驻 token
生效机制 改变模型的行事方式(统计约束) 提供模型原本没有的动作
失败模式 模型没遵循文档 连接断、调用超时、结果异常
类比 给新人的操作手册 外包公司的服务接口

回想第 10 章的结论——"工具给模型手,技能给模型方法论"——这就是两个机制的本质差异,选型的一切讨论都从这个差异出发。

2. 同一个需求的两条实现路径

拿一个具体需求做思想实验:"让 Agent 能做前端设计"。

路径 A(Skill):写一份设计规范文档,模型读了照做。

优点:零基础设施;改文档立即生效;灵活(模型可酌情变通)
缺点:遵守是概率性的;效果依赖模型能力;无法保证一致性

路径 B(MCP):做一个 design_server,暴露 render_component、check_contrast 等工具。

优点:确定性执行(对比度检查就是真的跑代码);不依赖模型悟性
缺点:开发成本高;只能覆盖可形式化的部分("美感"没法做工具)

观察关键差异:这个需求里,有些子能力适合 Skill(设计理念),有些适合 MCP(对比度校验)。真实答案通常是组合:

Skill(设计规范文档)
  └── 其中一条规定:"每次交付前必须调用 check_contrast 工具(MCP)验证"

方法论指导工具的使用——这是最常见的生产形态。

3. 选型决策表

按需求特征逐条对照:

需求特征 推荐 理由
领域知识/规范/流程(评审标准、写作风格) Skill 本质是"给模型看的话"
访问外部系统(数据库、API、第三方服务) MCP 需要真实执行,文档给不了
团队共享的 SOP Skill 文档版本管理即可,无需部署
严格确定性要求(合规校验、精确计算) MCP 第 6、7 章原则:硬约束靠代码
高频小动作(读文件、查时间) MCP 常驻 schema 成本低,调用可靠
低频大手册(特定行业的完整规范) Skill 渐进式披露省窗口(第 10 章的核心价值)
需要给全生态复用(任何 Agent 都能用) MCP 协议即生态,一次实现处处接入
快速迭代试错 Skill 改 markdown 就行

两条经验法则:

  1. 拿不准先写 Skill:成本是几行 markdown,验证想法后再决定要不要硬化成工具
  2. 组合优于二选一:问"这个能力怎么拆"而不是"这个能力归谁"

4. 三个维度看清差异

决策表之外,更立体的对比可以从三个维度展开:

维度一:信任模型还是信任代码。Skill 把正确性交给模型的"理解力";MCP 把正确性交给代码的确定性。你的场景容错高(创意写作)倾向前者,容错低(支付、合规)倾向后者——这呼应第 8 章"能力来自模型,可靠性来自工程"的总纲。

维度二:变更成本。Skill 的迭代是改文档(秒级、无风险);MCP 的迭代是改服务、发版本、管兼容(小时级、有协调成本)。探索期用 Skill 固化认知,稳定期把验证过的流程下沉为工具——Skill 是 MCP 的孵化器。

维度三:分发半径。Skill 天然是"给自己人用的"(团队内共享文档);MCP 的协议属性让它适合"给全世界用"(发布到生态)。开源一个 Skill 只是分享一个 markdown;开源一个 MCP server 是贡献一个服务组件——后者才有生态位的概念。

5. 组合架构的三条原则

真实系统里两者共存,按这三条原则组织:

原则一:按层分工。MCP 工具是"动词层"(能做什么),Skill 是"副词层"(怎么做更好):

Skill: 代码评审规范
  ├─ 第1步 用 list_changes 工具(MCP)看变更
  ├─ 第2步 逐文件用 read_file(MCP)细读
  ├─ 第3步 按本文档第3节的检查清单人工评估
  └─ 第4步 用 format_report 工具(MCP)产出报告

Skill 编排 MCP 工具——这不就是第 8 章 ReAct 的文档化:把验证过的行动序列固化成方法论,模型照着走减少试错。

原则二:索引归索引。第 10 章的渐进式披露和第 7 章的工具控制可以叠加:skill 索引一行常驻,工具 schema 按职责装配。两者对窗口的占用要统一预算(第 13 章 Context Engineering 的账本里,这两项都记在"系统级常驻"科目下)。

原则三:升级路径单向。Skill 验证成熟 → 硬化为工具(MCP)。反方向(把工具拆回文档)通常意味着维护两份逻辑,是坏味道。例外是工具的"使用说明"(什么时候调、参数怎么选的领域知识)——那本来就是 Skill 的地盘。

6. 一个完整的例子:企业知识库助手

"企业知识库助手"的完整选型,综合运用全部原则:

能力 机制 理由
检索知识库 MCP(search_kb 工具) 访问外部系统,必须真实执行
回答格式规范 Skill(企业公文写作手册) 文档型知识,渐进披露
数据脱敏规则 MCP(sanitize 工具)+ Skill(规则说明) 硬约束靠代码,例外情况靠文档补充
新员工 FAQ Skill 低频、纯知识
权限边界 系统提示词 + MCP 工具的权限层 第 15 章主题,此处不展开

注意"数据脱敏"那行——同一个能力可以同时需要两种机制:规则本体文档化(Skill 教模型识别敏感场景),执行靠工具(MCP 保证真的被处理了)。这是"组合优于二选一"的最典型形态。

7. 为什么需要子代理:三堵墙

前六节讲的都是工具层的组织——一个能力该交给文档(Skill)还是服务(MCP)。工具生态至此讲完了(本地工具、Skill、MCP),还剩最后一块拼图:当任务大到单个 Agent 吃不消,需要分身——子代理(Sub-agent)。

单个 Agent 有两个硬上限:上下文窗口装不下无限信息,串行循环跑不快复杂任务。子代理用"分而治之"同时突破这两个——主代理拆任务,子代理各自带着干净的上下文去执行,只把结果交回来。

具体来说,第 8 章的 Agent 跑长任务时会撞上三堵墙:

墙一:上下文污染。任务越长,messages 里堆的历史越多——中间步骤的工具结果(多半已经没用了)持续占用预算(第 6 章的裁剪只能缓解,因为"哪些还有用"很难判断)。到后期模型注意力被稀释,质量肉眼可见地下降(第 4 章的窗口预算问题在长任务上的总爆发)。

墙二:串行低速。主循环一步接一步,即使两个子任务毫无依赖(查两个城市天气、读十个文件)也只能排队。

墙三:职责混杂。一个 Agent 又写代码又查资料又排版,系统提示词塞满互相打架的指令——第 5 章说过,指令越多越容易被稀释。

子代理的解法,对三堵墙各有一剂药:

主代理(orchestrator)
  ├─ 拆解任务:"调研A、调研B、汇总"        ← 职责上移到规划层
  ├─ spawn 子代理1(干净上下文,只做A)      ← 墙一:每个子代理窗口都是新的
  ├─ spawn 子代理2(干净上下文,只做B)      ← 墙二:可并行
  └─ 收集结果,汇总输出                     ← 墙三:每个子代理提示词专一

关键洞察:子代理和第 8 章的 Agent 是同一个东西。区别只在调用方式——人调用的叫 Agent,Agent 调用的叫子代理。就像函数调用函数没有新语义,只是栈深了一层。

8. 心智模型:子代理是一种"高级工具"

从第 7 章的视角看:子代理就是一个返回字符串的大工具——输入是任务描述(prompt),输出是执行结果(text)。对主代理而言:

工具调用: calculate("(12+8)*3")        → "60"
子代理调用: run_sub_agent("调研XX")     → "调研结果:..."

接口完全同构!所以实现上可以把子代理包装成第 7 章的 Tool 注册进 Registry——主代理不需要知道"这个工具背后是函数还是一整个 Agent"。这个视角让架构保持干净:分而治之不需要发明新机制,复用现有的一切(这也是第 11 章"分层"哲学的延续)。

和普通工具的差异在两点(都源于它是"活的"):

  1. 执行时长:子代理内部要跑若干轮循环,秒到分钟级
  2. 内部状态:子代理有自己的 messages、自己的工具集、自己的系统提示词

9. 实现:三层结构

9.1 子代理工厂

子代理就是第 8 章的 Agent,但加两个配置:专用工具集、精简的轮次预算:

from dataclasses import dataclass

@dataclass
class SubAgentSpec:
    """子代理的岗位说明书"""
    name: str
    system: str                       # 专一职责的系统提示词
    tools: list                       # 只装配职责内的工具(第 7 章:工具是负债)
    max_rounds: int = 4               # 小任务不需要大预算

9.2 把子代理包装成工具

from pydantic import BaseModel, Field

class RunSubAgentArgs(BaseModel):
    task: str = Field(description="要子代理完成的任务描述,要具体、自包含、"
                     "包含所有必要背景信息")

def make_subagent_tool(spec: SubAgentSpec, registry_factory):
    """把一个子代理岗位包装成主代理可调用的工具"""

    def run_sub_agent(task: str) -> str:
        # 每次调用创建全新实例 → 干净上下文(墙一的解药)
        sub_registry = registry_factory(spec)
        sub_agent = Agent(
            system=spec.system,
            registry=sub_registry,
            max_rounds=spec.max_rounds,
        )
        # 事件可以转发到主代理的监听器(级联观测)
        return sub_agent.run(task)

    return Tool(
        run_sub_agent, RunSubAgentArgs,
        description=f"委派「{spec.name}」子代理执行任务。"
                    f"适用:{spec.system[:60]}。任务描述必须自包含。",
    )

两个设计决策:

  • 每次 spawn 新实例:不复用,保证上下文绝对干净——脏上下文是本章第 7 节墙一的病根,复用等于带病上岗
  • description 强调"任务必须自包含":子代理看不到主代理的任何历史,任务描述里缺背景就会瞎做。这是子代理系统的第一大翻车点,值得在说明书里反复强调

9.3 主代理组装

# 主代理自己的工具(汇总用的基础能力)
main_registry = Registry()
main_registry.register(Tool(calculate, CalculateArgs, "..."))

# 注册子代理岗位
researcher = SubAgentSpec(
    name="调研员",
    system="你是一个网络调研助手。用搜索工具查证事实,"
           "返回结构化调研结果(要点+来源)。",
    tools=[web_search, read_webpage],
)
main_registry.register(make_subagent_tool(researcher, build_research_registry))

agent = Agent(
    system="你是项目经理,负责拆解任务、委派子代理、汇总结果。"
           "委派时给子代理的任务必须包含全部背景信息。",
    registry=main_registry,
    max_rounds=6,
)
print(agent.run("调研一下 Rust 和 Go 在 Web 后端的生态对比"))

运行轨迹(示意):

主代理:  ⚙ run_sub_agent({"task": "调研 Rust 的 Web 后端生态:框架、"
          "成熟度、大厂案例,返回要点和来源"})
        ↳ (子代理内部 3 轮:搜索→阅读→整理,主代理视角只看到结果)
        ⚙ run_sub_agent({"task": "调研 Go 的 Web 后端生态:……"})
        ↳ ……
        ⚙ calculate(...)
        ✔ 汇总输出对比报告

注意主代理的 messages 里只有子代理的最终结果(几百 token),而不是子代理内部的完整轮转(可能上万 token)——上下文隔离的直接收益。

10. 并行执行

子代理是最适合并行的结构:主代理一次 tool_calls 里发出多个 run_sub_agent(第 7 章的并行调用),执行层并发跑:

import concurrent.futures as cf

def dispatch_parallel(self, calls: list[tuple[str, str]]) -> list[str]:
    """并行执行多个(子代理)调用"""
    with cf.ThreadPoolExecutor(max_workers=4) as pool:
        futures = [pool.submit(self.dispatch, name, args) for name, args in calls]
        return [f.result() for f in futures]

第 8 章的 Agent 循环里,把"逐个执行 tool_calls"换成"收集后并行执行",就是完整的并行版本。收益直观:两个各需 30 秒的调研,串行 60 秒、并行约 30 秒。

注意边界:只有无依赖的调用才能并行。如果后一个调用需要前一个的结果(先查 ID 再查详情),模型通常会自己分开两轮请求——并行与否其实由模型在每一轮内怎么打包调用决定,执行层只需要提供并行能力。

11. 工程要点

① 结果契约。子代理返回自由文本,主代理要再消费它——所以子代理的系统提示词里应规定输出结构("返回:结论/要点/来源 三段")。本质是第 6 章结构化输出在代理间的应用:代理间通信也该有 schema。

② 预算控制。子代理是 token 黑洞:每个 spawn 都是完整的 LLM 会话。主代理 max_rounds × 子代理 max_rounds 是最坏情况的乘法关系。工程上必须给子代理更小的预算(示例里的 4 轮),并计入总账(第 8 章的 token 闸门要扩展成"含子代理的总账")。

③ 观测级联。子代理的事件应向上转发(9.2 的注释),否则调试时主代理显示"调用了子代理,10 分钟后返回",中间一片漆黑——第 15 章可观测性的伏笔:调用树(trace)必须跨代理层级连续。

④ 失败传播。子代理达到轮次上限返回"(未完成)"时,主代理需要决策:重试、换方案还是如实上报。把"子代理失败"设计成可被主代理理解的结果(而不是异常),失败处理就成了模型的自然决策而非代码的崩溃路径——第 7 章原则在代理间的延伸。

⑤ 深度限制。子代理可以再生子代理(无限套娃),工程上要限制层数(常见 2 层)。没有限制的深层级联会导致:预算指数爆炸 + 观测困难 + 定位问题如地狱。

12. 何时不用子代理

最后是克制清单——子代理不是银弹:

  • 简单任务:一次 tool call 能解决的事,包装成子代理纯属浪费(多一次 LLM 调用的开销和延迟)
  • 强依赖顺序的流程:步骤间数据强耦合时,拆开反而要在任务描述里搬运大量上下文,得不偿失——这种该用第 14 章的 Graph 结构
  • 对延迟敏感:子代理至少多一跳 LLM 调用。实时场景直接主代理自己做
  • 上下文本来就不脏:短会话硬拆,只会让任务描述变复杂。分而治之的成本在"任务描述必须自包含"

判断口诀:上下文脏了、可并行了、职责真多了——三者至少占一,才值得拆。

本章小结

  • 一句话分工:Skill 分发"知道怎么做"(文档),MCP 分发"能动手做"(服务)
  • 三个维度:信任模型 vs 信任代码;迭代成本高低;分发半径大小
  • 经验法则:拿不准先写 Skill(它是 MCP 的孵化器);组合优于二选一
  • 三条架构原则:动词层/副词层分工、索引统一预算、升级路径单向(Skill→工具)
  • 同一能力可拆可叠:硬约束给 MCP,领域知识给 Skill
  • 三堵墙(上下文污染、串行低速、职责混杂)各有解药:干净上下文、并行、专一提示词
  • 心智模型:子代理 = 返回字符串的高级工具;主代理不需要知道背后是不是 Agent
  • 三层实现:岗位说明书(Spec)→ 工具包装(每次 spawn 新实例)→ 主代理组装
  • 工程五要点:结果契约、预算乘法控制、观测级联、失败传播、深度限制
  • 克制清单:简单任务、强依赖流程、延迟敏感、短会话都不要拆

至此,Agent 的全部构造技术都齐了:循环(第 8 章)、工具(第 7 章)、技能(第 10 章)、协议(第 11 章)、分身(本章)。第四章「怎么扩展它」到此收官。剩下的问题是工程级的:上下文怎么经营(第 13 章)、流程怎么编排(第 14 章)、怎么稳妥上生产(第 15 章)。最后一部分,我们从上下文开始。

下一篇:13 · 提示词工程与上下文工程