Pi 这类工具用顺手之后,单线程让它写代码会越来越不过瘾。前面几篇讲的是怎么让 Pi 完成单个任务,比如改 bug、写测试、做代码审查,但真实项目从来不是单任务战场:一个需求拆下来,少说有三四个模块要动,前后端要配合,文档要同步,测试要跟上。如果全塞给一个主代理串行处理,要么上下文越拖越长导致后期指令混乱,要么一个文件改动引发连锁反应却没人提前兜底。这篇「Pi 实战 04」就专门讲多智能体与高级工作流,带你把 Pi 从一个「能干的助手」升级成「一个能带队干活的小团队」。
我会从 Pi 的多智能体机制讲起,把主代理和子代理的分工逻辑说明白,再给一套可以直接抄的工作流配置方案,包括需求拆解、并行编码、代码审查、测试收尾这几个环节,最后补充几个我在实际操作中踩过的坑。适合已经对 Pi 的基本用法有了解、想让协作效率再上一个台阶的朋友阅读,读完你会发现多智能体不是把任务丢给多个 AI 而已,关键在于编排、上下文控制和风险闸门。
1. 为什么要搞多智能体:单代理模式的瓶颈在哪
1.1 单代理越长越笨的上下文问题
先看单代理的工作方式。你给 Pi 一个需求,它在一个对话上下文中连续读文件、改代码、跑测试,所有历史记录都会保留。这个模式在任务范围小的时候非常稳,但一旦任务复杂,上下文窗口就会被逐步填满。文本一多,Pi 的注意力就会分散,经常出现「前面说好的命名规范,后面改着改着就忘了」或者「明明刚刚确认过某个接口签名,下一轮就开始自由发挥」这类现象。
这其实是所有大模型应用都绕不开的问题。上下文越长,模型对早期指令的遵循度就越低,同时对 token 的消耗也越大。我实测过,一个包含几十个文件的增量改造任务,如果全程塞在主代理里跑,到后半程 Pi 的决策质量会明显下降,而且每次回复前的等待时间肉眼可见地变长。与其硬扛,不如把任务拆开,让每个子代理只处理一个局部范围,上下文短、目标清晰、输出质量反而更稳定。
1.2 Pi 的多智能体工作机制
Pi 的多智能体采用的是「主代理调度 + 子代理执行」的架构。主代理负责接收你的指令、拆解需求、分配任务、汇总结果;子代理是轻量级的执行单元,每个子代理有自己独立的上下文和任务清单,干完活之后把结论交回给主代理。
这个机制里最关键的一点是子代理之间不直接互相通信,所有信息都通过主代理中转。这样做的好处是避免了多智能体之间消息风暴和上下文串扰,代价是主代理的上下文会成为信息集散地,所以控制好每个子代理回传内容的粒度很重要。你可以让子代理「只返回结论 + 变更文件清单 + 需要主代理注意的风险点」,而不是把完整的会话记录倒出来。
1.3 多智能体真正解决的是什么
多智能体不是「多个 AI 一起干活」这么简单,它解决的问题有三个:一是上下文隔离,每个子代理只需要加载自己负责的那部分代码,不用背着整个项目历史;二是并行效率,没有依赖关系的任务可以同时跑,省掉串行等待时间;三是角色专业化,你可以给不同子代理设定不同的人设和能力边界,比如一个只做代码审查、一个只做安全扫描、一个只写技术文档,每个子代理都能做到术业有专攻。
有个类比挺合适:单代理模式就像你雇了一个全能实习生,什么事情都喊他做,他忙得晕头转向还容易出错;多智能体模式像是你带了一支小队,拆解、编码、审查、测试各有专人,你只需要坐镇指挥。对项目管理者来说,后者的体验要好太多。
2. 动手前的基础准备:初始化工作区与角色配置
2.1 安装 Pi 并初始化项目工作区
开始之前先确认 Pi 的版本,多智能体功能在较新版本里才算完整,建议保持最新版。项目里执行:
pi init这个命令会在当前目录生成.pi/工作区目录,里面包含全局配置、技能目录、代理角色定义等基础文件。初始化完成后,用pi doctor检查一下环境是否正常,它会报告配置文件的解析情况、依赖项是否齐全、工作区里有没有明显冲突。
我建议把.pi/目录纳入版本管理,团队协作时每个人拉下来都能保持一致的行为配置。不过要注意,如果你的项目里已经有旧的.pi/目录,先备份再升级,新版初始化会覆盖部分配置文件。
2.2 用 Skill 扩展子代理的能力
Pi 的 Skill 机制相当于给代理安装「专业技能包」。比如你要让子代理做前端代码审查,没有对应的 Skill 它也能做,但有了 Skill 之后,它会更清楚项目的技术栈规范、目录约定、常见反模式。Skill 可以通过pi skill install从市场安装,也可以自己写,本质是一个带说明文档和规则提示的文件夹。
我最常用的操作是导入项目自定义 Skill。在.pi/skills/下建一个目录,里面放一个SKILL.md文件,内容用简洁的自然语言描述这个技能的使用场景、检查要点和输出格式:
--- name: project-reviewer description: 针对本项目的代码审查技能,关注接口兼容性、数据迁移、日志规范 --- 检查代码时请重点关注: 1. 涉及数据库变更时,是否提供了相应的迁移脚本说明 2. 新增接口是否向后兼容,是否有版本兼容策略 3. 日志输出是否遵循项目的统一格式Skill 不要写得过于抽象,直接告诉子代理「在这个项目里什么重要」是最有效的。子代理加载 Skill 之后,它的行为会明显更贴合项目实际。
2.3 创建你的第一份子代理角色清单
子代理的配置在.pi/agents.toml里定义,每个子代理包含名称、角色描述、可用 Skill、允许的操作范围、温度参数等字段。下面是一份我常用的最小配置:
[agent.reviewer] role = "代码审查员" description = "负责检查代码质量、发现潜在 bug 和安全隐患,只读代码,不直接修改文件" skills = ["project-reviewer"] permissions = ["read", "run-tests"] temperature = 0.2 [agent.doc-writer] role = "文档工程师" description = "负责从代码变更中提炼文档要点并生成 Markdown 文档,不修改源代码" skills = ["doc-generator"] permissions = ["read", "write-docs"] temperature = 0.5 [agent.frontend] role = "前端开发" description = "负责前端页面与组件实现,遵循项目前端目录规范和代码风格" skills = ["frontend-stack"] permissions = ["read", "write"] temperature = 0.3这里有几个设置要点。温度参数控制创意的随机性:代码审查、测试这类任务建议调低到 0.2 左右,追求严谨;文档写作可以稍高一点。权限控制一定要收紧,安全相关的子代理尽量只读,避免 AI 审查代码时顺手帮你改了文件,那会非常灾难。
配置完成后,执行pi agents list可以查看所有子代理的状态。如果某个角色的 Skill 没有正确加载,这里会直接报出来,趁早排查。
3. 一套能直接复制的多智能体工作流
3.1 阶段一:需求拆解与调研并行化
拿到一个中等规模的需求时,不要直接下令「开始干活」,先让主代理做需求拆解。我会在 Pi 里发起这样一场会话:
请根据以下需求进行任务拆解,并把每个子任务分配给最合适的子代理: 需求:给订单系统增加批量导出功能,支持 CSV 和 Excel 格式,要求可以按时间范围筛选、按状态筛选,导出时不能阻塞主服务。主代理会结合项目上下文,把需求拆成几个典型的子任务:后端接口设计、导出文件生成模块、前端操作入口、异步任务队列改造、测试与文档。拆解完成后,主代理会生成任务依赖图,比如「前端入口依赖后端接口完成」「Excel 导出依赖文件生成模块完成」。
这个阶段适合并行的是「调研型任务」。比如让一个子代理梳理现有订单表结构和接口,另一个子代理调研项目里是否有现成的异步任务队列,第三个子代理查看前端订单列表页的实现方式。它们互不依赖,可以同时跑。主代理会在收到所有调研结论后做汇总,形成一份实现方案。
3.2 阶段二:按模块并行编码
需求分析完成后进入编码阶段。这个阶段最常见的错误是强行把所有模块同时开工,结果接口还没定义好,前后端各自按自己的想象去实现,最后联调时全是冲突。
我的做法是让主代理先定义好「契约」。比如后端接口的出入参结构、导出文件的字段清单、错误码规范,这些先确定下来,再分发给各个子代理并行开发。配置一个并行任务组:
请调度以下子代理并行执行: - frontend:实现订单列表页的批量导出按钮和筛选条件 - backend:实现导出任务的创建接口和状态查询接口 - async-worker:实现导出任务的后台处理逻辑 所有代理必须遵循已确认的接口契约,完成后报告变更文件和测试结果。并行编码时,代码仓的冲突控制要注意。最好是每个子代理负责完全不同的文件目录,避免两个代理同时改同一个文件的尴尬情况。如果项目比较小、文件之间耦合度高,并行未必有优势,串行反而更稳妥。
3.3 阶段三:代码审查代理独立上线
编码完成不等于可以交付。我很坚持的一点是:负责写代码的子代理和负责审查代码的子代理必须是不同的角色。首先写代码的代理对代码有「感情」,不容易发现自己的问题;其次审查需要更低的温度和更挑剔的眼光,和开发代理共用一个上下文会影响判断。
启动审查代理的命令大概是:
请 reviewer 审查以下分支的变更,重点关注:数据库迁移是否遗漏、接口兼容性、异常处理路径、日志规范。不要修改代码,只输出问题清单和修改建议。审查代理会从只读权限的文件系统里快速浏览变更,结合 project-reviewer Skill 的检查要点,输出风险分级清单。通常我会要求审查结果标注严重级别:阻塞问题、建议修复、可选优化。阻塞问题直接打回给对应开发代理处理,建议修复的排到下一轮迭代。
3.4 阶段四:测试与文档收尾
代码通过审查之后,测试子代理开始工作。它负责补单元测试、集成测试,以及关键路径的端到端验证。这里有一个重要细节:测试代理需要知道哪些是「关键路径」,不能所有函数都无脑补测试,产出质量反而不高。
文档代理在编码阶段结束后介入,根据代码变更记录、接口定义、测试报告,自动生成技术文档和变更日志。文档代理的权限只允许写 docs 目录,不允许碰源代码。三个代理(测试、文档、以及可能的构建发布代理)在这个阶段又形成一轮并行。
整个工作流跑完之后,主代理会输出一份完整的交付报告,包含变更文件树、测试覆盖率、遗留问题、发布建议。你只需要做最后的人工复核,而不需要盯每一行代码的编写过程。
4. 高级工作流的编排技巧与上下文管理
4.1 表达任务依赖:串行、并行与汇合
多子代理协作时,最常见的需求就是「A 做完 B 才能做,C 和 D 可以同时做,最后 E 汇总」。Pi 的工作流里,可以用depends_on字段显式声明依赖关系,也可以用更直观的分组语法:
# workflow.yaml stages: - name: 调研 agents: [env-explorer,>[agent.reviewer] max_context_tokens = 10000 max_output_tokens = 4000同时在主代理的调度指令里强调输出的精简性,让子代理只返回变更摘要而不是大段代码。还有一种更省钱的方式:把子代理的中间产出直接写入仓库里的临时目录,回传时只带文件路径,主代理需要看时再读取。这种「外置记忆」能大幅降低上下文占用。
4.3 人机协作的审批闸门
多智能体全自动跑完整个工作流听起来很爽,但在真实项目里,我强烈建议在关键路径上设置人工审批闸门。比如「契约定义」完成后需要你确认接口设计,「代码审查」完成后需要你确认问题清单的处理方式。闸门机制避免了一个小错误被流水线放大到不可收拾的地步。
Pi 支持在 workflow.yaml 里声明approval.required: true,运行到该节点时会暂停下来等你确认。你可以在交互界面上查看这个阶段产出的摘要、变更文件、风险提示,选择「通过」「打回」或「修改后继续」。这个设计相当于给了人控制多智能体的方向盘,而不是把整个项目全权交给 AI。
4.4 多智能体的「会诊」式协作
除了流水线式的分工协作,还有一种更高级的用法:针对疑难问题,让多个子代理从不同视角进行分析,然后汇合出综合方案。比如线上出现一个偶发的性能问题,你可以同时让性能分析代理看慢查询日志,让代码审查代理检查热点路径的代码,让架构代理评估是否存在设计层面的瓶颈。
三个代理看完之后,主代理把所有分析结论汇总,再输出一份「问题根因 + 解决路径」的报告。这种会诊式协作特别适合复盘场景。我第一次测试这个模式时,效果超出预期,一个我排查了两小时没头绪的问题,四路并行下来,很快就定位到了缓存穿透加 N+1 查询叠加的根因。
5. 常见问题与排查技巧实录
5.1 多个子代理同时改代码,冲突了怎么办
并行编码最容易翻车的场景就是两个子代理改了同一个文件。即使你在任务分配时强调了文件边界,子代理还是有可能会顺手调整公共模块。出现冲突时,不要直接让主代理强行合并,最好先把冲突文件交由一个子代理单独处理,同时让其他代理暂停对相关文件的写入。
我也学到一个更稳妥的做法:在任务分配阶段就让子代理先输出「计划修改文件清单」,由主代理检查是否存在重叠,如果有重叠就重新划分边界。这个动作只花十几秒,但能把冲突概率降到极低。
5.2 子代理跑着跑着丢失了关键上下文
子代理的执行时长较长时,会出现上下文被清空或轮换的情况,表现为它忘记了一开始的任务目标,开始做一些偏离需求的操作。排查第一步是看任务日志里有没有上下文重置的记录,第二步是检查子代理配置里max_context_tokens是否设置得太小。
缓解手段有两种:一种是把关键约束写进 Skill 文件,让子代理每次唤起时都能重新读取;另一种是设置阶段检查点,每个阶段结束时让子代理把「当前进度 + 下一步计划」写回工作区文件。这样即使上下文重置,它也能从检查点文件恢复状态。
5.3 工作流卡住不动或超时
工作流跑着跑着不动了,通常原因是某个子代理在执行过程中抛出了异常,但工作流没有配置失败处理策略,就一直等待。排查时先看子代理的退出码和错误日志,是文件读写权限问题、还是模型输出格式解析失败、还是依赖的 Skill 没有正确加载。
我在配置工作流时习惯对每个阶段都加上超时时间和失败重试策略:
stages: - name: 实现 agents: [frontend, backend] mode: parallel timeout_seconds: 600 retry_count: 2 on_timeout: notifyon_timeout设为notify而不是fail,能让你第一时间收到通知,决定是让代理继续跑还是手动介入。这里建议把超时阈值设得比平时执行耗时多 30% 左右,避免频繁误报。
5.4 模型输出不稳定,同一任务两次结果差异大
温度参数对多智能体的输出稳定性影响非常大。同样的代码审查任务,温度设为 0.8 时审查结果天马行空,设为 0.2 时更贴合项目实际。如果你发现子代理的输出质量波动大,第一件事就是检查它的temperature是否在合理范围。
还有一个小技巧:在子代理配置里加入output_schema,规定返回结果必须是结构化格式:
[agent.reviewer] output_schema = """ { "result": "pass|fail|warning", "issues": [{"file": "", "severity": "blocker|suggestion", "line": 0, "message": ""}] } """格式化输出对后续主代理汇总结果非常有帮助,省去了解析自然语言结果的成本。
收尾:关于多智能体的几句大实话
折腾多智能体这么长时间,我最大的体会是:多智能体不是万能药,它解决的是复杂任务的组织效率问题,而不是模型能力问题。如果你的任务一张嘴就能说清楚,比如「把这个函数改成支持可选参数」,那就让主代理直接做,完全没有必要调度子代理,多智能体的调度开销反而成了负担。反之,当任务涉及多个领域、多个模块、多个角色视角时,多智能体的价值就体现出来了。
最后分享一个经验:从两个子代理起步,一个负责开发、一个负责审查,跑跑看效果,再逐步增加文档、测试、调研等角色。不要一上来就配八个子代理跑一个超大工作流,因为调度复杂度会指数级上升,最后的瓶颈往往不是 AI 的能力,而是你的流程设计是否合理。先把小闭环跑顺,再扩大规模,这样踩坑的成本更低,也更清楚每个子代理到底能给你带来多少增量价值。