AI Agent 第三章:Pi Agent 与多模型分工,构建可验收的编码工作流

最后更新:2026-08-07
所属系列:AI Agent 实战 · 第 3 / 4 篇
文章目录 39 个章节

一个模型已经能搜索代码、修改文件和运行测试,为什么还要多模型分工?

最常见的答案是“不同模型各有所长”,但这句话不足以指导工程实践。真正需要解决的是:任务应该在哪个边界拆开,模型之间交接什么,谁拥有写权限,如何避免两边同时修改同一文件,以及最后由什么证据判断工作完成。

多模型系统的价值不在于模型数量,而在于让不同阶段拥有独立上下文、明确权限和可验收输出。 如果只是让三个模型在同一段对话里轮流发表意见,成本增加了,责任边界却没有变清楚。

这一章以 Pi Agent 这类终端编码工具为例,构建一条能在真实仓库中落地的多模型工作流。方法同样适用于其他支持模型切换、会话分支、命令行非交互模式或扩展机制的编码工具。

先区分三个容易混淆的概念

模型切换

同一个 Agent 循环在不同阶段更换模型,但继续使用相同工具和会话历史:

同一会话:快速模型探索 → 深度模型实现 → 快速模型总结

它的优点是交接成本低,缺点是后一个模型会继承前面的全部假设与噪声。适合任务阶段自然变化,但不适合需要真正独立意见的代码审查。

多模型路由

宿主根据任务类型、风险或预算选择模型:

格式整理       → 低成本模型
跨模块设计     → 强推理模型
视觉理解       → 支持图像的模型
高风险代码审查 → 独立审查模型

路由发生在调用模型之前,通常仍只有一个 Agent 在控制工具。它解决的是“这一步应该用哪个模型”,不是并发协作。

多 Agent 编排

多个拥有独立上下文的 Agent 分别执行子任务,编排器负责依赖、交接和汇总:

                 ┌→ Agent A:调查后端
任务编排器 ──────┼→ Agent B:调查前端
                 └→ Agent C:检查测试
                           ↓
                       汇总与验收

多 Agent 能并行,但也会引入文件冲突、重复读取、预算竞争和结论合并。只有子任务边界清晰、产物可以独立验证时,并行才真正有收益。

Pi Agent 提供了什么,又刻意没有提供什么

根据 Pi 官方仓库当前文档,Pi 的定位是一个最小终端编码 harness。默认向模型提供 read、write、edit 和 bash 四个工具,并通过 Skills、Prompt Templates、Extensions 和 Packages 扩展能力。

与多模型工作流直接相关的能力包括:

  • 通过 /model 或快捷键在多个 Provider 和模型间切换;
  • 通过 models.json 接入自定义 Provider、本地模型或兼容网关;
  • 会话以树结构保存,可以 /tree 回到旧节点,也可以 /fork 或 /clone 建立分支;
  • 长上下文支持手动或自动 compaction;
  • Extension 可以注册命令、工具、权限门、模型交接和 sub-agent;
  • print、JSON、RPC 与 SDK 模式可用于外部编排。

Pi 同时明确说明:它不把 sub-agent 和 plan mode 作为内置默认功能,而是让用户通过扩展或第三方包按自己的流程实现。官方扩展示例中提供了跨 Provider handoff、plan mode 和 sub-agent,但它们是可选实现,不应描述成 Pi 默认就会自动组织多模型团队。

这个取舍很适合作为架构提醒:工具支持多个模型,不等于工作流已经定义了模型之间的责任。

不要按品牌分工,要按产物分工

“模型 A 写代码、模型 B 做审查”仍然太模糊。更稳定的做法是为每个角色定义输入、权限和必须交付的产物。

角色 主要输入 权限 必须产出
侦察者 用户目标、只读仓库 只读、可运行安全查询 相关文件、调用链、风险与未知项
架构者 侦察报告、业务约束 只读 改动边界、接口契约、测试计划
实现者 已批准方案、目标文件 可写、可运行测试 最小代码改动与验证结果
审查者 原始需求、最终 diff 只读 按严重度排序的问题与证据
验证者 代码、验收命令 只执行确定性检查 退出码、失败日志、覆盖结果

这里故意没有写具体模型名。模型更新很快,角色契约应该比模型生命周期更长。选择模型时再根据上下文容量、工具调用可靠性、推理质量、延迟和成本匹配角色。

验证者首先应该是程序

很多“多模型流水线”最后安排一个更强模型判断前面是否完成。这个设计仍然把事实交给概率输出。

更可靠的验收顺序是:

  1. 编译器、类型检查和格式化;
  2. 单元测试、集成测试与静态分析;
  3. 页面截图、协议回放或性能基准;
  4. 独立模型审查无法由程序表达的设计风险;
  5. 人工确认发布、删除和外部消息等高风险动作。

模型可以建议测试命令,但不能只说“看起来应该通过”。验收记录必须包含真实命令、退出码和关键输出。

模型提出假设
      ↓
程序执行验证
      ↓
原始结果进入交接产物
      ↓
模型解释结果,而不是替代结果

一份可执行的交接协议

模型之间不要只交接一段自然语言总结。建议使用固定结构:

task: 修复工具页面生成漂移
goal: 源文件、生成页和运行时缓存版本保持一致
scope:
  allowed:
    - scripts/build-tools.sh
    - static/tools
  forbidden:
    - content/posts
facts:
  - CHECK=1 当前返回 1
  - 7 个页面都只在资源版本上不同
assumptions:
  - 生成页继续提交到 Git
decisions:
  - 资源版本改为内容哈希
open_questions:
  - Docker 是否也需要执行一致性检查
acceptance:
  - CHECK=1 scripts/build-tools.sh
  - go test ./...
evidence:
  - command: CHECK=1 scripts/build-tools.sh
    exit_code: 1
    summary: 7 generated pages drifted

这份交接把事实、假设和决策分开。后续模型可以挑战假设,但不需要重新猜测哪些命令真正执行过。

尤其不要只写“测试已通过”。应该记录测试范围和退出码,因为“运行了一个测试”和“运行了全部相关测试”是两件事。

一条实用的五阶段工作流

阶段一:侦察

侦察者只读仓库,不修改文件。它负责回答:

  • 需求对应哪些模块;
  • 当前实现的真实数据流是什么;
  • 工作区是否已有未提交改动;
  • 有哪些测试和构建入口;
  • 哪些结论仍只是猜测。

这一步适合速度快、成本低且工具调用稳定的模型。输出是一份短报告,而不是完整解决方案。

阶段二:设计

架构者读取用户目标和侦察报告,提出最小改动方案。对于跨模块修改,它需要明确:

  • 哪个文件是单一数据源;
  • 哪些接口会改变;
  • 兼容路径如何处理;
  • 失败时是否会留下部分状态;
  • 需要哪些回归测试。

这一步更依赖推理质量,可以使用更强模型,但工具权限仍保持只读。设计先经过人或主 Agent 接受,再交给实现者。

阶段三:实现

实现者获得明确的允许修改范围和验收命令。它不应该重新扩大目标,也不应该顺手重构无关模块。

如果任务可以拆成互不相交的文件集合,可以并行多个实现者;只要两个实现者可能编辑同一文件,就应改为串行,或者使用独立 Git worktree 后再显式合并。

阶段四:独立审查

审查者最好只接收:

  • 原始需求;
  • 最终 diff;
  • 必要的仓库上下文;
  • 已执行测试的证据。

不要把实现者的长篇理由全部塞给审查者。理由可能形成锚定,让审查者重复实现者的判断。真正需要独立性时,应使用新会话,必要时使用不同模型系列或 Provider。

审查者只报告具体问题:触发条件、影响、文件位置和建议验证方式。没有发现问题时也要说明残余测试缺口。

阶段五:验收与收口

主 Agent 汇总审查结果,决定哪些必须修复,再执行完整验收矩阵。最终交付应包含:

  • 实际变更;
  • 测试与构建结果;
  • 未完成或刻意推迟的事项;
  • 是否存在工作区改动、提交或外部发布。

模型之间可以讨论方案,但只有这一阶段有权宣布任务完成。

在 Pi 中如何落地

方式一:同一会话手动切换模型

最简单的做法是在阶段边界使用 /model。例如侦察完成后,把报告保存为消息或仓库外的临时交接文件,再切换到适合设计或实现的模型。

这种方式适合小任务,因为工具状态和上下文连续。但要注意:切换模型不会自动清理旧假设。进入审查阶段时,更推荐新建分支或新会话。

方式二:使用会话树建立独立分支

Pi 的会话记录具有树结构。可以在共同的用户目标处 /fork,让两个模型从同一事实起点分别提出方案,再由主会话比较结果。

用户目标
  ├─ 分支 A:方案一与风险
  ├─ 分支 B:方案二与风险
  └─ 主分支:比较后选择

这比在一个上下文里连续问“还有别的方案吗”更独立,也保留了完整历史。对于代码审查,可以从原始需求建立干净分支,只把最终 diff 加入上下文。

方式三:使用 handoff 扩展

Pi 官方扩展示例包含跨 Provider 的 handoff 命令。它适合把当前任务压缩成结构化上下文,然后交给另一个模型继续。

使用这类扩展时要检查三件事:

  • 交接内容是否保留真实测试证据;
  • 是否意外包含密钥或大量无关日志;
  • 新模型获得的工具权限是否与角色相符。

handoff 解决上下文搬运,不自动解决验收和权限问题。

方式四:多个进程或 sub-agent 扩展

真正并行时,可以启动多个 Pi 进程,或使用官方示例中的 sub-agent 扩展。每个执行单元应有独立任务、预算和目录。

对会修改代码的角色,推荐使用 Git worktree 隔离:

git worktree add -b agent/backend ../project-backend
git worktree add -b agent/frontend ../project-frontend

两个 Agent 分别工作,最后由主流程审查提交并合并。不要让多个进程在同一个工作区同时写文件,否则一个 Agent 的格式化或生成命令可能覆盖另一个 Agent 尚未提交的修改。

sub-agent 也不应该无限递归创建。编排器需要限制最大并发数、总模型调用数、截止时间和预算。

模型选择看五个维度

不要只用公开榜单给角色分配模型。编码 Agent 更应该看真实工作流指标:

工具调用可靠性

模型能否稳定生成正确参数,遇到工具错误后是否会调整,而不是重复同一调用。

上下文与检索能力

大型仓库需要找到真正相关的文件。上下文窗口很大不代表模型会利用得好,还要观察它是否能压缩和引用证据。

修改精度

实现者应该产生范围小、能通过测试的 diff,而不是为了完成局部需求重写整个模块。

独立审查能力

审查者需要主动寻找反例、边界条件和遗漏测试。使用与实现者不同的模型系列,通常比同模型自我审查更容易获得不同视角,但最终仍要以实际发现质量衡量。

延迟与成本

侦察、日志分类和格式整理不必全部使用最昂贵模型。应记录每个角色的输入输出 token、缓存命中、耗时、重试和最终采纳率。

一个简单的路由策略

路由不需要一开始就训练分类器。确定性规则更容易调试:

只读、低风险、上下文较小
  → 快速模型

跨模块设计、安全或数据一致性
  → 强推理模型

明确实现任务且有完整测试
  → 工具调用稳定的编码模型

最终代码审查
  → 与实现者不同的独立模型

编译、测试、格式化、生成校验
  → 不调用模型,直接运行程序

等积累足够运行数据后,再根据任务成功率、成本和人工返工率调整规则。不要在没有观测数据时构建复杂的“智能路由器”。

并行之前先画依赖关系

只有没有写冲突且输入已经就绪的任务才能并行:

需求澄清
   ↓
仓库侦察
   ↓
接口设计
   ├──────────────┐
   ↓              ↓
后端实现       前端实现
   └──────┬───────┘
          ↓
       集成测试
          ↓
       独立审查

如果前端依赖尚未确定的接口,提前并行只会制造返工。先冻结契约,再并行实现,通常比“所有 Agent 立即开工”更快。

权限必须跟角色走

Pi 官方文档明确提醒:默认运行时继承启动进程的文件、命令、网络和凭据权限,不内置完整权限沙箱。Pi Package 和 Extension 也可以执行任意代码,因此安装第三方扩展前需要审查来源。

多模型工作流会放大这个风险,因为更多执行单元意味着更多凭据副本和命令入口。建议:

  • 侦察者和审查者使用只读工作区;
  • 实现者只写自己的 worktree;
  • 不向子 Agent 传递生产密钥;
  • 网络访问使用目标白名单;
  • 发布、删除和外部消息始终经过人工确认;
  • 第三方扩展固定版本并审查源码;
  • 高风险任务在容器、虚拟机或专用沙箱运行。

第二章建立的工具风险等级、确认和审计机制,在多 Agent 场景中仍然适用,而且应该由编排器统一执行,不能交给每个子 Agent 自行决定。

如何判断多模型真的有收益

至少记录以下指标:

指标 说明
一次通过率 实现后无需返工即通过验收的比例
审查采纳率 审查发现中最终被确认并修复的比例
重复工作率 多个角色重复读取或实现相同内容的成本
人工介入次数 需要人补充上下文、解决冲突或纠偏的次数
总耗时 从任务开始到确定性验收完成
总成本 所有模型调用、缓存和失败重试的合计

如果加入第二个模型后只增加 token,没有提高一次通过率或审查发现率,就应该退回单 Agent。多模型不是默认更高级的形态,只是一种在特定任务结构下有效的工程工具。

常见失败模式

所有角色共享同一段长上下文

这样虽然省去交接,却让错误假设在所有角色之间传播。独立审查应从更干净的上下文开始。

多个实现者共用一个工作区

文件修改、依赖安装和生成命令会相互覆盖。使用不相交文件边界或独立 worktree。

交接只有自然语言结论

没有命令、退出码和文件引用时,后续模型无法区分事实与推断。使用固定交接结构。

让模型自己宣布测试通过

模型输出不是执行证据。编排器必须实际运行测试并读取退出状态。

每一步都调用最强模型

这会显著增加延迟和成本,还可能让简单任务过度设计。模型能力应与角色风险匹配。

sub-agent 可以无限派生

没有并发、深度和预算上限时,一个普通任务可能扩散成大量重复调用。编排器必须持有全局停止条件。

不使用 Pi 也能复用这套方法

Pi 的价值在于模型选择、会话树和扩展接口足够开放,适合实验自己的流程。但这套分工并不依赖某个具体产品:

  • 支持模型切换的终端工具,可以手动执行阶段式工作流;
  • 支持非交互模式的工具,可以由 CI 或脚本编排;
  • 支持子任务的 Agent 平台,可以把角色契约写进任务描述;
  • 只支持单模型的工具,也可以通过多个独立会话完成实现与审查分离。

真正需要保留的是四个边界:独立上下文、最小权限、结构化交接和确定性验收。

本章小结

多模型分工不是“给每个模型一个职位名称”,而是一套软件交付协议:

侦察者提供事实
架构者冻结契约
实现者产生最小 diff
审查者寻找反例
程序负责最终验收
主 Agent 控制权限、预算和停止条件

Pi 提供了多 Provider、模型切换、会话分支和扩展机制,但它刻意把具体工作流留给用户。这个设计让我们看到一个更普遍的结论:Agent 框架负责提供能力,可靠的分工仍然来自清晰的输入输出契约。

下一章可以继续向编排层推进:用 Go 实现一个带依赖图、并发限制、预算和检查点的任务调度器,把本章的角色协议变成可运行代码。

参考资料