
最近帮一个团队做代码评审发现一个特别典型的场景需求文档写得很清楚子agent也忠实地“写完了代码”结果打开Diff一看接口签名和文档里定义的完全对不上错误处理逻辑散落在三个文件里测试文件干脆就没生成。这不是哪个模型智商不够而是组织方式出了问题——你让一个agent同时当架构师、实现者、测试员和评审员它的注意力天然会被稀释。这正是我认同Subagent驱动开发模式的原因。Superpowers系列里讨论过很多次这个思路核心主张其实很朴素不要训练一个“全能助手”而是要组织一条生产流水线。每个Subagent只负责一个工位有独立的上下文、明确的工具集和可验收的输出标准主控agent负责调度、校验和返工。这样AI写的每一行代码都是可检查、可拒绝、可追溯的真正从“让AI写代码”变成“用AI管理一条编码产线”。这篇文章我会把整套流水线架构拆开讲为什么单个agent大包大揽必翻车、五种Subagent工位怎么设计、主控调度怎么写、我在实测中踩过的坑以及到底什么团队适合上这套玩法。现在很多团队已经在用AI写代码但效果忽好忽坏问题恰恰出在流程而不是模型上。1. 为什么单个“超级Agent”大包大揽是AI编程翻车的主要根源1.1 一个Agent同时扮演所有角色恰恰是它最不擅长的先说个我自己的经历。早期我也图省事把“把这个支付模块写出来”这种需求直接甩给大模型让它自己看仓库、自己定接口、自己写代码、自己补测试。单看某个文件产出质量其实不错但一旦涉及多个文件之间的协同问题就全出来了。最典型的情况是“前面定义、后面推翻”。agent在生成接口定义的时候是一套方案写到某个具体实现时又为了“省事”改了参数结构而调用方代码还是按老签名生成的。你问它为什么不一致它甚至会给出一个逻辑自洽的理由。这种连续性断裂的原因并不神秘上下文窗口再大也没法把整个项目的所有细节都装进去并保持全局一致。当agent同时关注“这个函数怎么写”和“整个项目架构怎么定”时注意力被分散是必然结果。打个比方你就明白了。传统手工作坊里一个老师傅从画图到锻造到打磨全包能做出一把好刀但你要他一天做出五百把标准一致的刀他一定失控。流水线革命解决的不是“工人变聪明”而是把工序切细、把每个工位的输入输出固定下来让品质问题能在某个环节被拦住。AI编程也是同理。单个大agent就是那位老师傅而Subagent架构就是那条流水线。1.2 Subagent的本质把“一个聪明的Agent”换成“一组职责清晰的Agent”Subagent并不是更聪明的agent它只是可组合、可隔离、可验证的agent。每个Subagent拥有独立的上下文窗口、独立的角色提示词、独立的工具集以及独立的输出工件。这个设计带来的好处非常直接上下文隔离实现模块的agent不需要关心需求文档里那些营销背景它只需要接口规范、它负责的文件路径和仓库里相关类型的定义。上下文越小注意力越集中越不容易跑偏。关注点分离架构agent负责定边界写代码的agent负责填充实现测试agent负责找茬审查agent负责挑刺。每个角色只干一件事衡量标准完全不同。架构agent写得再好也不能替测试agent决定测试策略。错误不向下游传播主控agent在每一道工序之间做校验。架构agent输出的接口文档格式不对直接打回重做根本不会传到实现环节。这比一个agent从头写到尾、最后统一review要省得多。我自己在项目里实践下来最大的感触是一个Subagent的输出质量大概率比同一个模型当“全能助手”时的输出质量高出一截。原因不是模型变了而是它收到的信息、被要求的产出形式、以及验证方式都变得更像一份“工位作业指导书”而不是一句“你看着办”。2. 五种Subagent工位架构、编码、测试、审查、文档2.1 流水线总览与工位卡片把软件开发拆成流水线首先要做的是定义工位。我这边经过几次迭代后固定下来五类每一类都有明确的输入工件、输出工件和退出标准整理成一张表你一眼就能看明白工位输入工件输出工件退出标准架构定义需求文档、约束条件模块边界、接口签名、数据模型接口文档为结构化JSON通过scheme校验模块实现接口规范、目标文件清单、相关类型定义单个模块的完整代码、新增测试文件代码通过编译与静态检查测试文件存在测试生成实现代码、接口规范单元测试代码与用例说明测试文件可执行至少覆盖关键分支代码审查实现代码、测试代码、接口规范审查意见列表无阻塞性意见或有且已被主控裁决文档更新最终代码、测试报告、变更记录README段落、CHANGELOG条目文档路径匹配变更文件无过时描述流水线里交接的永远是“工件”不是自然语言聊天记录。实现agent给测试agent的不是“我写完了你看一下”而是一份代码变更、一份接口文档和一个可执行的测试入口。这个区别非常重要——工件可以被程序校验聊天记录只能靠人看。2.2 每个工位的提示词里应该有什么不该有什么工位定义完之后提示词设计就变成最关键的工程决策。这里我走过弯路一开始恨不得把所有信息都塞给每个子agent后来发现完全相反。架构agent的提示词只给需求原文和明确的技术约束比如“必须兼容现有的权限中间件”“数据模型需要预留软删除字段”不给任何历史对话。要求它输出严格的结构化接口定义而不是散文式的设计说明。提示词里我会明确要求“如果需求本身存在歧义请列出你的假设并给出默认选择”这样能逼出隐含的不确定性。实现agent的提示词只给接口规范、它要动的文件清单以及必要的依赖类型定义。不给全部仓库代码不给需求背景。最重要的是一句话“你的唯一任务是让这些接口签名存在且行为符合描述。”此外我强烈建议让它先输出一段不超过三行的实现计划再写代码。这是降低返工率最有效的一招后面会细说。审查agent的提示词明确告诉它“你只输出意见不修改代码”。每条意见必须包含文件、行号、问题类别正确性/性能/可读性/安全隐患和建议修改方向。如果它想改代码说明这个工位设计有问题。还有个我试过多次的小技巧让每个subagent在输出末尾增加一个self_check字段用一两句话说明自己是怎么验证产出的。这个字段价值极高很多agent在写self_check的时候会发现自己根本没跑过测试或者说不出验证方法——它自己写出来都会心虚。3. 主控调度任务分解、工件交接与并行控制3.1 主控的责任是拆任务不是写代码流水线的主控agent不需要写一行业务代码它的核心工作是三件事拆解任务、调度工位、验证成果。任务拆解的粒度非常关键。我的经验是一个任务卡应该小到“一个Subagent在有限的上下文里能独立完成并自我验证”。一个支付模块可以拆成“账户余额查询接口”“转账事务服务”“交易记录分页查询”三张任务卡而不是一张超大的“实现支付模块”。每张卡要写清楚目标、输入工件路径、输出工件规范、退出标准。这里补充一个重要的设计原则不要把调度逻辑做成纯agent决策尽量写成确定性代码再加上关键节点的agent辅助。很多人会把主控也定义成一个“很聪明的agent”让它自己决定怎么拆任务但这样做的代价是行为不可预期。我实际项目里采用的方案是用Python脚本定义流水线状态机任务卡由人工或架构agent一次性生成提前定义好脚本按依赖关系执行调度只有遇到状态判断模糊的地方才让LLM做一次辅助决策。一个简化版的调度伪代码长这样from dataclasses import dataclass from typing import Callable import subprocess dataclass class TaskCard: role: str # architecture / implement / test / review / docs task_id: int input_paths: list[str] output_paths: list[str] acceptance_cmd: str max_retry: int 3 def run_acceptance(task: TaskCard) - bool: # 退出标准必须是确定性脚本不能听agent自己说“完成了” result subprocess.run(task.acceptance_cmd, shellTrue, capture_outputTrue) return result.returncode 0 def main_loop(tasks: list[TaskCard]): done, failed [], [] for task in tasks: for attempt in range(task.max_retry): # 1. 构造当前任务的完整prompt角色 输入工件 输出schema prompt build_prompt(task, include_historyattempt 0) # 2. 调用能跑subagent的模型接口拿到产出 output dispatch_subagent(task.role, prompt) write_outputs(output, task.output_paths) # 3. 跑确定性验收 if run_acceptance(task): done.append(task) break elif attempt task.max_retry - 1: failed.append(task) # 失败的任务打上标记进入人工处理队列 return done, failed这段代码的重点在于run_acceptance那一行——决定了“这个工位算不算过”的不是LLM的判断而是真实的编译命令、测试命令、静态检查命令。整个流水线最核心的哲学就是AI负责生成脚本负责验收。3.2 串行、并行与依赖关系不是所有工位都能并行。架构定义必须最先完成否则下游全部失去锚点。测试生成依赖实现代码审查依赖测试存在。这些硬依赖必须串行。真正能并行的是那些互不依赖的模块实现任务。“账户余额查询”和“交易记录分页查询”如果接口边界清晰、文件不重叠完全可以同时派给两个Subagent跑。我的建议是并行上限定在3到5个原因有两个一是token成本在高峰期会飙升二是并行任务之间的上下文隔离会增加输入裁剪的设计难度文件重叠的风险也会上升。想让并行更靠谱一个做法是先让架构工位输出一张“依赖图”主控按依赖层级分批调度。批内并行批次之间串行。这跟CI/CD里的pipeline思路完全一脉相承只是从“跑脚本”变成了“跑agent”。3.3 怎么对接git与CI很多团队倒在这一步subagent把代码生成了但agent生成的代码要落进真实工程仓库中间还有一道“信任边界”。我的做法是实现agent不直接改文件而是输出标准化的文件路径加完整内容或diff片段由确定性脚本负责写盘。写盘之后立即跑一次git diff --check和编译命令确保没有空白错误、没有语法错误然后才允许进入下一工位。这个过程中所有agent都没有仓库写权限连接近仓库的工具都不给。原因很粗暴一旦让agent直接操作git你会在review的时候发现一些“莫名奇妙的合并”和历史重写那个排查成本比返工高得多。等所有工位跑完流水线生成的产物就是“一批校验过的文件一份变更说明”人工review时只需要在GitLab或GitHub上开一个MR看diff、看测试报告、看审查意见列表。整个流水线并没有替代人而是把人的注意力收窄到“最终决策”这一步。4. 实测中踩过的坑上下文污染、幻觉验收、并行写冲突4.1 坑一上下文越“丰富”产出越糟糕第一次搭流水线的时候我为了“让子agent更懂这个仓库”把整个仓库目录树和几个核心模块的代码全塞给了实现agent。结果它写出来的代码学会了无关模块的命名习惯复制了一段与任务无关的工具函数更离谱的是引用了一个根本不存在的方法——因为它从参考代码里“推断”出有这个方法。后来我才想明白上下文上下文没有边界就是噪音。实现一个登录接口的agent不需要知道推荐系统的聚类逻辑。合理的做法是给“文件清单相关类型定义接口签名”把这些信息整理成一个最小设计视图。如果它在编码过程中确实需要查某个函数定义正确的机制是给它一个检索工具让它自己按需查询而不是提前把所有可能用到的信息全塞进去。4.2 坑二agent自己说自己“测试通过”这个坑我印象太深了。早期我把验收逻辑写成“读取subagent返回的文本如果包含‘测试通过’四个字就把状态置为success”。某个实现agent很流畅地输出了“所有测试均已通过并验证”但我一检查它压根没生成测试文件那只是一种语言上的“顺滑”。模型不会撒谎的机制它只是在预测话语模式。从那次之后我立了一条铁律任何验收都只认脚本返回值。测试跑没跑过不是agent说了算是pytest/go test/cargo check的退出码说了算。检查-反馈循环也要配套设计验收失败把失败日志作为修订输入退回给原工位让它修改后再试连续重试超过三次标记为疑似“工位解决不了”的任务转入人工处理而不是无限重试烧token。4.3 坑三并行Subagent改同一批文件并行调度看起来很美但第一次实际运行就翻车了。两兄弟一个做“用户资料查询”一个做“用户资料修改”任务卡里恰好都写了“可能需要调整model/user.go”。结果两人同时往同一个文件里写入各自的版本后写入的覆盖了前一个代码直接编译不过。解决方式靠工程约定每个任务卡里声明这个子任务的“文件所有权”。调度器在分配并行任务前检查任务的输出文件路径集合是否存在交集有交集的任务自动降级为串行。这跟真实团队里的代码所有权机制是一样的只是提前到调度阶段做了自动检查。对了git status里出现意外冲突文件也是同样的排查思路先看任务卡的文件所有权声明再看上下文隔离对不对。4.4 坑四昂贵的token花在“解释”上子agent有一个我觉得还挺烦的习惯喜欢在代码之外输出大段的“设计说明”。第一次跑完一条流水线我看了一下token账单好家伙40%的费用花在了解释代码细节和复述需求上。对策有两层。第一层是在提示词里规定“解释最多三句话输出以代码为准”第二层是给每个工位的输出定义schema例如实现工位只允许输出files: {path, content}[]和self_check: string两个字段。结构化输出的限制比自然语言提示词更硬因为它从格式层面堵死了“写一堆散文”的空间。5. 适合与不适合团队和项目如何决定要不要上Subagent流水线5.1 真正适合这套玩法的场景从我接触过的项目来看最适合Subagent流水线的有三类场景模块边界清晰的中大型功能开发、重复性高的编码工作、以及需要完整审计轨迹的正式工程团队。举个例子。某个后端团队接了一批标准的CRUD接口开发需求二十多个资源模型接口模式几乎相同。他们把这活儿拆成流水线任务卡由架构agent先统一生成数据模型和接口模式然后三个实现agent并行填不同的资源模块测试agent自动补单测审查agent查安全隐患。原来估计两周的排期实际一周出头就出了可提交的代码人工review只需要重点看几个不常见资源的不同处理逻辑。这类场景之所以能跑通是因为“输入边界清楚、输出规格明确、返修标准固定”。流水线的本质是确定性流程它最喜欢的也是确定性问题。5.2 不太适合的场景与低成本起步方案反过来有些场景我劝你别上这套流程。五百行以内的小脚本拆流水线纯属过度设计——人工写半小时的事流水线搭一上午。还有高度耦合的遗留系统接口边界根本定义不出来架构工位第一步就会卡死。另外处于探索试错阶段的原型今天定义接口明天就推翻流水线的“验收标准”反而成了阻碍。如果你不确定团队适不适合可以先来一个最低成本的试水只引入“代码审查subagent”和“测试补全subagent”两个工位服务人工编码流程。即程序员照常写代码写完自动触发审查agent给意见、生成测试框架人工确认后合入。这样做不需要重构开发流程也不改变团队的协作方式却能让你快速感受到“agent在固定工位上干活”和“agent接管一切”的区别有多大。5.3 成本与质量怎么衡量最后聊聊大家最关心的成本。我按一次典型的小型功能模块五工位全跑统计过大约消耗2万token左右运行时间在几分钟级别具体取决于模型速度和并发数。费用上大约相当于普通办公场景下几杯咖啡的钱但换来的是“一版能提交的代码”。更值得关注的其实是时间分配变化编码时间明显下降从原来的几个小时缩到几十分钟但review时间会从零变成十五到二十分钟——这其实是被重新分配了因为以前人工写的代码也要review只是没人在意罢了。真正的成本是返工一次返工大约要重新消耗三分之一的流水线费用所以重试上限必须严格限定。我的个人判断标准很简单如果连续三次实验你有两次愿意合入subagent生成的代码那这套流程对你的项目是划算的如果总是推翻重来别急着换更强的模型先排查是提示词设计问题还是任务边界本身没定义清楚——多半是后者的责任。最后再分享一个提升效果的小技巧。在实现工位的提示词里加一句“先输出你的实现计划每步不超过三句话然后才开始写代码。”这一步能让返工率直接砍半。原因是很多代码问题在计划阶段就会暴露如果agent的计划里压根没有“处理超时重试”这步你甚至不用看它写的代码就能断定这个功能没做超时处理。让AI把自己的思路先摊开是流水线上最便宜的一道路检。