写在前面
之前写过两篇工具指南:Claude Code 使用指南讲 CC 的命令、权限与配置,Codex 使用指南讲 Codex 的沙箱、审批与迁移差异。它们回答的是"这个工具怎么用";这篇文章回答另一个问题——工具会用之后,工作该怎么组织。
这段时间我把 AI 编程从"对话式补全"用到"带着多个 agent 做跨周的大任务",被迫沉淀了一套工作流。越用越清楚一件事:AI 的能力上限很高,但可靠性不会随能力免费到来,它需要一套工程化的兜底体系——就像你不会因为某个人很聪明,就把生产库密码交给他。
这套工作流的主线可以概括成三句话:
- 让事实可查:AI 的每个关键论断,都能被一条命令或一份文档核实;
- 让边界成文:做什么、不做什么,写在文档里而不是靠默契;
- 让验证可复现:成功与否由命令输出和测试判定,不由 AI 的自述判定。
全文围绕这三句话展开:先认清失败模式(一),再搭工作台(二),然后把大任务拆成文档工程(三),建立审查与验证的闭环(四),进而做多 agent 分工(五),把经验沉淀为 skill 和自动化约束(六),第七节把全套流程串成可以照做的流水线,最后以一点反思收尾(八)。
适用读者:已经在日常使用 Claude Code、Codex 等 agent 工具,想从"小修小补"进阶到"把大任务托付出去"的开发者。文中以 Claude Code 为主线、Codex 为辅(主要作为交叉审查的另一方出场),概念可以迁移到其他 agent 工具。
一、认清失败模式:幻觉、越界修改与假验证
大多数 AI 编程的挫折,不是因为 AI 笨,而是因为它以三种可预测的方式出错。先认清失败模式,后面的技巧才有落点——所有防线都是修在这三个地方。
1.1 幻觉:一本正经地编造
表现:引用不存在的 API、配置项、参数或文件路径,给出看似合理实则拼凑的用法。幻觉不是偶发 bug,而是语言模型的固有属性——它在"预测合理的文本",不在"陈述事实"。
检测信号:
- 引用了仓库里不存在的文件或符号(
rg一下就知道); - API 签名与官方文档对不上;
- 语气笃定但给不出出处,或用"应该是支持的"这类含糊措辞。
处置:要求 AI 给出论断的出处——文件路径加行号,或官方文档链接;用发现命令当场核实。预防:改动前先做代码走读(见 3.2),让 AI 的论断锚定在真实代码上,而不是想象上。
1.2 越界修改:顺手多做了一点
表现:任务只要改一个函数,它顺手统一了整个文件的命名;或者顺手格式化整个文件、重排 import、动了没让它动的模块。AI 没有"这不在我的任务里"的本能,边界不清时,它的默认行为是自行补全假设。
检测信号:git diff --stat 里出现超出任务范围的文件;diff 里混着大量与任务无关的格式变更。
处置:先止损,再决定回滚还是修复(见 2.2)——暂停写入、检查 diff,保留已有人工改动;确认本轮改动可以整体丢弃后,再回到干净锚点,重新下一次边界更明确的任务。预防:在方案文档里写明非目标与禁区(见 3.4),用 worktree 分开任务工作目录(见 2.2)。
1.3 假验证:自称通过
表现:声称"测试已通过"“已验证可用”,但实际没跑、跑的是别的命令,或者选择性引用了输出。这不一定是有意欺骗——AI 可能把"应该会通过"的预期当成了事实陈述——但后果一样:你基于一个不存在的绿灯放行了代码。
检测信号:说不出执行了哪条命令、给不出原始输出;执行耗时与任务量不匹配;输出内容与代码现状矛盾。
处置:要求粘贴原始输出,自己复跑同一条命令。预防:验证脚本化(见 4.4),“通过"必须附带命令与输出。
1.4 一张速查表
| 失败模式 | 检测信号 | 处置 | 预防 |
|---|---|---|---|
| 幻觉 | 引用不存在的文件/API;语气笃定无出处 | 要出处,用 rg 核实 | 走读先行,论断锚定真实代码 |
| 越界修改 | --stat 超出任务范围;混入格式噪声 | 先保留已有工作,再决定回滚范围 | 非目标与禁区成文;worktree 分目录 |
| 假验证 | 无原始输出;耗时异常;输出与现状矛盾 | 复跑同一条命令 | 验证一条命令化,以输出为准 |
三种失败模式有一个共同的工程问题:模型的回答本身不能证明事实正确、改动合规或验证成功。所以防线的设计思路是改造环境:事实可查(文档与走读)、边界成文(方案文档与隔离)、验证可复现(脚本与测试)。后面各章,就是把这三件事做扎实的具体做法。
二、搭建工作台:worktree、共享文档与会话管理
2.1 给 AI 配三层记忆
AI 的工作质量取决于它记得什么。按生命周期,我把它的记忆分成三层:
| 层 | 载体 | 生命周期 | 适合放什么 |
|---|---|---|---|
| 会话记忆 | 上下文窗口 | 最短:compact 折叠、超限截断、新会话不继承 | 当前任务的即时状态 |
| 项目记忆 | CLAUDE.md / AGENTS.md(入库) | 与仓库同寿,团队共享 | 构建命令、代码约定、仓库礼仪 |
| 个人记忆 | 本地共享文档目录(不入库) | 跨仓库、跨任务长期积累 | 走读笔记、任务文档、个人经验库 |
前两层两篇指南里讲过,这里重点说第三层。总有一类知识不适合入库:个人笔记、带私有信息的走读、与具体仓库无关的方法论。但它们恰恰是 AI 最需要的背景。我的做法是:在所有仓库之外维护一个公共文档目录,通过 Windows Junction 以 docs-ref/ 的名字接进每个 worktree——本地留存、全局共享、Git 不感知。怎么搭见 2.3 和 2.4。
2.2 git worktree:一任务一分支一目录
多任务并行时,一个工作区只能 checkout 一个分支,几个 AI 任务会互相踩。git worktree 让同一仓库同时挂多个工作目录,各自在不同分支。下面的 Git 命令可在 PowerShell 或 Bash 中执行;先在已有提交的仓库根目录创建任务分支,要求分支名与目标目录尚未被占用:
| |
与 AI 协作时,这套结构特别合身:
- 一会话一 worktree:每个任务有独立的工作文件、索引和
HEAD,减少直接覆盖彼此改动的机会;但 worktree 不是权限沙箱,agent 仍可能通过路径访问其他目录,分支引用、对象库及部分配置也由各 worktree 共享; - 故障范围更清楚:先检查本任务的改动,再决定修复还是从已知提交重新开始。共享文档、数据库和外部服务仍可能受其他任务影响;
- 为回滚保留锚点:每个验证过的小步保存为提交。
git reset --hard会丢弃已跟踪文件的未提交改动,还可能覆盖挡路的未跟踪文件;无目标参数时只是重置到当前HEAD,不会自动寻找上一个正确版本。执行前必须核对目录、目标提交和保留范围;混有人工改动时,应先单独保存或只撤销明确属于本任务的部分。
任务完成、需保留的内容已保存后,在主工作目录执行 git worktree remove ../myproject-task3 清理入口。它通常拒绝移除含未提交改动或未跟踪文件的 worktree;不要用强制删除掩盖尚未确认的内容。忽略文件也要单独检查,不能把 Git 状态干净等同于目录里没有需保留的数据。
2.3 共享文档目录:内容一份,入口各建
结构:公共文档目录放在仓库外(比如 D:\docs),每个 worktree 里放一个名为 docs-ref 的 junction 指向它。所有任务共享同一份文档,零复制。
创建 junction 前,确认目标目录 D:\docs 已存在、当前用户有相应访问权限,且 worktree 根目录下尚无 docs-ref 入口。下面二选一:第一条在 PowerShell 执行,第二条在 CMD 执行。
| |
| |
选 junction 而不是符号链接,是因为它不需要管理员权限或开发者模式,且只能指向本地卷,行为可预期。
然后让 Git 忽略它。先用这条命令定位当前实际生效的 exclude 文件:
| |
在其中加入两行:
| |
这里有个实测细节:exclude 文件是各 worktree 共用的——在 linked worktree 里执行上面那条命令,解析到的仍是主仓库的 .git/info/exclude(git 2.55 实测;以你机器上这条命令的输出为准)。所以 exclude 只需要配一次,全部 worktree 生效。但 junction 本身是工作目录里的文件,不会自动出现在其他 worktree——每个新 worktree 都要各建一次 junction(以及 2.4 的 .ignore)。
2.4 让 AI 读到被 Git 忽略的文件
docs-ref/ 被 Git 忽略后,文件选择器可能不再列出其中的文件。要区分三件事:Git 是否跟踪、搜索是否列出、工具是否有权读取。下面讨论搜索可见性,不把忽略规则当作访问控制。
Claude Code:设置选择器的 respectGitignore。当前官方设置参考支持把该键写入用户、项目、项目本地或托管设置。只想影响当前项目时,可以在 .claude/settings.local.json 中合并下面的键,不要覆盖文件内已有的其他配置:
| |
终端里的 /config 也提供 Respect .gitignore in file picker 开关,它写入 ~/.claude.json;当前版本只有在设置文件未指定此键时才使用该回退值。旧版本的能力和优先级可能不同,以所用版本的设置参考与实际候选结果为准。
这个开关只影响 @ 选择器的候选列表,不是访问控制:被忽略的文件在权限允许时仍可通过明确路径读取。关闭过滤可能让 .env 等敏感文件进入候选;不再需要时恢复 true。配置后仍应实际搜索目标文档,目录链接能否被遍历是另一项条件。
Codex 侧的候选办法:.ignore 反向规则(按路径)。对使用 ripgrep 的搜索,.ignore 可重新包含被 Git 忽略的路径;ripgrep 的优先级为 .rgignore > .ignore > Git 忽略规则。但这不能证明 Codex CLI、IDE 与桌面端的 @ 选择器行为相同。可以在 worktree 根目录的 .ignore 中追加下面两行,保留已有规则,再验证当前客户端是否列出目标文件:
| |
Git 不读取 .ignore,所以原有 Git 忽略规则保持生效。可先在 worktree 根目录执行 rg --files --hidden --follow docs-ref,检查输出中是否出现预期文档;--follow 用于遍历链接目录,忽略规则本身不会开启链接遍历。这只能验证该条 ripgrep 命令,随后仍要在 Codex 的 @ 选择器中单独验证。若选择器不支持,直接提供明确的文件路径,请 agent 在权限允许时读取,不要把命令行搜索成功当成客户端验证成功。
两种方案的取舍:
| 维度 | CC respectGitignore | .ignore 反向规则(须验证客户端) |
|---|---|---|
| 生效范围 | 当前支持按设置文件选作用域;/config 写全局回退值 | 所在目录及子目录,依赖搜索实现 |
| 粒度 | 所选作用域内统一切换 | 按路径精准 |
| 安全面 | 敏感文件可能进候选 | 只放开明确列出的目录 |
| 维护成本 | 检查作用域与设置优先级 | 本文采用不入库配置,每个新 worktree 建一次 |
我的用法:优先按路径放开所需文档,客户端不支持时使用明确路径。CC 侧优先限制到所需项目,仍要留意候选范围。敏感文件应移出共享资料目录,并由工具权限与文件系统权限限制访问;不出现在候选中,并不代表 agent 无法读取。
2.5 会话命名:把会话当任务索引
会话是最小的工作单元,也是最容易失控的东西——并行任务一多,/resume 列表里全是分辨不出归属的会话。命令层面两篇指南都讲过(CC 的 /rename 与 claude -n,Codex 的 /rename 与 codex resume),这里只补一条命名约定:
| |
例如 3-gRPC改造-方案讨论、3-gRPC改造-清单执行。它和 3.3 的文档编号共用一套分类号,效果是:会话、文档、worktree、分支四者同名互查——“那个 gRPC 任务的方案会话"不需要回忆,按分类号就能定位。文件名里的 任务N- 只是人类可读标识,不要求与分类号相同。像对待分支一样对待会话:一个会话一个用途,用完归档,不把新话题混进旧会话。
三、大任务的文档工程
单人用 AI 做小任务,对话就是全部;任务一大,对话就不够了——上下文装不下,人记不住,AI 更记不住。这一章是全文的核心:用一套文档体系,把"一个大任务"变成"一串可独立托付的小任务”。
3.1 为什么必须拆
- 上下文有限:一个跨周的大任务塞不进一个会话;就算塞得进去,经验上长上下文里的指令遵循也会变差,早期的约束到后期就"忘了”;
- 失败模式被放大:任务越大,幻觉与越界修改的爆炸半径越大,审查也越难——没人审得动一个三千行的 diff;
- 可验证性:拆小之后,每一份产出都能被独立验证、独立回滚。
拆的粒度用一个标准卡:一个任务 = 一次可验证的交付。写不清验收标准的,说明还拆得不够小。
拆完之后自然形成三层:专题 → 任务 → 清单项。专题是一段时间要完成的一个目标,由几个相关的任务组成;任务就是上面的可验证交付;清单项是任务内的执行步骤。三层的目录与命名规则见 3.5。
3.2 文档三件套:代码走读、实现方案、任务清单
一个专题到任务的完整链路包含三类文档,各管一段。它们是工作流角色,不要求每个任务各复制一套,也不要求物理上放在同一层目录:
代码走读(现状):让 AI 系统性地读代码,产出"这个系统怎么工作"的结构化笔记——模块划分、关键类型、数据流、约定与坑。走读是所有后续工作的地基:它让 AI 的论断锚定在真实代码上(防幻觉),也让人确认"AI 理解的系统"和"实际的系统"是同一个。改既有代码时,明确要求新代码沿用走读确认过的既有风格,而不是它自带的默认品味。重量级专题的走读放在专题级共享;跨专题复用的走读再按主题沉淀进 common/,不在每个任务目录重复复制。
实现方案(设计):改什么、怎么改、分几步、每步的风险与验证方式。AI 起草、人审查拍板(见 4.1)。方案归属具体任务,是任务期间最高权威的文档,后续所有会话以它为准。
任务清单(执行):把方案拆成可勾选的步骤列表,一步一项,写明验证方式,并给每项一个 TODO 编号作为引用键(见 3.6)。每个任务一份独立清单,它是跨会话的进度账本:新会话接手时先读清单,做完一步勾一步;多 agent 协作时它还是共享状态(见第五章)。
三者的关系是一条流水线:走读喂方案,方案拆清单,清单驱动会话。文档在这里的角色,是 AI 的外置记忆——会话会丢,文档不会。
3.3 编号与命名:文件名自带顺序和语义
文档一多,“哪个任务、哪份文档"就成了日常检索。我用一套固定的文件名结构:
| |
例如:
| |
规则只有三条:分类内的序号零填充,让同一分类的文件按字典序排列;任务名人类可读,内容可变——名字里的数字(如"任务1”)只是可读标识,不必与分类号对应;类型后缀区分角色——走读、实现方案、清单、审查是最低词表,实际按需生长:范围清单、技术决策、基线、新旧对比、复审、检查表、操作指南、缺陷与风险登记……词表是开放的,约束只有一条:同一类文档始终用同一个类型词。重量级专题里,分类号对应专题内的阶段或任务目录;轻量专题平铺时,分类号先表示专题本级文档,其后按任务分组,具体见 3.5。若分类号达到两位数,也应统一宽度,例如 03.01,避免字典序把 10 排在 2 前面。结构固定、内容随意——它不是什么规范,只是一个用了就回不去的约定。
编号之外再补一条引用规则:正文互引用《文档标题》,不引用文件名。标题稳定,文件名可能调整;引用与文件名解耦,改名就不破坏引用——对人,索引是稳定的;对 AI,上下文里的锚点也是稳定的。
3.4 任务文档模板:必备章节
方案文档我固定用一套章节骨架:
| |
每个章节都有存在的理由:
- 背景与目标:为什么做、做成什么样。AI 知道目标,才谈得上取舍;
- 术语说明:统一叫法。领域词汇的歧义是方案跑偏的隐形原因——同一件事两种叫法,AI 就当成两件事;
- 现状摘要:引用走读结论,不重复铺陈,控制上下文成本;
- 非目标与禁区:不做什么、不许动哪些文件和模块。这是最重要的一章:越界修改的根源,就是方案文档只写了"做什么"。AI 对边界靠推断补全,写明禁区是最便宜的预防;
- 验收标准:怎么算完成,尽量写成可执行的命令或测试(衔接 4.4 与 4.5);
- 风险与回滚:出问题怎么退回来(衔接 2.2)。
再配一个开工仪式:让 AI 复述任务与边界——用自己的话重述目标、非目标、验收标准,然后你再纠正。理解偏差在第一分钟暴露,成本近乎为零;等到审查阶段才发现,返工的是一个会话的产出。
复述之外,还可以主动考它:针对刚读过的代码或方案提几个具体的问题——这个应答超时之后会发生什么?这个字段由谁负责更新?——回答应当附代码位置或可复现实验,再由人抽查。答错能直接暴露走读或方案的漏洞;答对只是理解的证据之一,不能替代后续验证。
3.5 多任务并行时的文档组织
任务多了以后,目录按三级组织:顶层按模块或域分(如 backside/、edgeside/、common/,common/ 放跨模块的背景知识与手册);域内按专题分目录,专题用 yyyymmdd. 日期前缀——时间是专题的天然排序键,日期即启动日,不需要维护发号器;专题内部再组织任务,内部文档一律不带专题前缀,层级由目录树承担,号段只管局部顺序。一棵真实项目的树:
| |
六个要点:
- 号段有分工:重量级专题里,
0.统筹、1.现状基线、2.代码走读是专题本级——统筹是总控账本,现状基线回答"问题是什么",走读回答"机制怎么转",三者各有职责不混写;3起才是任务目录,文件名<分类号>.<序号>.任务N-<主题>-<类型>.md。跨专题可复用的走读沉淀进common/; - 结构随规模伸缩:专题小就平铺——专题本级文档(总览、现状)占前几个号段,其后一个号段 = 一个任务,任务的实现方案、任务清单等文档聚在自己的号段内,不建目录。别为三个文档搭八层楼。平铺与目录是同一分组思想的两个粒度:专题长大后,
2.号段原地升级为2.任务1/目录,文件名一个不用改; - README 是专题的入口:目录结构表、命名规则、每篇一句话摘要、推荐阅读顺序(统筹→基线→走读→任务)。给 AI 的应该是一张地图,不是一摞手册——新会话先读 README,再按需下钻;
- 任务目录的根只放三份核心文档:在上例中是实现方案、范围清单、任务清单;专题级共享走读留在
2.代码走读/,不为每个任务重复复制。这三份是脊柱文档,编号连续、常读常改,扫一眼根目录就该能看清任务全貌。审查记录按轮次越积越多,图片是二进制附件,混进根目录会淹没编号的可读性——所以任务目录内固定三个子目录方案审查/、代码审查/、images/,开工建任务目录时(第七节阶段 1)一并创建。子目录里的文件沿用任务分类号;方案审查与代码审查共用任务内的文档序号和审查轮次序列,不按子目录重新从01或R01起号;图片按内容描述性命名,不发编号(同 3.6 的发号原则); - 资料跟着任务走:厂商 SDK、手册、多版本 DLL 放进消费它的任务目录(必要时再分新版本/老版本);测试日志也归档进任务目录,作为执行证据留存(衔接 4.4);
- 喂给会话的文档只有两类:本任务的目录 + 用得到的走读。上下文最小化,检索沿目录树下钻。
这棵树加上第二章的 worktree,多任务并行就各有各的领地。
3.6 给会被引用的实体发 ID
文件名解决了文档的检索,但还有一类东西也需要被稳定引用:缺陷、清单项、审查意见——它们出现在对话里、提交信息里、审查回归里。口头说"那个超时的 bug",每次都要重新对齐;给它们发 ID,引用就有了稳定的键。
两层结构:
| 层 | 格式 | 适用 | 例子 |
|---|---|---|---|
| 自描述 ID | 大写缩写 + 连字符 + 零填充序号 | 需要脱离当前文档识别;具体作用域由类型决定 | BUG-012、TODO-012、DEC-012 |
| 局部极简 ID | 单字母 + 零填充序号 | 作用域已限定的任务或审查记录内 | 意见 F01、轮次 R01 |
各实体的约定:
- 缺陷
BUG-012:项目级流水。若项目已有 GitHub Issues、Jira 等任务系统,直接沿用它生成的编号,不再维护第二套BUG流水; - 清单项
TODO-012:任务级流水,直接写进清单——- [ ] TODO-012 实现 ACK 重试。做完勾选,编号不变;跨任务引用时写任务3/TODO-012; - 审查轮次
R01、R02:按发生顺序编号——3.04.任务1-gRPC改造-方案审查R01.md。编号只表示先后,不把某个序号固定解释成首审、二审或回归; - 审查意见
F01、F02:单轮文档内的条目;跨轮引用组合成R01-F03——“R01-F03 在 R02 确认已修”。从第一条起就固定宽度,避免条目增加后重编号; - 决策记录
DEC-012(可选):记录"当时为什么选这个方案"及适用背景。决策失效时追加新记录并关联旧记录,不改写已经被历史引用的 ID。
配套两条原则:
- 前缀和作用域共同构成命名空间:
BUG按项目编号,TODO按任务编号,DEC按约定的决策库编号,F只在所属轮次内编号,R只在所属任务内编号。想加新缩写,先写清作用域与唯一发号源; - 发号有门槛:只给会被跨文档、跨会话、跨提交引用的实体发 ID,只在文档内部使用的列表用普通有序列表。口诀:流程性实体发号,知识性实体起名(
common/走读用主题词命名,不编号);被引用才发号,只被阅读不发号。
最后是提交回链:编号的价值一半在发出去,一半在提交信息里——fix BUG-012、fix 任务3/R01-F03、完成 任务3/TODO-012。提交格式仍以仓库约定为准;把作用域一起写上,Git 历史才能成为可靠索引。
四、质量闭环:审查与验证
4.1 方案审查到底审什么
方案是 AI 起草的,但方案审查是人的主场——判断力和品味不能外包。审三层,由浅入深:
- 命名与概念:新名词是否贴合领域、与既有代码一致。命名歪了,后面所有代码跟着歪,纠错成本随时间上升;
- 项目结构:改动落在哪个项目、哪一层;依赖方向对不对;是复用了既有抽象,还是在旁边又造了一个;
- 可行性:方案依赖的关键假设是否成立——真有这个 API?性能量级估过吗?跨平台行为确认过吗?可行性问题在方案阶段发现是改文档,在编码后发现是返工一轮。
审查的输入永远是"方案文档 + 相关走读",不是只看 AI 的一句话总结。
4.2 双模型审查,并且要回归
写和审可以用不同模型。我的常态是 Claude 写、GLM 审,或者反过来;实际使用中,这有时能带来不同视角。但不同模型也会共享盲区,不能保证相互纠错。审查方应独立阅读需求与代码,用文档、源码或实验裁决分歧,不能把两次赞同当成正确性的证明。
审查要输入完整:审查方必须拿到方案文档和完整 diff。知道"意图"才能审出"偏差",脱离意图的审查只能挑表面毛病。
要回归(regression):审查意见修改后,必须让审查方对修改后的版本再确认一次。“改了"不等于"改对了”——修改本身可能引入新问题,也可能改丢了原来的意图。没有回归环节的审查流程,最后一轮意见是没人背书的。轮次与意见可以用 3.6 的记号编号(如"R01-F03 已修,待 R02 回归"),回归对账就有了稳定的引用键。
顺带一提,你正在读的这篇文章就是这么生产的:写作流程定义在 skill 里,两位审阅者读同一版本,任何一方改了正文,另一方就要重新确认——写代码和写文章,质量闭环是同构的。
4.3 diff 纪律
审查代码时的操作顺序,固定成纪律:
- 先看
git status --short,再看统计:用状态检查新增与暂存文件,再分别看git diff --stat和git diff --cached --stat。单独的git diff --stat只覆盖未暂存的已跟踪改动,会漏掉已暂存变更和未跟踪文件; - 再看分文件 diff:先核心逻辑,后配套变更;分别检查
git diff与git diff --cached,未跟踪的新文件直接阅读全文。如果任务已产生提交,还要比较约定的基线与任务分支,不能只检查工作区; - 对大重写保持警惕:AI 偶尔会重写整个文件,而不是打一个精准 patch——内容可能等价,但审查负担完全不同,应当要求它改用最小改动方式重做。
两条配套规则:最小改动原则——只做任务内的变更;禁止顺手格式化——格式化、import 重排、大规模重命名会制造噪声,把真实改动淹掉,审查能力直接归零。格式问题交给格式化工具,单独一次提交。
4.4 验证可复现:一条命令,以输出为准
把 build、test、lint 收进一条命令——make verify、just verify 或一个 verify.ps1,人和 AI 跑同一条。然后是两条铁律:
- “验证通过"必须附执行证据:命令、工作目录、对应代码版本、退出码及关键输出;长日志保存到可查看的文件或 CI 任务,不能只截取成功片段;
- 核对测试是否真的运行:退出码为零还不够,要检查用例数量、跳过项和环境。优先看工具执行记录或 CI 原始日志,并不定期自己复跑;AI 在聊天中粘贴的所谓原始输出仍可能不真实。
这也是 1.3 的制度化解法:把"验证"从对话里的一个说法,变成可复现的机器事实。
4.5 从提示词走向测试
前面所有手段解决的是"怎么让 AI 不出错”,这一节换个角度:怎么让"对"的定义本身离开自然语言。
对能自动验证的需求,把人工确认的验收标准写成测试,能减少反复口述的歧义。但测试通过只证明被执行的断言满足了:漏测边界、错误的预期、过度 mock,都会让错误实现变绿;AI 也可能改弱断言、删除或跳过用例。因此,测试本身要对照需求审查,测试的变更与代码的变更享受同等的审查待遇(见 4.3)。
可以采用测试驱动开发(Test-Driven Development,TDD)的节奏:先把确认过的验收标准翻译成测试,确认它因目标行为尚未实现而失败,再实现到通过,最后在测试保护下重构。对接口已经稳定、兼容性要求明确的任务,还可以先确认对外契约,再围绕契约分批补测试与实现;探索性设计则保留从测试反馈中调整接口的空间。AI 可以降低编写测试的成本,但不会自动解决测试设计、遗留系统可测性或维护成本的问题。
边界也要说清:不是所有验收标准都适合完全自动化。视觉回归和架构规则可以覆盖部分 UI 与结构要求,观感、命名和设计取舍仍需要人工判断。测试与审查互补,审查也必须检查行为是否正确。日常沟通仍然重要;适合自动化的核心需求,则尽量沉淀为可执行的规格。
五、多 Agent 分工:写、审、监控
单会话流程跑顺之后,自然的下一步是并行:任务大到一定程度,一个会话串行做不完,就拆给多个 agent。
5.1 三个角色
- 写码 agent:按任务清单实现,一个任务一个;
- 审查 agent:对每个完成的步骤,对照方案审 diff;
- 监控 agent:盯清单进度、汇总状态,发现卡住或跑偏时向人报告。
5.2 模型搭配的原则
- 写和审尝试不同模型——理由同 4.2,增加视角,但不保证消除盲区;
- 按难度分配审查与监控——机械进度汇总可以先用成本较低的模型;涉及并发、安全或架构的审查需要足够的推理能力,不能只因它是读取任务就降档。
背后是一个实用原则:按风险和实测效果分配模型。把返工、漏检和人工复核的成本一起计算,再判断便宜模型是否真的省钱。
5.3 让分工成立的前提
纸面上画三个框不难,让它真的工作需要四件事:
- worktree 分目录,权限限制写入范围:每个写码 agent 各占一个 worktree;共享资料仍是同一份文件,应明确只读范围与编辑负责人;
- 清单统一记账,更新串行化:每个任务的清单由一个负责人更新,其他 agent 提交结果;若必须多方写入,使用带锁或版本冲突检测的任务系统,避免同时覆盖 Markdown。每个完成项关联代码版本和验证记录,勾选本身不构成完成证明;
- 审查 agent 必须读方案文档:知道意图才能审出偏差(同 4.2);
- 人握着合并权:方案拍板、分歧裁决、最终合并,三个 agent 都不碰主分支。
最后一句实话:多 agent 不是银弹,协调成本真实存在——清单对账、上下文同步、审查排队都是开销。先把单会话流程跑顺(前三章),再逐步并行化;顺序反过来,通常收获一堆混乱。
六、沉淀为基础设施:skill、自动化约束与经验回流
6.1 项目专用 skill:流程写一次,处处调用
识别信号很简单:同类任务第三次出现。发版流程、走读模板、审查清单……凡是每次都要口头交代一遍的流程,都值得写成项目专用 skill——步骤、检查项、输出格式固化成文件,新会话零上下文继承也能按流程走。skill 是三层记忆之外更高一级的形态:不是帮 AI 记住,而是把做法本身固化。比如把 3.4 的文档模板做成 skill,“新任务"一句话就能起全套文档。
6.2 脚本与自动化约束:不靠自觉靠机制
在 CLAUDE.md 里写提交前跑检查,是给模型的指令;把检查接入能阻断操作的 hook 或必需 CI 检查,才能形成可执行门槛。以 Claude Code 为例,PreToolUse 命令钩子可用退出码 2 阻止工具调用,普通非零退出码未必阻断;只打印提醒也不等于拦截,必须实际验证失败路径。
权限 deny 适合拦截已覆盖的调用形式,但命令文本匹配不是完整的安全边界:git push --force 还可能写成 git push -f,或由脚本间接调用。重要限制应结合沙箱、操作系统权限、远端受保护分支和必需检查;本地 Git hook 也可能被跳过。机制能减少越界与漏跑检查,却不能独自判断需求是否正确、测试是否充分。
6.3 经验回流:让踩过的坑只踩一次
新会话不会自动拥有上一会话的完整上下文;Claude Code 的 auto memory 等功能可以保存部分经验,但不能保证所有教训都被准确提取和重新加载。因此,关键规则仍要写成可审查的项目文档或 skill。任务收尾可以固定问一句:
这个任务里学到了什么,是值得写进
CLAUDE.md、skill 或文档模板的?
把答案真写进去。久而久之,CLAUDE.md 会从"仓库说明书"长成"经验库”,skill 从"流程"长成"标准做法"。这本质上是给个人知识做持续集成:知识也要 CI,不回流就腐烂。
七、串起来:一个任务的完整流程
前面六章是零件,这一节把它们装配成一条可以照着做的流水线。先补一条贯穿全程的会话纪律:
对跨天、跨会话的大任务,我默认采用一种工作类型一个会话,换类型就换会话。走读、方案、执行、审查尽量不挤在同一条会话里;同一次审查及其回归可以留在原审查会话中,便于逐项对账。理由有三:
- 上下文干净:每个阶段的会话只装载该阶段需要的材料——走读会话读代码,方案会话读走读,执行会话读清单。前序阶段的探索、试错和被废弃的方案,不会作为噪声留在后续阶段的上下文里;
- 状态主要从文档继承:新会话的第一件事是读文档(走读/方案/清单),必要时再追溯旧会话。文档是筛选过的结论,闲聊是未过滤的过程;
- 上下文故障隔离:执行会话跑偏,不会把试错过程带进方案讨论。重开会话只能清理上下文;已经产生的文件、提交和外部副作用,仍要按 2.2 的边界检查和恢复。
会话名要认真起——它不是标签,是跨会话的检索索引(见 2.5)。阶段正好落在命名约定的"性质"字段里:3-gRPC改造-走读、3-gRPC改造-方案、3-gRPC改造-执行、3-gRPC改造-审查。命名后的会话列表可以辅助定位阶段;任务清单仍是进度的唯一账本。
完整流程如下(单人、多会话形态;多 agent 扩展见第五章):
| # | 阶段 | 会话(性质字段) | 输入 | 产出 | 关键纪律 |
|---|---|---|---|---|---|
| 1 | 准备 | —(主工作区) | 任务描述 | worktree、分类号、任务目录 | 一任务一分支一目录(2.2);任务目录及子目录见 3.5 |
| 2 | 走读 | …-走读 | 代码库 | 走读笔记;可复用部分沉淀进 common/ | 论断锚定真实代码;已有走读先复用(3.2) |
| 3 | 方案 | …-方案 | 走读 + 任务描述 | 方案文档 | 按 3.4 模板起草,非目标与禁区必填 |
| 4 | 方案审查 | …-审查 | 方案 + 走读 | 方案审查/ 中的审查记录、修订后的方案 | 人主审(4.1);修订后要再确认 |
| 5 | 拆清单 | …-方案 续 或新会话 | 定稿方案 | 任务清单 | 一步一项,写明验证方式(3.2) |
| 6 | 执行 | …-执行 | 清单 + 方案 | 代码、检查点、执行证据 | 逐步做、逐步验证;按仓库规则和授权保存提交(4.4、2.2) |
| 7 | 代码审查 | …-审查 | diff + 方案 | 代码审查/ 中的审查记录 | status → 统计 → 分文件(4.3) |
| 8 | 回归 | 审查会话续 | 修订后的 diff | 确认结论 | “改了"不等于"改对了”(4.2) |
| 9 | 合并清理 | 人 + 主工作区 | 任务分支 | 合并、worktree 清理 | 合并权始终在人(5.3) |
| 10 | 复盘回流 | …-复盘 | 全程记录 | CLAUDE.md / skill 更新 | 知识也要 CI(6.3) |
四条使用说明:
- 循环在 6-8:执行、审查、回归转圈,直到清单清空,不是线性走一遍就完;
- 阶段 4 与 7 独立阅读完整输入;条件允许时换模型,增加观察角度,但仍靠证据裁决(4.2);
- 阶段 6 可按清单分批换会话:一个会话做一两项、勾掉、结束,下个会话从清单接着来——清单就是为此设计的进度账本;
- 多任务并行时,整套流程在每个 worktree 里分别运转,降低工作文件互相覆盖的概率;共享引用、配置和外部服务仍需协调(第二章)。
第一次看会觉得这套流程很重。它的适用边界和整篇文章一致:小修小补不需要它,对话就够了;跨会话、跨天、需要审查和回归的大任务,才值得把流水线立起来。
八、瓶颈的转移:读、判断与克制
最后把视角拉远一点。AI 把"写代码"的成本打了下来,但总成本没有消失,而是转移了:
- 读:审查大 diff 成为日常,4.3 的纪律不是讲究,是生存技能;
- 判断:方案拍板、可行性裁决、命名品味——AI 给选项,你给结论;
- 决策:什么托付、什么不托付,成了每小时都在做的选择。
四条收尾的克制:
- 能验证的才敢托付。你对一个领域建立不起验证手段(测试、走读、基准),AI 在这个领域的产出对你就全是黑箱——先造验证,再谈托付;
- 看懂的才敢合入。是否采用 AI 写的代码,取决于你有没有看懂它——看不懂的代码,无论谁写的,都是负债;
- 不是什么都值得 agent 化。一行改动、需要精密品味的重构、解释成本高于动手成本的活,自己写更快;反过来,模板化、重复且容易验证的工作——例如已有范式下的样板代码、测试骨架和接口文档——通常更适合优先尝试,产出仍要按领域风险验证。AI 是工具箱里最锋利的一件,不是唯一一件;
- 吞吐可能放大返工。如果单位产出的缺陷率不变,产出越快,单位时间累积的缺陷也越多;这不是固定倍数的性能结论。纪律的价值随吞吐放大,而不是消失。
还有一条,关于你自己:先自己思考,再和它讨论。执行的过程也是思考的过程,把方案直接外包出去,省下的思考会变成后面付的利息,用得越久越明显。先形成自己的判断,再让 AI 参与验证、修正和优化——与它讨论的往返本身,才是学习和手感留存的地方。
这套做法可以视为 Harness Engineering(本文暂译为“驾驭工程”) 的一种个人工作流实践。这里的 harness 不只是一轮“写代码—跑测试—修错误”,还包括 agent 能看到的上下文、可调用的工具、权限与沙箱、任务状态、审查、验证和恢复机制。全文的 worktree、文档三件套、清单、审查回归、测试与 hook,分别补上这些环节。它们提高结果可验证、可追踪和可恢复的程度,却不保证每次自动得到正确答案;复杂任务仍需要人定义意图并处理无法机械判定的取舍。
这套工作流如果只用一句话总结:把"信任 AI"换成"验证 AI"。工程手段不生产信任,它生产可验证性——而可验证性,才是你敢把大任务交出去的全部底气。