Anthropic 官方教你把手动代码检查写成技能,让它自己查自己修
- AI 改完代码,编译报错、类型检查、测试、linter 这些信号它自己看得见;剩下那几步只有你知道的检查,每次都得你亲手点一遍。
- Claude Code 团队给的做法:把你每次都在点的那几步用大白话写下来,存成一个技能,它就能自己跑、自己修。最小的一个只有十几行。
- 检查写得好只是一半,另一半是它装在哪一层:你想起来才叫、嵌进生成代码的那个技能里、一个技能干完自动叫下一个、挂到每个 PR 上(PR 就是把改动提交给团队合并的那个请求)。四层越往后越省心,也越难改。
- Anthropic 自己的 Claude Code 团队日常跑的是四个技能接力:
/code-review找 bug,/simplify清理 diff,/verify把 app 真跑起来看效果,改动碰了界面就再叫一个自定义的/design对着 DESIGN.md 核一遍。 - 代价也写在明处:技能一旦加载就常驻上下文到会话结束,串得越长 token 烧得越多;而且
/verify和/code-review从 v2.1.215 起只在你开口叫的时候才跑,不会自己开火。
AI 改完代码,哪些检查它自己会做,哪些还得你来
Anthropic 官方团队分享了他们怎么在 Claude Code 里建立验证循环(verification loop):把平时手动做的检查步骤,变成自动化的技能(Skill),让 AI 自己纠错。作者是 Claude Code 团队的 Delba de Oliveira,7 月 22 日发布。
简单来说,验证循环就是让 Claude 写完代码后自己检查一遍、发现问题自己修好,不需要你一直盯在电脑前当监工。
你现在大概是这么干的:让 AI 改一个功能,它说改好了,然后你打开页面点一遍,翻一眼日志,再把浏览器拖窄到手机宽度试试。这几下每次都得你自己做。要交出去的就是它们。
先看 AI 干活的完整流程长什么样。
这张图上有一个正文没提的细节:验证没过的时候,箭头指回去的是「收集上下文」,不是「动手改」。也就是说它不会拿着同一份信息硬改第二遍,而是先回去把情况重新摸一遍,再决定怎么动。
验证这一环,它本来就在做一部分。因为代码库里有一批信号是机器能直接读的:编译器报错、类型检查不通过、测试跑挂了、linter 的警告。这些东西一出现它就看得见,也知道该回头。
麻烦的是另一半,那一半没有任何报错文本可看。
- 编译器报错
- 类型检查不通过
- 测试没跑过
- linter 的警告
- 这个按钮在手机宽度下会不会被挡住
- 这条错误日志有没有把用户的请求体一起写进去
- 这次迁移删了一列,数据有没有补进新结构
- 这个改动合不合团队那份设计规范
右边这一列,没有任何机器信号会替你报警。所以它们每次都落回你手上,变成你亲手点的那几下。接下来要做的,就是把右边这些也写成它能读的信号。
Claude Code 里已经装好的六种检查,各管什么
从零开始写之前,先看看现成的。Claude Code 里已经装好六种,各站在不同的位置,有的要你开口叫,有的自己就跑。
/verify 和 /code-review 从 Claude Code v2.1.215 起,只在你主动调用时才跑;在那个版本之前,Claude 可以自己决定要不要跑它们。文章把 /verify 列在内置验证循环的第一条,容易让人以为它会自己开火,实际上得你开口叫。
还有两个常跟它们一起用的:/simplify 会派四个审查 Agent 并行跑,分别看能不能复用已有的辅助函数、能不能写得更简单、效率如何、以及这个改动是不是做在了正确的抽象层级上;从 v2.1.154 起它不再负责找正确性 bug,找 bug 归 /code-review。/run-skill-generator 则是专门教 /run 和 /verify 怎么在你这个项目上从干净环境把 app 构建、启动、驱动起来。
怎么把你每次都在做的检查写下来
起手第一步是写字。把你每次都在做的那几个小纠正,一条条记下来。
用大白话把「最佳做法」的那个版本写出来,就像你要把它交给一个第一天来的新同事。不用写成文档的语气,写成交代事情的语气就行。
如果你发现自己说不清这个检查到底在查什么,还有个反过来的办法:先问 Claude 这类事情的通行做法是什么,拿它给的版本当底稿,再往上改成你的。你的做法跟通行做法不一样的那几点,恰恰是最该被写下来的,因为那些正是没人会替你记着的部分。
举个例子,这么一条规矩:任何一个删了列、却没有回填步骤的数据库迁移,一律打回。回填指的是把数据补进新的结构里,跟备份是两回事,备份是留后路,回填是保证数据不丢在半路上。
这条规矩死得不能再死,判断标准清清楚楚,但通用 linter 抓不到它,只有你项目自己的检查抓得到。凡是你老得用手盯着执行的规矩,都够格变成一个循环。
一个能直接抄的验证技能,一共十几行
最省事的做法是让 Claude 反过来采访你。装上 skill-creator 插件,然后敲这么一句:
/skill-creator Create a skill for verifying frontend changes end-to-end. Interview me about my workflow.
手写也不难。在项目里的 .claude/skills/ 放一个 markdown 文件,那就是一个技能。最小的例子只有十几行,查的是错误日志有没有带上请求 ID、有没有把请求体写进日志:
--- name: verify-log-hygiene description: Check that error logs include the request ID and never include the request body. Use when the diff touches error handling or logging. allowed-tools: [Read, Edit, Grep] --- Read the error-handling paths in the current diff. For each log call on an error path, confirm it includes the request ID and does not pass the request body, headers, or any user-supplied payload. Report each violation with file:line, then fix it: add the request ID where it's missing and strip the payload from the log call.
最后那句是整个技能的关键:报完不算完,报完接着修。它先给你一份带行号的清单,然后把缺的请求 ID 补上,把不该写进日志的内容从调用里剥掉。少了这半句,它就只是个报警器,报完停在那儿等你动手。
检查放在哪跑,四个位置
检查写出来之后,紧接着的问题是它什么时候开火。四个位置,从你想起来才叫,一路到挂在每个 PR 上。位置一变,同一份检查的性质就变了。
- 谁开火
- 你,手动敲
- 适合
- 横跨多条工作流、但不需要每次都做的检查
- 代价
- 每一次都是你要记得去做的动作
- 谁开火
- 生成代码的那个技能,自动带着跑
- 适合
- 绑死在一条工作流上的检查
- 代价
- 只对你能编辑的技能有效
- 谁开火
- 上一个技能干完,自己叫下一个
- 适合
- 整条开发流程从头跑到尾
- 代价
- 不能再单跑其中一步,token 也花得更多
- 谁开火
- CI,谁提交的改动都跑
- 适合
- 要让全团队都遵守的标准
- 代价
- 每次调整都变成团队可见的事件
单独调用:你想起来才跑
这一档是东西已经做出来之后,你主动敲一下它才跑。
它适合那种横跨很多条工作流、但不需要每次改代码都做的检查。三个典型场景:提交前的一次安全扫描、发 PR 前的一次无障碍审查、整个仓库的许可证头核对。这类检查你希望在任何场景下都能随手叫出来,但不希望它每改一行代码就跳出来一次。
代价很实在:每一次调用都是你要记得去做的一个动作,忘了就是没做。
什么时候该往上升,判据是这一条:当你每改完一次都在跑它,说明它不该再靠你记着了。到这个时候,这个流程已经挣到了一个固定的位置,该往下面两档挪,要么嵌进去,要么串起来。
嵌进去:在生成代码的那个技能末尾加一行
这一档是让检查跟着生产它的那条工作流一起跑,你不用开口。
做法比想象中简单,在那个技能的正文末尾追加一句话就行。拿一个生成 React 组件的技能举例,前面都是它原本的内容,加的只有最后那两行:
--- name: scaffold-component description: Scaffold a new React component under src/components/, including the component file, its co-located test, and an index export. Use when the user asks to create a new component. allowed-tools: [Read, Write, Edit, Bash, Glob] --- # Scaffold a new React component Given a component name (PascalCase), create the following under `src/components/<Name>/`: 1. `<Name>.tsx`: function component with a typed props interface and a default export. 2. `<Name>.test.tsx`: React Testing Library test that renders the component and asserts it mounts without throwing. 3. `index.ts`: re-export the default and any named exports. Follow the patterns in `src/components/Button/` as the reference. Match the import alias style (`@/components/...`) used throughout the codebase. # code continues... After creating the component file, run eslint on it and address any errors before reporting completion.
怎么确认它真的生效?拿一个全新的任务调用一次这个技能,看新加的这一步有没有出现在输出里。没出现,说明这个技能的 description 或者前面那些指令没能把这一段带进来,得回去改。
这一档有个明确的边界:只对你能编辑的技能有效。你自己写的可以,装在项目层、SKILL.md 文件在你手上的也可以。内置技能和插件管理的技能不行,后者会在更新时被整个覆盖掉,你加的东西会丢。这两类要接检查,得用下一档的串联。
还有一条反过来的:跨工作流的检查不要嵌。那种东西你希望从任何上下文都能叫出来,留在单独调用那一档。
串起来:Anthropic 内部四个技能接力
一个技能在自己结尾处叫下一个,几段验证过的交接就连成了一条能端到端跑完的链。
Anthropic 的 Claude Code 团队日常就在用这个模式,链条是四段:
/design 是他们自己写的技能,不是内置的。串联还有一个作用:给你改不了的那些技能补上验证。做一个包装技能,让它先调原来那个,跑完再调你的检查:
Run /simplify on the current diff first. When /simplify finishes, invoke /verify-no-public-api-changes.
这一步的性质变化在这里:原来那是一个习惯,我每次跑完 /simplify 都会跑 /verify;现在它成了一条约定,/simplify 跑完一定会跑 /verify。链条自己把整个开发循环走完,只有需要你拍板的事情才会升上来。
代价也写在明处。步骤之间足够独立、你有时候想单独跑其中一个的话,就别串,串联是拿灵活性换自动化。另外串起来会明显多花 token,所以大范围铺开之前先小范围测一测。
挂到每个 PR:同事的改动也过一样的关卡
链条在你自己的改动上跑顺了之后,同一套流程可以搬到每个 PR 上。
底层的东西一点没变:同样的技能、同样的评分表、同样的标准。变的是它作用在谁身上。
链条在你的机器上跑,你的改动过这几道关。别人的改动过不过,取决于他记不记得调用。
改动进了 PR 就过这几道关,谁提交的都一样。作者的自觉不再是变量。
验证到这一步就不再是你个人的基础设施,成了团队的基础设施。你当初为了给自己省两分钟才写下来的那条检查,现在每一次改动都在给每个人省两分钟。
但有一条要注意:链条还在反复调的时候,先别挂到全团队。挂上去之后,你每调整一次都会变成一个全团队都能看见的事件。
串起来为什么更费 token,以及能省的两个开关
串联会多花 token,这笔钱花在哪,官方文档里写清楚了。
你或者 Claude 调用一个技能时,渲染后的 SKILL.md 内容会作为一条消息进入对话,并且在这次会话剩下的时间里一直待着。它不是用完就走的。
所以技能正文的每一行都是一笔重复开销:链条上串了四个技能,这四份正文就一直躺在那儿,往后每一轮都得再带一遍。这也是官方反复强调技能正文要写短的原因,写清楚「做什么」,不要叙述「怎么做、为什么」。
两个能省的开关
还有两个数字,动手写技能之前值得先知道:
description 和 when_to_use 合起来,在技能清单里被截断到这个长度。超出的部分,Claude 在决定要不要用这个技能的时候看不到,所以最关键的使用场景要放在最前面。照着做的六步
不管你要自动化的是什么、在什么环境里,下面这六步的顺序都一样。
你越是能把要求写下来交给 Claude 遵守,它第一次给出的东西就越接近你想要的。那些你不用再反复纠正的地方,腾出来的注意力可以放到那些没有任何技能能替你写下来的事情上。
Delba de Oliveira,本文结尾
/verify 与 /code-review 的调用限制、/simplify 的四个审查 Agent、技能内容常驻上下文的机制、frontmatter 字段与两个数字上限。上下文占用示意图为本站所画。原文全文未给出任何效果数据。你改完代码手动点的那几下,写成十几行就能让它自己跑自己修
Claude Code 团队公开了自家内部日常在跑的四技能接力,一页带图讲完这套检查怎么写、放哪跑、代价多少。
↓ 一页读完 · 有一张会动的图
AI 改完代码,编译报错、测试挂了这些它自己看得见,会回头改。剩下那几步只有你能看见的检查,每次都落回你手上。把那几步写下来交出去,它就能自己跑。
你让 AI 改一个功能,它说改好了,然后你打开页面点一遍,翻一眼日志,再把浏览器拖窄到手机宽度试试。这几下每次都得你自己来。为什么偏偏是这几下?看下面这条分界线。
编译器报错
类型检查不通过
测试没跑过
linter(自动扫代码毛病的工具)报的警告
这个按钮在手机宽度下会不会被挡住
这条错误日志有没有把用户提交的内容一起写出去
这次改动删了数据库的一列,数据有没有补进新结构
这个界面合不合团队那份设计规范
一个技能就是项目里 .claude/skills/ 下的一个 markdown 文件(一种纯文本格式,记事本就能写)。把你每次都在做的那几步用大白话写进去,就像交给一个第一天来的新同事。文章里最小的那个只有十几行,查的是错误日志有没有带上请求编号、有没有把用户提交的内容写进去。
想让它不用你开口就自动跑,办法是在生成代码的那个技能末尾追加一句话。下面这个生成前端组件的技能,改动只有最后几行。
the default and any
named exports.
component file, run
eslint on it and
address any errors
before reporting
completion.
加的那句话是:创建完组件文件之后,对它跑一遍代码检查工具,把错误处理掉,再报告完成。从此每次生成组件都自动带上这一步。三个能整段抄走的模板都在正文里。
检查写出来之后,紧接着的问题是它什么时候开火。同一份检查放在不同位置,性质就不一样。
串起来会明显多花钱,钱花在哪,Claude Code 官方文档写清楚了:一个技能被调用,它的正文会作为一条消息进入对话,并且在这次会话剩下的时间里一直待着。链条上串了四个技能,这四份正文就一直躺在那儿,往后每一轮都要重新带一遍。
能省的两个开关:给技能加一行 context: fork,把它丢进一个独立的分身里跑,正文不占主对话;技能正文只写「做什么」,不写「怎么做、为什么」。
这三个数字来自 Claude Code 官方文档,是照做前要知道的硬上限。
都得他
自己动手
类型检查没过
测试挂了
linter 的警告
它会回头再改一轮
- × 按钮在手机宽度下会不会被挡
- × 日志有没有把用户提交的内容写出去
- × 删了一列,数据补进新结构没有
- × 界面合不合团队那份设计规范
.claude/skills/ 下
一个 markdown 文件
的全部内容
四个开火位置
/code-review
从 v2.1.215 起,
只在你开口叫
的时候才跑
丢进独立分身跑,
不占主对话
做什么
超过 1,536 字符,
它挑技能时看不到
