第 8 章

子智能体架构

第 8 章:子智能体架构

当单个智能体不足以应对复杂任务时


想象一下,你的智能体开始了一项重构任务。它需要搜索代码库、制定计划、修改三十个文件并运行测试套件。它试图同时完成这四件事,导致上下文窗口迅速填满。当处理到第 23 个文件时,它已经忘记了最初的计划,开始做出与十个文件前相矛盾的更改。测试失败了,智能体试图修复它们,但它甚至记不起最开始要实现的目标是什么。

这就是把智能体当成无限资源的结果。智能体并不是无限的,每一个智能体都运行在约束之下——上下文限制、注意力衰减以及同时处理多个任务的难度。

这种挑战的应对之道正是经典的“分而治之”(Divide and Conquer)。父级智能体可以生成多个 子智能体(sub-agents) 来分担特定的子任务。

关键在于识别问题的性质,并为每个执行者提供成功所需的精确资源。

为什么要进行委派?

在动用子智能体之前,首先要理解它们存在的必要性。过早的拆分只会增加架构复杂性。但当你遇到以下“瓶颈”时,子智能体就变得至关重要。

首先是 任务规模(Scale) 的限制。诸如“将代码库从 REST 迁移到 GraphQL”这类复杂工程,实际上包含了分析架构、识别依赖、规划顺序、更新端点及编写测试等数十个环节。若由单一智能体独立承担,往往会因上下文过载而在任务中段便陷入“疲劳”。

其次是 专业化能力(Specialization) 的需求。一个具备所有权限的通用智能体虽是“万能钥匙”,但在特定领域往往缺乏极致表现。相比之下,一个专注于“代码审计”的子智能体——拥有只读权限并配置了针对性的提示词,其发现漏洞的准确性远高于一个同时需要修改文件、执行命令和浏览网页的通用智能体。专注的提示词能显著提升智能体的注意力,降低工具选择偏差。

此外还有 并行加速(Parallelism) 的考量。如果你需要分析 50 个文件的安全风险,与其让单个智能体按顺序处理,不如调用 50 个专注的子智能体同时开工,大幅缩短处理耗时。

最后是 隔离与安全性(Containment)。执行任意 Shell 命令或修改敏感配置具有天然风险。通过将危险操作限制在权限受控且环境独立的子智能体中,可以有效缩小潜在的“故障半径”。即便子智能体出错,损害也会被限制在特定的沙箱环境内。

隔离模式

在创建子智能体(Spawn sub-agent)时,首要决策是设定其隔离级别。隔离级不仅关乎技术实现,更体现了任务与父级智能体间的信任程度。若隔离不足,子智能体可能非预期地修改父级状态;若隔离过度,跨进程写作的成本将抵消委派带来的收益。

常见的隔离策略可以看作一个连续的光谱:

共享 ◄────────────────────────────────────────────► 隔离

默认 (Default)   派生 (Fork)    工作区 (Worktree)   远程 (Remote)
(进程内)         (子进程)       (git worktree)     (异地执行)

默认:进程内共享状态

子智能体(In-process Teammate)在同一进程中运行,共享父级文件的内存加载状态及环境变量。其执行极快,几乎没有启动开销,如同调用异步函数。

适用场景: 快速、低风险且需即时共享父级修改的任务。例如:解释复杂函数的局部逻辑,或通过模式匹配在已加载的文件列表中进行检索。

派生:独立会话副本

就像 fork 一个进程——子进程从父进程状态的快照开始,但从那一刻起独立运行。子级拥有全新的消息队列(Message history),避免被过往的杂音干扰。

适用场景: 执行过程较长,或需保持对话记录精简的情况。例如一并开启大规模重构的智能体——若子进程方向跑偏,父级可以随时干净利索地“Kill process”,而不必担心主上下文被污染。

工作区:文件系统隔离

通过 Git Worktree 机制,为子智能体提供一个独立的临时工作目录。子级可以在其中编译代码、执行带副作用的测试,完全不影响主工作目录下的研发进度。

适用场景: 具有破坏性的文件修改任务,或需评估不确定方案的可行性。若子智能体方案可行,父级可通过 Git Cherry-pick 操作合入工作区中的成果;否则,直接销毁工作区。

远程:物理隔离执行

隔离程度最高。子智能体运行在完全隔离的任务容器(如 Remote CCR 环境)中,通过网络(WS/HTTP)进行通信。这是处理不受信任代码或在特定异构硬件上运行指令的终极手段。

同步与异步执行

决定了 在哪里 运行后,接下来需明确父级如何处理返回结果。

同步执行(Synchronous) 模式下,父级智能体在调用子智能体后会阻塞等待(Await),直至任务返回:

父级                       子级
  │                          │
  │──── 调用 (spawn) ───────►│
  │                          │
  │         (阻塞处理中...)   │
  │                          │
  │◄─── 返回结果 (result) ───│
  │                          │
  ▼ (继续逻辑)              

这是最可预测的控制流。适用场景: 任务执行极快,且父级在获取结果前无法进行后续工作的强依赖场景。

异步执行(Asynchronous/Background) 则更为灵活。父级触发子任务后立即返回,处理其他待办。

父级                        子级
  │                          │
  │──── 启动 (spawn) ───────►│
  │                          │
  │ (处理其他任务)           │ (后台执行中)
  │                          │
  │     ◄── 进度回报 ────────│ (Progress Events)
  │                          │
  │ (由于任务复杂可能仍在忙) │
  │                          │
  │     ◄── 完成通知 ────────│ (Events/Polling)
  │                          │
  │──── 获取结果 ───────────►│
  │◄─── 结果数据 ────────────│

通过指定 run_in_background=true,父级可以在执行大规模变更的同时,继续分析其他模块信息。异步模式要求开发者为子任务分配唯一 ID,并能够处理任务乱序归档或部分失败的协调逻辑。

子智能体知道什么?

上下文传递是一个具有权衡的设计决策。

最简单的方法是 全量上下文 —— 将父级的整个对话记录传给子级。信息无损,但消耗 Token 较多。子级可能会被无关的历史记录干扰。对于超长对话,甚至会直接超出上下文限制。

更高效的方法是 总结性上下文 —— 传递压缩后的相关背景以及具体任务。这种方法适用于更长对话的扩展,但总结过程中会丢失细节,子级可能会请求父级已经掌握的信息。

最理想的方法是 任务特定上下文 —— 仅传递子智能体完成特定任务所需的内容:

任务:"审查 auth.py 中的身份验证更改"

传递的上下文:
  - auth.py 的内容(当前版本和差异)
  - 总体目标("迁移到 JWT 身份验证")
  - 具体的审查指令

不传递的上下文:
  - 早期关于数据库 Schema 的讨论
  - 父级在其他尝试中的失败记录
  - 父级查看过的无关文件

任务特定上下文通常是最佳选择。子级在没有噪音的情况下获得所需信息。但这要求父级仔细考虑子级究竟需要什么。

智能体专业化

不同任务的响应需求截然不同。与其构建一个漏洞百出的全能通用智能体,不如根据能力范围划分专门的智能体,通过聚焦来提升精度。

探索型智能体 (Explore agents) 扮演只读分析师的角色。其核心职责是代码导航与检索,工具集通常被限制在 read_filegrep 等非破坏性工具中。鉴于其极低的“爆炸半径”,你可以大量生成此类智能体以并行获取背景信息。

  1. “解释当前函数的业务逻辑”
  2. “检索所有旧版本 API 的调用点”
  3. “绘制该模块的整体架构图”

执行型智能体 (Execute agents) 则是具备实操权限的技术员。它们负责修改代码、执行脚本并达成具体交付目标。执行型智能体具有一定的操作风险,必须在具体的、有明确边界的任务指令(Prompt)下运行。

  1. “重构该函数并适配新的统一调用接口”
  2. “为核心逻辑补全单元测试(Vitest)”
  3. “修复该已知 Bug 并验证修复效果”

规划型智能体 (Plan agents) 是战略指挥官。其核心是不直接入场编码(只读、只分析),专注于推导演进方案,避免“盲目编码(Coding blindly)”。这种结构强制智能体在动工前先进行深思熟虑。

  1. “制定从 MySQL 迁移到 PostgreSQL 的详细分步计划”
  2. “设计重构期间的代码质量保障策略”
  3. “评估现有方案的性能瓶颈并提供改进思路”

验证型智能体 (Verify agents) 是最后一道质量防线。它们对执行结果进行二次确认,拥有执行测试集(Tests)的权限。这种“二把手”式的意见对防范回归错误至关重要。

  1. “审查上述重构是否引入了隐蔽的逻辑漏洞”
  2. “验证代码实现细节是否严格遵循技术规范”
  3. “跨环境确认所有集成测试是否顺利通过”

上述智能体的编排拓扑结构如下图所示:

                    ┌─────────────────┐
                    │  父级智能体      │
                    │  (编排者)        │
                    └────────┬────────┘
                             │
        ┌────────────────────┼────────────────────┐
        │                    │                    │
        ▼                    ▼                    ▼
┌───────────────┐    ┌───────────────┐    ┌───────────────┐
│ 规划型智能体   │───►│ 执行型智能体   │───►│ 验证型智能体   │
│ (制定策略)     │    │ (具体实施)     │    │ (结果检查)     │
└───────────────┘    └───────────────┘    └───────────────┘
        │                    │                    │
        │                    ▼                    │
        │            ┌───────────────┐            │
        └───────────►│ 探索型智能体   │◄───────────┘
                     │ (调查研究)     │
                     └───────────────┘

规划、执行、验证——并由探索支持所有阶段。

结果采集与合入

子智能体的反馈机制是协作链条的关键。

强制应用结构化输出(Structured Output)。 应当要求子智能体返回遵循 JSON Schema 的结构化数据而非大段纯文本。

{
  "status": "success",
  "task": "Security Review: auth.ts",
  "findings": [
    {
      "severity": "high",
      "line": 42,
      "issue": "Raw parameter injection identified",
      "patch": "Using prepared statements"
    }
  ]
}

结构化返回值允许父级智能体通过硬编码逻辑进行判断,避免了对模糊文本解析的依赖。

容错与熔断逻辑。 子任务失败在分布式智能体系统中是常态。健全的父级必须具备异常处理机制:

智能结果聚合。 若同时派生了 10 个安全扫描器,其中 2 个请求超时,父级应基于当前的置信度决定是带伤归纳结论,还是进行局部重试任务。这要求父级具备更高的调度策略而非单纯的命令转发。

任务生命周期管理

子智能体从生成到销毁,需要父级进行精密的周期控制。

┌────────┐    ┌─────────┐    ┌───────────┐    ┌────────────┐
│  生成  │───►│  执行中  │───►│  进度上报  │───►│ 结果投递   │
└────────┘    └─────────┘    │  (可选)   │    └────────────┘
                   │         └───────────┘    
                   │                                
                   ▼                                
             ┌──────────┐                           
             │  取消 / 熔断 │ (强制终止)
             └──────────┘                           

父级必须具备实时感知能力:可以通过 ID 检索子任务的状态、拦截中间进度输出(Partial logic)、或在任务出现幻觉(Hallucinated commands)时强制熔断。

对于异步运行的耗时任务,通常采用如下调度模式:

# 异步派生扫描器
task_id = spawn_agent(
    task="Comprehensive Audit",
    run_in_background=true
)

while True:
    state = fetch_agent_status(task_id)
    
    if state.is_completed():
        return merge_results(state.payload)
    elif state.is_stuck_or_expired():
        force_terminate(task_id)
        return notify_timeout()
        
    # 提供异步回调钩子处理中间进度
    if state.has_progress_updates():
        stream_updates_to_console(state.progress)
    
    sleep(POLLING_INTERVAL)

典型架构模式

Map-Reduce (映射-归约)

将一个庞大的作业(如全库扫描)拆分为 N 个并行的子项,通过 N 个子智能体同时处理,最后在父级进行归纳汇总。这是提升处理通量最有效的范式。

           ┌────────────────────────────────────────────┐
           │               父级智能体                   │
           │                                            │
           │  1. 分治任务 (Split tasks)                │
           │  2. 并行映射 (Map spawn)                  │
           │  3. 最终归约 (Reduce results)             │
           └─────────────────┬──────────────────────────┘
                             │
         ┌───────────────────┼───────────────────┐
         │                   │                   │
         ▼                   ▼                   ▼
    ┌─────────┐         ┌─────────┐         ┌─────────┐
    │ 子级 1  │         │ 子级 2  │   ...   │ 子级 N  │
    └────┬────┘         └────┬────┘         └────┬────┘
         │                   │                   │
         └───────────────────┼───────────────────┘
                             │
                             ▼
                    ┌────────────────┐
                    │     聚合      │
                    └────────────────┘

典型案例:分析大量文件的安全漏洞。每个子级扫描一个文件;父级收集并确定所有发现的可读性优先级。

Pipeline (流水线)

子级 A 的输出作为子级 B 的输入。工作流经各个阶段。

    ┌─────────┐      ┌─────────┐      ┌─────────┐
    │ 阶段 A  │─────►│ 阶段 B  │─────►│ 阶段 C  │
    │ (解析)  │      │ (分析)  │      │ (报告)  │
    └─────────┘      └─────────┘      └─────────┘
         │                │                │
      原始输入         结构化数据        最终报告

当工作具有天然的转换阶段时使用。代码审查流水线可以先解析更改,分析问题,最后生成格式化报告。

Supervisor (监督者)

父级监控子级,重启失败任务,确保最终完成。

    ┌─────────────────────────────────────────┐
    │               监督智能体                 │
    │                                         │
    │  - 监控所有子级                         │
    │  - 检测故障                             │
    │  - 使用退避策略重启                     │
    │  - 必要时重新分配工作                   │
    └──────────────────┬──────────────────────┘
                       │
       ┌───────────────┼───────────────┐
       │               │               │
       ▼               ▼               ▼
  ┌─────────┐     ┌─────────┐     ┌─────────┐
  │ 工人 A  │     │ 工人 B  │     │ 工人 C  │
  │ (存活)  │     │ (存活)  │     │ (重启)  │ ◄── 失败并重启
  └─────────┘     └─────────┘     └─────────┘

当工作必须可靠完成且不因单点故障而中断时使用。监督者的职责是提高韧性:检测问题并从中恢复。

Swarm (蜂群)

多个智能体在松散协调下对共享状态进行操作。每个智能体观察当前状态,识别可做的工作,贡献更改,并避免与其他智能体冲突。

    ┌─────────────────────────────────────────┐
    │           共享状态 / 目标               │
    └─────────────────────────────────────────┘
         ▲           ▲           ▲           ▲
         │           │           │           │
    ┌────┴───┐  ┌────┴───┐  ┌────┴───┐  ┌────┴───┐
    │智能体 A │  │智能体 B │  │智能体 C │  │智能体 D │
    └────────┘  └────────┘  └────────┘  └────────┘

蜂群协作非常复杂。它需要对共享状态和冲突解决进行精密设计。适用于复杂、不可预测的任务,在这些任务中,僵硬的协调会过于受限——但不要过早尝试这种模式。

一个完整示例

让我们追踪一个现实场景:“将代码库从 REST 迁移到 GraphQL。”

第 1 阶段:规划。 父级同步生成一个规划型智能体:

任务:"创建从 REST 到 GraphQL 的迁移计划"

规划型智能体分析代码库并返回结构化阶段:

{
  "phases": [
    { "name": "设置 GraphQL 服务", "files": ["server.js"] },
    { "name": "创建 Schema", "files": ["schema.graphql"] },
    { "name": "迁移端点", "files": ["api/*.js"], "parallel": true },
    { "name": "更新客户端", "files": ["client/*.js"], "parallel": true },
    { "name": "移除 REST 代码", "files": ["legacy/*.js"] }
  ]
}

第 2 阶段:顺序设置。 父级通过同步执行型智能体执行前两个阶段。这些阶段必须按顺序发生——没有服务器就无法创建 Schema。

第 3 阶段:并行迁移。 父级为每个 API 文件异步生成执行型智能体。20 个文件,20 个智能体同时运行。父级在每个智能体完成时收集结果。

第 4 阶段:验证。 父级生成一个验证型智能体,并附带所有更改列表。验证型智能体运行测试,检查 Schema 有效性并报告问题。

第 5 阶段:迭代。 如果验证发现问题,父级生成执行型智能体进行修复,然后重新运行验证。如果通过,则进入下一阶段。

这种编排——规划、并行执行、验证、迭代——从子智能体架构中自然产生。每个子智能体处理自己的片段,父级仅负责协调全局流程,因此其上下文始终保持精简和聚焦。

原则

起步要简单。 在达到单个智能体的极限之前,坚持使用它。只有当有具体理由时才进行解构。

定义明确的边界。 每个子智能体应当只有一个明确定义的职责。如果你不能用一句话解释它是做什么的,那么它做得太多了。

倾向于隔离。 疑虑之时,给子智能体更强的隔离性。

在每个层面处理失败。 子级会失败,网络会中断,上下文会超限。从一开始就在设计中融入韧性。

显式传递上下文。 不要假设子级知道父级所知道的一切。只传递它们需要的——不多也不少。

记录一切。 多智能体调试非常困难。对生成、结果和失败进行全面的日志记录,对于理解出错原因至关重要。


总结

子智能体架构是单个智能体扩展到复杂问题的方式。通过生成专门的子级——适当隔离、同步或异步运行、具有精细范围的上下文——父级智能体能够编排那些会让任何单一智能体不堪重负的复杂工作流。

核心洞见:

在第 9 章中,我们将探讨可扩展性——如何通过协议驱动的扩展、传输层抽象和插件架构,让智能体在无需修改核心代码的前提下获得新能力。