夜雨聆风学习资料网

ARTICLE · 1137615

AI 代码一碰就炸?Claude Code 3 道关卡

AI 代码一碰就炸?Claude Code 3 道关卡

先还原一个评审现场。

一次前端交付,改动跑起来演示正常,页面交互流畅,实现会话里的自检也没报错。评审会话拿到 diff,干净上下文只读代码,五分钟后退回:两处状态更新没有对应测试,一处边界条件处理依赖了组件的内部实现,一旦组件升级就会碎。实现的人自己看过三遍 diff,没看出来。这不是水平问题,是实现方的上下文里全是「我为什么这么写」,评审方没有这些预设,只看「这么写会怎么碎」。

「看起来能跑、一碰就碎」的交付,我们靠评审拦下过不止一例。这类交付有一个共同来源:合入的判断依据是 AI 的完成声明,关卡缺位。这篇讲的就是关卡:三道质量关卡,加两个长期机制(spec 会话、三层记忆)。前两篇《提示词技巧 7 招》管单次交互怎么写、《vibe coding 技巧 12 招》管会话动作怎么做,这篇管的是更硬的问题:AI 写的代码,凭什么敢合入。

答案不靠任何人的自觉。提示词会忘、状态会飘、赶工期的时候人人都想跳过检查,所以这三道关卡全部做成机制:测试默认做、评审独立做、扫描机器做。这套机制一半来自 Claude Code 官方文档的推荐实践,一半来自团队事故后的固化,两部分都在日常交付里跑过验证,没有一条是听起来有理的纸上规范。

三道关卡在交付流程里的位置:第一道卡在写代码的同时,测试跟实现一起出来;第二道卡在提交之前,独立会话审 diff;第三道卡在对外发布之前,机器扫产物。三个位置对应三类风险:行为变了没人知道、盲区没人看见、坏习惯混进对外内容。风险各归各位,一道关卡只管一种。位置卡得准,每道关卡只花几分钟。

一、第一道关卡:测试默认做,不是可选项

做法定死一条:只要改代码,单元测试和端到端测试就是交付内容的一部分,不是单独排期的可选项。顺序也有讲究:先写特征测试锁定现状,再动手重构,最后补新测试覆盖新行为。

为什么顺序不能反。直接重构等于在没有安全网的高架上换桥面:改完了,没人知道哪些行为变了。特征测试先行,等于先把当前行为拍成快照。重构过程中测试红了,就是行为变了,当场定位。这套顺序是成本中心项目用真金白银换来的教训:那个项目反复延期、质量不稳,这套顺序是成本中心项目用真金白银换来的教训。那个项目反复延期、质量不稳,症结不在人手也不在工具,在测试始终是「有空就补」的可选项。复盘下来落点就是这条:测试是可选项的时候,赶工期的测试永远是第一个被砍的,而测试被砍的下一个迭代,bug 数就会把工期吃回去。

机制化之后,这条要求固化进了 skill,AI 编码前会自动加载遵守,不存在「这次先不写」的协商空间。检查不依赖记性,这是第一道关卡的全部要义,跟《提示词 7 招》里「验收写进提示词」是同一个原理的团队版:个人把验收埋进指令,团队把验收做成默认。

特征测试长什么样,拿前端的字段排序举个例子:不改任何逻辑,先写一组测试把现有排序行为钉死(数字字段按数值排、空值沉底、同值稳定序),全绿。然后才允许 AI 动排序逻辑,动完这组测试还绿,说明既有行为没变;新行为的测试另补。这组「钉现状」的测试就是安全网,AI 重构时它在下面接着。

单测和 E2E 的分工也定死:单元测试管逻辑分支,跑得快,AI 每轮改完自己跑;端到端测试管关键路径,跑得慢,提交前跑一遍。AI 交付时两样都要绿,只绿一样不算完成。

反例就是「测试后补」:先合入功能,测试单独立项排期。排期永远排不上,半年后这块代码没人敢动,因为没人知道动了会碎什么。

二、第二道关卡:一个写,一个查,上下文必须分开

Writer/Reviewer 模式的核心不是「多看一遍」,是评审方的上下文和实现方不一样。实现会话里装满了设计取舍和历史尝试,评审会话是干净上下文,只读 diff,只回答一个问题:这份改动会怎么碎。

具体运转分两块。并行审查:大量读文件但不产生改动的任务(接手新项目做代码分析、批量文件审查),交给 subagent 在独立上下文里跑,读完只回摘要结论,主会话不装这些文件内容。团队的前后端并行审查就是这么跑的:两个 subagent 分别读前端和后端代码库,各自核对接口约定的一致性,前端调的每个地址后端要有实现、参数结构要对得上,读完各回一份摘要,人拿两份摘要做决策。原本两天的通读,压缩到二十分钟的摘要比对。subagent 的调度机制我单独写过源码对比,见《Subagent 调度源码对比》,需要文件级隔离再配 git worktree,见《git worktree 隔离并行工作法》。组织级把同一件事推得更远:淘天海外把评审对象从文档换成机器可执行的 Spec,粒度压到一条群消息,人只守三道确认关卡,见《AI 写了 85% 的代码,交付却没变快》。

交付评审走双模式:这次提交改的是还没实施的计划,就评审计划本身;改的是代码,就评审代码 diff。代码评审的第一道关卡永远是第一道关卡本身:有没有对应测试。没有,直接退回,其余问题看都不看。有测试的提交再往下看边界条件、实现方式、和既有约定的冲突。

评审会话的提示词就一句:「只读这份 diff,回答两个问题:这份改动会怎么碎;有没有对应测试。不要看实现过程,只看代码本身。」退回的流程也固定:评审方列出问题清单,回传给实现方修改,改完重提,评审方再看。两个会话各干各的,中间传的只有 diff 和问题清单,谁也不进谁的上下文。

同一族还有个批量形态:非交互批处理。重复性任务(给五十个文件补注释、批量核对命名规范)不必一个个开交互会话,先让 AI 生成文件清单,再用命令行模式写循环逐条执行,输出落盘汇总。人只在清单和结果两头出现,中间全自动。

为什么独立上下文这么值钱。实现方看不见自己的盲区。原因在上下文污染:他知道自己每行代码的「为什么」,于是每行代码在他眼里都是合理的。评审方没有这些「为什么」,只看得到「是什么」,预设为零,问题就藏不住。这也是为什么评审必须是独立会话,同一个会话里「再检查一遍」不算评审:同一上下文里,AI 检查自己刚写的代码,盲区原样复刻。

三、第三道关卡:对外产物,机器扫描拦人

前两道管代码,第三道管一切对外产物:方案文档、博客文章、对外说明,全挂机器扫描,扫描出禁用词直接拦下,不许发出。

写文档和写代码是同一个道理:靠检查,不靠自觉。人眼审稿会累、会漏、会「差不多得了」,机器不会。我这个博客全站 56 篇文章做过一次系统性清理,从清理结果里归纳出一份 AI 味禁用词表,做成了扫描门禁:此后每篇文章发布前必须过扫描,词表命中就打回,人工改完再过。今天这篇和前面两篇,都是先过扫描再交到你面前的。

这条关卡的价值在「拦」的确定性。AI 生成内容有固定的坏习惯:空洞强调词、机械对仗、模板化开场。这些词人眼看两遍就脱敏了,机器扫一百遍还是逐字报。团队对外的一切正式文案挂上扫描之后,「文风漂移」这件事就从复查清单上划掉了。

词表怎么建:从你自己被坑过的稿件里归纳。拿一批觉得「读着不对」的旧稿,把反复出现的词圈出来,这就是第一版词表;此后每次人工改稿时顺手补新词,词表随使用生长。要留两类误报的口子:专有名词和有实质语义的用法标记保留,技术术语按语境判断。词表不求全,求每次命中都值得改。

扫描挂在哪:个人挂编辑器的保存动作或提交前钩子,团队挂 CI 流水线,时机只有一条原则:卡在提交动作上。写完就扫会打断心流,发出去之前才扫又嫌太晚,提交那一刻最顺。

三道关卡到此齐了。它们的共同结构值得点破:每一道都是「机制替代自觉」:测试默认做替代「记得写测试」,独立评审替代「自己再查一遍」,扫描门禁替代「发前通读一遍」。自觉是会波动的资源,机制不波动。

四、spec 会话:讨论归讨论,实施归实施

大功能开工前,先让 AI 采访你:需求边界、异常流、外部依赖、数据兼容、验收标准,一个一个问题问完,写出一份完整 spec。然后开一个新会话,只读 spec 实施。实施会话的启动指令也固定:「只依据这份 spec 实施,spec 没写的按项目约定,两处冲突以 spec 为准,拿不准的停下来问。」四句话把实施会话的边界划死。

两个纪律缺一不可。新会话的上下文是干净的,前期讨论里的废弃方案、走过的弯路、临时起意的想法,全都不会跟进来;spec 必须自包含,点明涉及的文件、接口、改动范围、验收方式,实施会话不需要翻讨论记录就能开工。两条合起来,实施阶段就不会被前期讨论带偏,AI 不会突然捡起三小时前讨论过又否掉的方案,因为那个方案根本不在它的上下文里。

采访的问题清单给个起步版,四组问下来 spec 基本就齐了:功能边界与异常流(不做什么和做什么一样重要)、外部依赖(调谁的接口、谁调我)、数据与兼容(表结构动不动、旧数据怎么办)、验收标准(什么情况下算完成,能不能写成断言)。验收写不成断言的需求,退回去重新想,这条和《提示词 7 招》第一招同源。用采访取代自己直接写 spec,原因是 AI 问得比你想的全:功能边界之外,它会问非功能约束(并发量级、响应要求)、兼容影响(旧数据、旧接口)、失败处理(下游挂了怎么办),这些偏偏是人写 spec 时最容易漏的部分。让它问,你答,spec 从问答里长出来,比对着模板硬填完整得多。

spec 的固定字段:背景一段话、涉及文件清单、接口约定、改动范围、明确不做的部分、验收断言。六个字段填不出来的 spec 是没想透的 spec,先补齐再开工。

这个做法和《会话卡》里的契约卡、五柱体系里的 spec 契约柱是同一条线:聊天记录当不了需求文档,能当需求文档的是写下来的 spec。区别只在小功能用一张卡,大功能用一个专门的采访会话加一份完整 spec。

五、三层记忆:约定放对层,别写满

长期机制的地基是记忆文件,分三层,各管一层,都不放能从代码里读出来的内容。

CLAUDE.md,项目级约定:构建命令、代码风格、测试跑法、分支方式。每次会话自动加载,不依赖人记得交代。adapter.md,项目专属事实:框架选型、常用命令、目标分支、组件库。约定不变,事实按项目填,换项目时 adapter 换掉、约定保留。为什么约定和事实要分开两层:约定是跨项目稳定的(测试先行、评审独立),事实是单项目易变的(用哪个框架、哪个分支)。混在一层里,换项目就得整个重写;分开之后换项目只动 adapter,经验完整平移。AGENTS.md,工作台级约定:跨项目的工作习惯,任务记录方式、文档受众、周报口径。

修剪按月做,三个动作:删掉模型已经能自动做对的(脚手架升级后构建命令不用再交代)、合并语义重复的条目、把失效事实改掉。修剪纪律和写入标准是同一条:模型不需要指导也能做对的内容,删掉。写满约定等于没有约定,模型在四十条规则里找重点的能力,和在四条规则里找重点的能力,是完全不同的两回事。CLAUDE.md 过载的反面教材见这篇最后一节的反模式表。

每层给三条真实条目做参照。CLAUDE.md:构建用 mvn package、测试跑法是 mvn test 加前端 vitest、分支用短命特性分支。adapter.md:框架 Spring Boot 3.2 加 Vue 3、目标分支 release/2.4、组件库用项目内维护的那套。AGENTS.md:任务完成写当周记录、对外文档默认受众是研发、周报从记录汇总。三条一对照,哪层放什么就清楚了:约定放上层,事实放中层,习惯放下层。

第三层上挂一个实用的协议:任务记录。每次交代的工作,AI 主动写入当周记录,周报时直接汇总。跨会话失忆是常态,隔三天回来接着干活,背景全在记录里,不用重新交代一遍。配套的三个小命令顺手记下:@ 引文件把内容带进上下文;/context 查看当前会话的上下文占用;/permissions 把常用只读命令加进白名单,减少确认打断。

个人的最低配置:三道关卡的去团队化版本

三道关卡听起来像团队规格,个人开发者有对应的最低配置,成本十分钟。

第一道,测试默认做的个人版:改逻辑前先让 AI 写特征测试钉现状,这条写进你的常用提示词。第二道,独立评审的个人版:实现完成后开一个新会话,贴上 diff 让它只找「会怎么碎」,两分钟的事。第三道,扫描的个人版:对外文案发布前过一遍你自己维护的禁用词列表,拿本文第三节的办法从旧稿里归纳。

顺序比规格重要。最低配置先跑一个月,等它变成肌肉记忆,再往上加规格。什么时候往上加规格,看三个信号:返工里出现「测试没拦住的行为变化」,把特征测试加进默认流程;评审开始发现跨模块的问题,给评审会话配上完整的项目约定文件;对外文档多到记不清哪些扫过,把扫描挪进 CI。信号驱动,不预先过度设计。关卡这个东西,粗糙但存在的,永远好过精致但不存在的。

反模式速查:四种「看起来没事」

反模式
长什么样
解法
大杂烩会话
一个会话里任务 A 穿插任务 B 再回到 A,上下文全是噪音
一个任务一个窗口;已经杂了,无关任务之间 /clear
反复纠正
纠正两次仍不对,上下文被失败方案污染
/clear 重来,带着教训写更好的初始提示词
CLAUDE.md 过载
规则越写越多,重要信息被淹没
果断删;机器能推断的内容删掉或改成检查
憋着不打断
明知理解错了还让它做完,等结果出来再返工
Esc 立即打断,说清错在哪,重给指令

这四条一半来自官方文档的常见问题归纳,一半来自团队实践。它们和三道关卡是同一枚硬币的两面:反模式是关卡缺位时的自然结局,关卡补上,反模式自动消失。

顺带三个关卡失效的信号,出现任何一个就该回头修关卡:评审连续五次全是小问题,说明第一道测试关卡漏了,评审在做测试该做的事;扫描命中率降到零,先怀疑词表过期,不是庆祝文风变好;spec 写完没人看第二遍,说明采访环节在走过场,退回去重新问。关卡会松,松了就紧,这本身也是条机制。

三道关卡速查表

收藏用。和前两篇的速查表凑成一套,单看哪篇都能对表自查。

关卡/机制
卡在哪
关键做法
测试默认做
写代码的同时
特征测试锁现状 → 重构 → 补新测,单测 E2E 都绿才算完成
独立评审
提交之前
干净会话只读 diff:会怎么碎、有没有测试
扫描门禁
对外发布之前
禁用词表机检,命中即拦,挂在提交动作上
spec 会话
大功能开工前
AI 采访写完整 spec,新会话只读实施
三层记忆
长期
约定进 CLAUDE.md、事实进 adapter、习惯进 AGENTS.md,月度修剪
任务记录
每次交代工作时
AI 主动写当周记录,周报从记录汇总

结论:提示词管单次,机制管长期

三篇连起来看是一个完整的体系。写提示词时,验收、上下文、节奏写进第一条指令,这是《提示词技巧 7 招》;会话进行中,换窗、验收、止损、防删,这些动作习惯是《vibe coding 技巧 12 招》;而把时间尺度拉长到一支团队、几十个需求,靠的就不再是任何一次交互的质量,是这道关卡体系:测试默认做、评审独立做、扫描机器做,spec 隔离讨论与实施,三层记忆托住所有约定。

有人担心关卡会拖慢交付。实测的体感相反:三道关卡拦住的返工,远多于关卡本身花掉的时间。一次被评审退回的交付,修改只要十分钟;合入之后在生产环境碎掉,定位加修复加善后,半天起步。关卡相当于把减速带修在了弯道之前,省下的全是事故处理。

个人用 AI,提示词的好坏决定一次交付的成色;团队用 AI,机制的健全度决定第一百次交付还能不能保持第一次的成色。前者的上限很高,后者的下限很高,而工程这件事,说到底比的是下限。三道关卡的成本都不高——一条默认规则、一个独立会话、一份扫描配置——换的是「敢直接合」这三个字,这场交换怎么算都划算。。

往期关联

  • 《AI 写了 85% 的代码,交付却没变快》:组织级版,评审对象换成机器可执行的 Spec,人只按三次确认键
  • 《Claude Code 提示词技巧 7 招:AI 一次做对,省下一整轮返工》:写法层,验收、上下文、节奏怎么写进第一条指令
  • 《vibe coding 技巧 12 招:少返工、省 token、防误删,一招管一段》:动作层,开验停防攒的会话习惯
  • 《Claude Code 裸聊会翻车:单轮 11 倍消耗与五根工程柱子》:体系层,三道关卡背后那根「测试门禁」柱怎么立

📖 完整原文:posts/ai-code-quality-gates/

相关学习资料