跳转到内容

验证方法论

进阶

内容验证于 2026-06-24适用 Claude Code CLI v2.1

验证是你和 Claude Code 协作中最重要的一步——但也是最容易被跳过的一步。这篇文章教你一套三层验证体系:从 grep 检查名字一致性,到 diff 审计意图对齐,再到实际运行确认功能真能用。学完后,你不再依赖“感觉应该没问题”。

写完作文后自己朗读一遍 = 基本验证。让别人朗读 = 双重验证。发表前编辑审稿 = 最终验证。

Claude Code 写的代码也一样——生成只是第一步,验证才是区分“能跑”和“跑对了”的关键。你可以把 Claude Code 想象成一个超级勤奋但偶尔会走神的队友:它能一口气写几千行代码,但可能把变量名拼错了一个字母、或者改了你没让它动的文件、或者漏掉了某个需求里提到的小细节。

验证就是你在验收这个队友的工作。你不需要逐行读懂所有代码——你需要的是几个具体、可操作、机械化的检查流程。

  • 已经用 Claude Code 完成过至少 2-3 次代码改动任务
  • 知道怎么打开终端和输入命令
  • 了解 git 的基本概念(如果不了解,先看 Git 10 分钟速成

Anthropic 官方文档把“验证循环”(verification loops)列为 Claude Code 的 #1 最佳实践。这不是随便说说的——有三个硬数据支撑:

1. AI 生成代码的准确率不是 100%

并非所有规范都会被完美执行——遗漏率不可忽视(具体比例因模型、prompt 长度和任务复杂度而异)。这在“增加一个按钮”这类简单需求上不明显,但在“重构用户认证模块”这种多文件联动任务上,遗漏率会显著上升。

2. Claude 不会主动告诉你它漏了什么

AI 不会说“对了,我其实把第二个需求跳过了”。它生成代码时的输出看起来完整、自信、条理分明,但这不代表它真的覆盖了你的全部需求。只有你去验证(对比你说过的话和代码实际做了什么),才能发现这些遗漏。

3. 真实案例:56 个单元测试通过,1 个真实端到端测试抓到了协议 bug

Jason 的实际经历:Claude Code 写了一个模块,56 个单元测试全部绿灯。看起来完美。但他多花了两分钟,在真实环境里跑了一次端到端调用——结果发现了一个协议层面的 bug:上下游之间的数据格式约定和实际传的不一致。56 个单元测试全都关注的是“函数内部逻辑对不对”,没有一个测试能抓到“两个系统之间说的语言不一致”这种问题。

结论:验证不是“不信任 AI”,而是“AI 写的代码需要和写出来的代码一样的验证标准”。你同事写的 PR 你会 review,AI 写的更该 review。

按投入时间从少到多、发现问题从浅到深,排成三层:

目标:确认所有新增的函数名、变量名在定义处和调用处拼写一致。

这是最低成本、最高频的检查。Claude Code 最常见的低级错误之一就是“定义了 getUserProfile,调用处写了 getuserProfile”(少一个大写字母)。

具体操作

Terminal window
# 假设 Claude Code 刚刚新增了一个函数 processImage
# 在项目目录下搜索这个函数名
grep -rn "processImage" .
# 预期输出应该至少有两个位置:
# 1. 定义处:function processImage(...) { ...
# 2. 调用处:processImage(params)

如果 grep 只找到一个结果(只有定义没有调用,或者只有调用没有定义),这就是一个 bug。

批量检查:如果改动涉及多个新名词,挨个 grep:

Terminal window
# 列出 Claude 新增的所有标识符
grep -rn "新增的关键词1" .
grep -rn "新增的关键词2" .
grep -rn "新增的关键词3" .

判断标准:每个名称至少出现两次(一次定义,一次调用),且拼写完全一致。

为什么有效:这层检查不需要理解代码逻辑,只需要对比字符。一个拼写 bug 能在 30 秒内发现,但如果不检查,可能直到运行时才报错——而如果你刚好没跑那条路径,这个 bug 就会悄悄留在代码里。

第二层:diff 审计 — 改动符合意图

Section titled “第二层:diff 审计 — 改动符合意图”

目标:确认 Claude Code 改的东西和你让它改的是一回事。

具体操作

Terminal window
# 第一步:看改动概览 -- 哪些文件被改了,每个文件改了多少行
git diff --stat
# 输出示例:
# src/auth.ts | 45 +++++++++++++++++-------
# src/utils.ts | 12 ++------
# src/config.json | 2 +-
# 3 files changed, 38 insertions(+), 21 deletions(-)

先问自己三个问题:

  • 改的文件数量和位置符合预期吗?(如果只让改 auth,结果 utils.ts 也变了——有侧效应)
  • 每个文件的改动量符合预期吗?(如果只让加一个按钮,结果改了 200 行——值得细看)
  • 有没有陌生的文件出现在列表里?(如果 config.json 不该被碰——Claude 可能误操作了)

第二步:逐条读 diff

Terminal window
git diff

你现在看到的是标准的 git diff 输出格式。每条改动前面有一个标记:

  • + 开头 = 新增的行(added lines)
  • - 开头 = 删除的行(removed lines)
  • @@ -a,b +c,d @@ = 位置标记,告诉你这段改动在原文件的第 a 行到第 b 行,在新文件的第 c 行到第 d 行

逐条读的时候,问自己

  • 每条 + 行:这是我让 Claude 做的改动吗?
  • 每条 - 行:删掉的内容确实该删吗?(Claude 有时会顺手删掉你不希望它碰的代码)
  • 改动范围:有没有我不认识的文件被改了?

判断标准:diff 中的所有 + 行都能对应到你的原始需求;所有 - 行都是你应该同意删除的。

为什么有效:Claude Code 最常见的“好心办坏事”就是顺手改了你没让改的东西——比如重构一个函数时顺便改了命名风格、删了一个它觉得“没用”但实际上有依赖的导入。diff 审计是唯一能在提交前发现这些侧效应的方法。

实战经验:diff 超过 200 行先拆分

如果一次改动的 diff 超过 200 行,且跨越 3 个以上的文件,强烈建议把任务拆成小份。先验证第一份,没问题再继续。一次性丢 500 行 diff 给人类审计,绝大多数人会“扫一眼感觉没问题”——这正是 bug 潜伏的温床。

第三层:实际运行 — 功能真能用

Section titled “第三层:实际运行 — 功能真能用”

目标:确认代码在真实环境中真的能跑,不是只在纸面上正确。

这是三层中投入最大、但价值最高的一层。前面两层检查的是“代码写对了吗”,这层检查的是“软件能用吗”。

不同类型的测试,抓不同类型的 bug

测试类型能抓到的问题抓不到的问题
单元测试函数内部逻辑错误函数之间的协作错误、协议不匹配
集成测试模块之间的协作错误真实环境的网络延迟、权限问题
端到端测试(真跑一遍)几乎所有真实使用场景的问题

Jason 的案例:56 个单元测试全部通过。1 个真实端到端测试抓到协议 bug。这不是单元测试的问题——单元测试本身跑对了,但它测试的范围天然不覆盖“上下游之间的数据格式约定”这种跨系统问题。

具体操作(按项目类型)

前端项目

Terminal window
npm run dev # 启动开发服务器
# 在浏览器打开,手动点一遍改动的功能
# 检查控制台有没有报错(F12 → Console)

后端项目

Terminal window
npm start # 启动服务
curl http://localhost:3000/api/your-endpoint # 手动调一次接口
# 或者用项目自带的测试
npm test

纯脚本

Terminal window
node your-script.js
# 看终端输出是否符合预期

判断标准:程序能正常启动、改动的功能路径被实际触发过一次、没有运行时报错。

为什么有效:代码在 AI 大脑里跑和在你电脑上跑是两回事。前者依赖 AI 的“理解”,后者依赖操作系统的实际执行。只要有一次真实运行,就能暴露出:缺失的依赖、错误的导入路径、环境变量没配置、端口冲突等等 AI 无法在静态代码中检测到的问题。

小 diff 让验证变简单。 一个 50 行的改动:用 git diff 逐行看,2 分钟能确认每行都对。一个 500 行的改动:看到第 100 行已经眼花,剩下的只能“相信 AI”。这就是为什么一次只改 200 行——不是限制 AI 的能力,是保护你的注意力。

最有效的验证技巧之一:直接告诉 Claude Code “检查你自己刚才写的代码”。

为什么这比你自己检查更有效

  • Claude Code 不会累——一行一行 grep 不会走神
  • Claude Code 不会跳过——你让它“检查所有新增函数”,它不会扫一眼就觉得“差不多”
  • Claude Code 有完整的上下文——它记得自己写了什么、为什么这样写

具体 prompt 模板

# 第一层检查
请用 grep 确认刚才所有新增的函数名、变量名在定义处和调用处拼写一致。
# 第二层检查
请逐条对比 `git diff` 中的改动和我的原始需求(上面我说过的 prompt),列出来哪些需求你实现了、哪些你可能漏掉了。
# 第三层检查
请列出你可能漏掉的需求或者没有完全按我的意图实现的地方。

不是审问,是协作

注意语气——不是“你肯定漏了东西,给我找出来”,而是“帮我确认我们俩没有漏掉什么”。把 Claude 当成和你一起做 code review 的同事,而不是写 bug 需要审问的对象。

让 Claude 写一个验证脚本

如果你有经常重复的验证动作,可以让 Claude Code 写一个验证脚本:

请写一个 bash 脚本 verify.sh,放在项目根目录,功能是:
1. 用 grep 检查所有新增的 API 端点名称在前后端拼写一致
2. 跑 npm test
3. 跑一遍项目的 dev server 确认能启动

之后每次 Claude Code 做改动,跑一遍 bash verify.sh 就行。

git diff 是验证工作中最重要的工具,但它的输出格式对新手不太友好。这里拆解一个具体的例子:

diff --git a/src/auth.ts b/src/auth.ts
index abc1234..def5678 100644
--- a/src/auth.ts
+++ b/src/auth.ts
@@ -10,7 +10,9 @@ function login(username, password) {
- const result = api.login(username, password)
+ // 添加输入校验
+ if (!username || !password) return { error: "用户名和密码不能为空" }
+ const result = api.authenticate(username, password)
return result

逐行解读:

  • --- a/src/auth.ts / +++ b/src/auth.ts:文件名,a = 旧版本,b = 新版本
  • @@ -10,7 +10,9 @@:以下改动发生在 login 函数附近。旧文件从第 10 行开始,涉及 7 行;新文件从第 10 行开始,涉及 9 行(+2 行的原因是有两行新增)
  • - const result = api.login(...):被删掉的行(函数名从 login 改成了 authenticate)
  • + // 添加输入校验:新增的注释行
  • + if (!username...):新增的校验逻辑
  • + const result = api.authenticate(...):新增的调用行(同时改了函数名)

实战技巧

  1. 永远先跑 git diff --stat 而不是直接 git diff。先看全局,再决定深入哪些文件。
  2. 改动文件超过 3 个,逐文件看git diff src/auth.ts 只看一个文件的改动,比一次性全看注意力集中得多。
  3. diff 不可读?让 Claude 翻译:直接把 diff 贴给 Claude Code,说“请用中文解释这段 diff 做了什么改动”。
  4. 看不懂的改动,标红:一条 + 行你看不懂它为什么在那里——先别放行,问 Claude“为什么加了这行?”

最典型的陷阱:代码逻辑看起来完全正确,变量名都对,格式也漂亮,但实际上功能不对。比如代码里调用了 api.login,但这个函数在最新的 API 版本里已经被 api.authenticate 取代了。静态看代码看不出这个问题,只有实际运行——或者至少运行一次端到端测试——才能发现。

防护:第三层验证——实际跑一次。

“56 个测试全过了,肯定没问题”——这是最危险的假设。单元测试只能验证“每个小零件单独工作时逻辑正确”,无法验证“所有零件拼在一起后协作正确”。更无法验证“代码和外部系统的约定一致”。

防护:单元测试通过是必要条件,不是充分条件。至少加一次端到端验证。

“Claude 说的看起来都合理,diff 就不看了吧”——这等于闭着眼睛签合同。Claude Code 可能在你没注意的时候多改了一个文件、删了一行你需要的配置、或者在一个关键函数的签名里加了一个参数。

防护:不管改动多小,至少跑 git diff --stat。养成肌肉记忆。

改了 A,B 也跟着变了,但没发现

Section titled “改了 A,B 也跟着变了,但没发现”

Claude Code 改动函数 A 时,如果 A 被 B、C、D 三个地方调用,Claude 可能会顺便修改 B 和 C 的调用方式(为了适配 A 的新签名),但是漏掉了 D。结果:A 和 B、C 没问题,但 D 运行时报错——而这个 D 恰好是那个你不常跑的边缘路径。

防护:grep 搜索被改函数的所有调用位置,确认每处都被正确处理。

你让 Claude 修复了 A 问题,你验证了 A 确实修复了,然后提交。但 Claude 的这次改动可能同时引入了新的 B 问题——而你因为只盯着 A,完全没注意到 B。

防护:每次改动后走一遍三层验证流程,不管改动看起来多简单。

用 Claude Code 做一个简单的改动,然后完整走一遍验证流程:

  1. 打开终端,进入任一个有 git 的项目目录
  2. 告诉 Claude Code:
    请给 src/ 下的入口文件加一行注释,内容是 “// 验证练习 2026-06-12”
  3. Claude Code 完成后,依次执行:
Terminal window
# 第一层:grep 确认注释确实在文件中
grep -rn "验证练习 2026-06-12" .
# 第二层:看 diff 确认只改了这一行
git diff
# 第三层:运行程序确认没有破坏任何功能
#(如果你的项目是纯 HTML:直接在浏览器中打开文件。如果是 Node.js 项目:npm start)
npm start # 或 node your-entry.js,或 npm run dev

如果程序正常启动且功能无异,验证通过。

进阶练习:这次让 Claude Code 做一个涉及多个文件的改动(比如“把 src/utils/ 下所有文件里的 var 替换成 const”),然后验证:

  • grep 确认所有文件确实被改了
  • diff 审计确认没有多改其他文件
  • 程序启动正常
  • 验证是日常节奏的核心环节——日常节奏 教你如何把验证嵌入每天的开发流程中
  • 验证的另一个维度是管理对话长度——上下文窗口管理 教你避免“对话太长导致 Claude 开始忘事”
  • 子 Agent 的输出也需要验证 → 子 Agent 协作
  • 如果你的验证流程需要反复执行,把它写成一个 Skill(参考Skill 体系