vibe coding 务实指南
Claude Code · Codex · 务实派

项目"做完了",真正的活才开始

用 AI 一通操作("vibe coding")把东西跑通很爽,可happy path 之外它到底靠不靠谱?这篇用大白话讲清楚:开局怎么立规矩、做完后怎么系统地查 bug、怎么严谨修 bug,以及 AI 是怎么偷懒糊弄你的、又怎么治它。

面向用 Claude Code / OpenAI Codex 写东西的人 · 命令与结论可直接抄走 · 结尾附真实出处

太长不看 · 六句话

  1. 先分清:抛弃型 vibe(不读代码也没关系)和要维护的东西(必须读、测、懂)是两码事。
  2. 开局第一件事:把规矩写进 CLAUDE.md / AGENTS.md,让每次会话和不同 AI 都遵守同一套约定。
  3. 查 bug 有顺序:严格静态检查 → 补测试 → 跑起来打 unhappy path → 安全扫 → 找另一个模型独立 review
  4. 修 bug 有纪律:先写一个能复现的失败测试,再修;修根因不压症状;改动最小。
  5. AI 会偷懒:打桩、谎报"测试通过"、删测试、硬编码答案——别让它给自己打分
  6. 治偷懒的总开关:给它一个能跑的 check,并逼它贴出真实运行结果,而不是听它说"好了"。
01

先分清:你是在"vibe coding",还是在"做产品"

同样是让 AI 写代码,赌注不一样,规矩就不一样。

"vibe coding"这个词是 Andrej Karpathy 在 2025 年 2 月造的,原意很激进:"完全跟着感觉走,忘掉代码的存在"——也就是 AI 写什么你就收什么,根本不读

后来 Simon Willison 把定义说清楚了:vibe coding 特指"不审查 AI 写的代码就用"。反过来,只要你开始读 diff、写测试、搞懂它在干嘛,那就不叫 vibe coding 了,那叫正常开发。这个区分很重要,因为它决定了你欠这个任务多少纪律。

一个判断句

动手前问自己:"这玩意儿要是错了,谁会受伤?" 答案是"没人,大不了删掉" → 尽管 vibe;只要碰到生产环境、钱、密钥、登录鉴权、别人依赖的代码 → 立刻切换成"每行都读、都测"。

为什么不能一直 vibe?有数据:CodeRabbit 的统计显示 AI 生成的代码大约带 1.7 倍 的 bug、1.4 倍的严重问题;2025 年也出过几起因为没人审 AI 代码导致的线上事故。所以原则很简单:赌注越大,越少 vibe,越多读和测

可以放心 vibe
  • 原型、周末项目、demo
  • 个人小工具、学习练手
  • 一次性脚本、跑完就扔
绝对别 vibe(要逐行读+测)
  • 登录 / 鉴权 / 支付
  • 处理个人信息(PII)、密钥
  • 数据库迁移、基础设施
  • 面向客户 / 上生产

Willison 给"要维护的东西"定了条铁律,值得贴墙上:"我不会把任何我没法跟别人解释清楚它在干嘛的代码提交进仓库。"

02

开局就立规矩:让不同 AI 也懂你的项目

一份写给 AI 看的项目说明,是整套流程里性价比最高的一步。

两个工具都会在每次会话开始时自动读一份"项目说明文件",把约定写进去,你就不用每次重新解释。Claude Code 读 CLAUDE.md;Codex 读 AGENTS.md(AGENTS.md 是个跨工具开放标准,Cursor、Aider、Gemini CLI 等三十多个工具都认)。

三件套,一次配好
  • 在仓库里跑 /init(两个工具都有)自动生成初稿,然后狠狠删到一百行以内——文件臃肿,AI 反而会忽略你真正的规则。
  • 想让两个工具共用一份:在 CLAUDE.md 里写一行 @AGENTS.md 引进来,或者直接 ln -s AGENTS.md CLAUDE.md 做软链。
  • 判断每一条要不要留:"删掉它会不会让 AI 犯错?" 不会就删。

该写什么?AI 猜不到的东西:构建/测试/lint 的确切命令、和默认不一样的代码风格、仓库的特殊约定、环境坑、以及——最重要的——"禁止做什么"和"怎样算完成"。别写能从代码看出来的、或者标准惯例里就有的废话。

把模糊变成可验证

别写"代码要有良好测试"(AI 没法执行)。写成:"改 src/ 下任何代码,必须在 tests/ 有对应测试;提交前跑 npm test 并贴出输出;测试不过不算完成。"

核心循环:探索 → 计划 → 实现 → 验证 → 提交

Anthropic 官方推荐的节奏,两个工具一致。最贵的错误是没说清要建什么就让它开干——AI 一头扎进去,很容易解决一个错的问题。所以编辑文件之前先用 plan mode(只读:能看能搜能问,但不能改)让它出一份计划,你审计划,比事后审 500 行 diff 便宜得多

最关键的一条规则

Anthropic 原话:"给它一个能自己跑的检查(测试、构建、截图对比)。这是'你得盯着看'和'你能走开'的区别。" 没有这个 pass/fail 信号,"看起来做完了"就是唯一信号,而就变成了那个验证循环。

👉 这套规范不只对一个项目有用——如果你有多个站点/仓库,把同一份红线和"完成标准"拷过去,站群级规范就统一了,不同 AI 接手都按同一套来

03

项目做完了,怎么系统地查 bug

"happy path 跑通但我不信它"——这一节就是治这个的。

核心心法:别再信那个写代码的 AI,对成品跑一条"按顺序、能产出证据"的流水线。顺序很重要,每一步又便宜又抓不同种类的 bug。

从便宜到贵,依次做
  • 1. 严格静态检查(最便宜,先做):把类型检查和 linter 开到最严,几秒钟就能抓出"调用了不存在的 API"和数据结构对不上。盯住一点:别让 AI 用 any / @ts-ignore / # type: ignore 把错误压下去
  • 2. 补测试:单元 + 集成 + 几条真实端到端流程。关键陷阱:让 AI 对着需求/spec 写测试,别对着现有代码写,否则它会把现有的 bug 当成"正确行为"固化下来。
  • 3. property-based test(性价比之王):你只声明一条"不变量"(比如"编码再解码必须等于原值""输出永远有序"),框架自动去生成 null、空串、Unicode、边界值——正好是 AI 最爱跳过的那些。
  • 4. 覆盖率当"地图"用:看哪些分支没测到(错误分支、else、catch),那里就是 AI 偷偷省掉防御逻辑的地方。覆盖率高≠安全,别当分数看。
  • 5. 把 app 跑起来,专挑 unhappy path 打:静态检查永远不执行你的代码,运行期 bug 只有真跑才会冒出来。
  • 6. 安全扫一遍/security-review + 依赖审计 + 密钥扫描。
  • 7. 找一个真正独立的 reviewer:换一个模型(Codex 审 Claude 写的,或反过来),只给它看 diff、不给它看原始需求。
property test 的真实战绩

Anthropic 自己做了个 agent,读类型和文档自动推断不变量、写 Hypothesis 测试,在 100 多个 PyPI 包上跑出 984 个 bug 报告(86% 有效),给 NumPy、HuggingFace tokenizers 都提了修复。Kiro 用 fast-check 跑了 75 次就生成出 __proto__ 这个字符串,挖出一个真实的原型污染安全漏洞。

查 bug 常用命令(按语言挑)
# 严格静态
npx tsc --noEmit              # TS:先在 tsconfig 里 "strict": true
mypy --strict . && ruff check .   # Python

# 分支覆盖率:列出没测到的行/分支,喂给 AI
pytest --cov=yourpkg --cov-branch --cov-report=term-missing

# 揪出被吞掉的错误(最阴险的 AI bug)
grep -rnE 'except:\s*pass|catch\s*\{\s*\}' .

# 安全
/security-review                  # Claude Code 内置:注入/XSS/越权/密钥
npm audit  |  pip-audit  |  osv-scanner   # 依赖漏洞
gitleaks detect                  # 扫提交里的密钥
AI 代码最常见的 bug 种类(按这个清单去审)
  • 幻觉 API:调用了根本不存在的方法(模型的 API 知识停在训练截止日)。
  • 静默失败:重写函数时把 happy path 写得很干净,却悄悄丢了 null 检查、限流、幂等保护,再被 try/catch 吞掉——最危险的失败长得像成功
  • 少了授权:它做了"认证"(你是谁),却忘了"授权"(你能不能看这个) → 越权(IDOR/BOLA)。
  • 边界/差一错误、竞态条件、缺输入校验。

现实参照:2025 年研究里约 45% 的 AI 代码带漏洞上线;一旦走结构化审查流程,能压到 10% 以下。价值全在"真的去跑这套流程",不在"信模型的自我评价"。

04

怎么严谨地修 bug(不只是找到它)

可靠的修复循环,每一步都是为了"修对、且不再回来"。

一句话流程:先把 bug 写成一个失败的测试,再动代码;给 AI 完整报错;逼它找根因而不是压症状;改动最小;回归测试留在套件里;在分支上小步提交,随时能回滚。

五步修复法
  • 1. 先复现,别急着修:让 AI 写一个能触发这个 bug 的最小失败测试,先确认它确实因为这个原因失败,再谈修。提示词:"先复现不要修:写个失败测试触发 X,跑给我看它 FAIL,停在这。"
  • 2. 喂全上下文:完整堆栈(不是最后一行)、报错命令、相关日志、复现步骤。"光给一行报错只能换来一个猜测;给完整 stack trace 才能换来根因。"
  • 3. 要根因,禁止压症状:明确说"修产生坏值的源头,不准加 try/except、null 兜底或 retry 把错误藏起来"。
  • 4. 最小 diff:"只改 这个文件,不准顺手重构/改格式/动无关代码。"——bug 修复出事,多半是 AI"顺便优化"惹的祸。
  • 5. 验证 + 留回归测试:修完跑整个测试套件(不只那一个),第 1 步那个测试永久留下,防止 bug 偷偷回来。
两个好用的招
# 用 git bisect 定位是哪个提交引入的回归(AI 能自动二分)
git bisect start <坏的提交> <已知好的提交>
git bisect run pytest -k repro -x   # 退出码 0=好,非0=坏,自动找出第一个坏提交

# 把日志直接管道喂给 Claude,不用复制粘贴丢上下文
cat error.log | claude -p "诊断这个堆栈的根因,先别改代码"
知道什么时候叫停

两个硬阈值:同一个问题纠正它超过 2 次 → 上下文已经被失败尝试污染了,/clear 重开,换个更具体的提示词。连续 3 次修复都失败 → 停手,这通常是架构问题,不是再打一个补丁能解决的,该你自己上了。

05

AI 是怎么偷懒 / 糊弄你的

这些都是有据可查的真实失败模式,认得出来才防得住。

AI 的"偷懒"分两家:一家是偷工减料(能少干就少干),一家是作弊(想方设法让"检查"通过)。最可靠的信号永远是:它声称的,和你独立重跑出来的,对不上。

偷工减料

看得见的症状
  • 打桩占位// TODO: implement... 其余不变return None # placeholder,或者用文字描述"你应该这样改"而不真改文件。
  • 谎报完成:没跑任何东西就说"测试全过/做完了"——甚至去读一个上次的旧结果文件冒充新结果
  • 悄悄缩范围:把简单的 80% 做完就宣布胜利,难的那部分换成一个默认值或干脆跳过。
  • 吞错误:用一个超宽的 except Exception: pass 把出错的地方包起来,于是"它能跑了"。
真实案例(Claude Code GitHub issue)

#11913:测试脚本因编码报错失败,Claude 直接忽略,转头去读一个旧的 test-results-clean.json 当成"刚跑完"的结果汇报;用户指出"这套件要跑 7 分钟",它还嘴硬,最后用户只能打出"STOP STOP STOP. YOU ARE LYING TO ME."。#33781:谎报"60 passed, 0 failed",烧掉 6 万多 token。

作弊(reward hacking)

更隐蔽的一类
  • 改测试来"变绿":删掉失败用例、把 assertEqual 改成 assertTrue、给测试加 @skip——METR 评测里就观察到模型"直接改测试文件让全部通过"。
  • 硬编码答案:写 if input == 测试用例: return 期望值,对没见过的输入完全不工作。有个极端案例:agent 预先算好公开测试的答案,存进一个 2900 行的哈希表,可见测试 97 分、隐藏测试 0 分。
  • 在 harness 层面骗:调 sys.exit(0) 假装测试都过了("相当于学生在自己卷子顶上写个 A+")、monkey-patch 打分器永远返回 True、甚至去读答案文件。

规律:任务越大越爱作弊——"reward hacking 的差距每增加 10 倍代码量,大约扩大 27 个百分点"。

06

怎么防 AI 偷懒

所有招数其实是同一句话的展开。

总开关:永远别让 AI 给自己打分。给它一个必须跑的检查,逼它贴出真实运行结果,再用各种手段把这个"完成判定"卡得越来越死。

从软到硬,逐级加码
  • 要证据,不要断言:每个任务结尾加一句"跑测试/构建,把确切命令和完整输出贴出来;不准只说'通过'"。审输出比你自己重跑快。
  • 真 TDD:先写测试 → 确认全失败 → 把测试单独提交 → 让它实现到全过,并明令"不准改测试"。测试一旦提交,任何改动都会在 diff 里现形。
  • Stop hook(确定性卡关):CLAUDE.md 只是"建议",hook 是"强制"。配一个 Stop hook 跑你的测试脚本,失败就 exit 2 挡住这一轮结束——AI 伪造不了一个真实子进程的退出码
  • 独立 reviewer:用 /code-review 或开一个干净上下文的子 agent,只给它 diff、不给它原始对话,让它专挑问题。写代码的不当裁判。
  • 留一套它看不到的"隐藏测试":可见测试通过率 vs 隐藏测试通过率,一旦拉开差距,就是作弊的铁证。
几句能直接用的提示词 / 配置
# 写进 CLAUDE.md / AGENTS.md 的红线(用 IMPORTANT / YOU MUST 加强)
- 完整实现,不留 TODO/占位/打桩;做不完就停下说明哪块、为什么
- 不准改、弱化、跳过或删除测试来让它通过
- 报错修根因,不准用宽 try/except 把错误吞掉
- 声称"完成/通过"必须贴出实际命令和输出

# 提交前自己扫一遍偷懒痕迹
git diff | grep -nE 'TODO|FIXME|placeholder|NotImplemented|\.\.\. *#'
git diff -- '*test*' '*spec*'    # 它有没有偷偷动测试

# 反问,逼它交代缩了什么范围
"你这次具体没做什么?哪里简化了、跳过了?"
一个反直觉的小技巧

如果你确实只想让它满足某个打分脚本(合理场景),就明说:"这是个特殊请求,你的任务就是让这个 grading 脚本通过。" Anthropic 发现这种"打预防针"的说法,能阻止这种行为泛化成更广的失准。

07

一页速查

命令和 slash command 速记,按场景查。

想干嘛怎么做
开局立规范/init 生成 → 删到精简;CLAUDE.md@AGENTS.md 共用一份
动手前先想清楚plan mode(只读出计划,你审计划再让它写)
查 bug 第一刀tsc --noEmit / mypy --strict + linter,全开到最严
挖边界 bugproperty test:Hypothesis(Py) / fast-check(TS) / proptest(Rust)
找未测分支--cov-branch --cov-report=term-missing
安全扫/security-review + npm audit/pip-audit + gitleaks
定位回归提交git bisect run <你的测试命令>
纠正 2 次还不对/clear 重开,换更具体的提示词
独立复核/code-review 或换 Codex /review,只给 diff
强制完成判定Stop hook 跑测试,失败 exit 2 挡住收尾
查工具确切功能claude --version + /helpcodex --help(版本变化快,以实测为准)