上一篇文章总结了 Vibe Coding 的代价,也就是不读代码就开发时会产生的三个问题。
你会无法修复 bug,同一项功能会出现在多个地方,还会悄悄留下安全漏洞。当时我提出的解决方案是“只读关键区域”“阅读 AI 摘要”和“运行扫描器”。
不过,这些解决方案有一个共同点:全都是在事故发生后才发现问题的事后验证。
这篇文章再进一步:在验证之前,通过强制约束让 AI 从一开始就无法生成这类代码。
工具大家其实已经有了,就是 CLAUDE.md、.cursorrules、AGENTS.md 这类规则文件。
Vibe Coding 的成败不在读取代码的阶段,而是在编写第一个规则文件的阶段决定。
为什么是规则文件?——AI 每次都是刚入职的新人
先来看看 AI 编程工具的根本特性:会话结束后,AI 通常会忘记大部分内容。
即使你昨天说过“把 API 密钥移到环境变量中”,今天开启新会话时,那段对话也相当于从未发生过。
因此,每个会话都要重复的指令不能只留在对话里,而必须写入文件。
CLAUDE.md(Claude Code)、.cursorrules(Cursor)和 AGENTS.md(Codex 等通用工具)就是例子。这些规则文件会在每次会话开始时自动添加到提示词中。
换成人来理解,就像每天早上上班时交给新人的入职培训文档。
这特别适合 Vibe Coding,因为 Vibe Coding 顾名思义就是人不阅读代码的一种方式。
人工审查留下的空缺必须由其他机制填补,首选就是生成时的规则。与其筛掉糟糕的代码,不如从源头避免生成,成本低得多。
在上篇的三个问题之外,再加上两个不读代码就无法发现的 AI 特有错误,接下来看看如何用规则防住这五个问题。
规则 1. 安全性——不仅要写“不要做”,还要写“应该这样做”
先处理上篇提到的 API 密钥硬编码问题。规则文件可以这样写:
## 安全规则(违反时停止生成代码并报告)
- API 不要将密钥、令牌或密码硬编码到代码中.
必须从环境变量(.env) 或密钥管理器中读取.
- .env 绝不提交该文件. .env.example;只提交.
- 不要信任用户输入. SQL,使用参数绑定,
HTML 输出默认进行转义.
- 编写文件删除·DB 、迁移或外部支付 API 调用代码时
执行前必须先获得用户确认.
- 不得擅自安装新库。先提出包名和
选择理由,获批后再添加.
这里有两个关键点。
第一,不要只写禁止事项,还要同时写出替代方案。如果只写“禁止硬编码”,AI 就必须自行寻找绕行方案。
如果明确写出“从环境变量读取”,它就会毫不犹豫地选择这条路径。规则的遵守率与替代方案的具体程度成正比。
第二,对于风险等级不同的任务,流程本身也要有所区别。删除、支付和迁移如果明确规定“确认后再继续”,即使整个流程都在点击 Accept All,也会只在这些节点踩下刹车。
最后一行的依赖规则同样是安全性的延伸。有调查显示,AI 推荐的软件包名称中有 5%~21% 实际并不存在于仓库中,但真正可怕的是接下来发生的事。
攻击者会提前抢注 AI 经常凭空编造的虚假名称,并用这些名称上传恶意软件包。Slopsquatting(slopsquatting)攻击确实正在发生。
在连安装命令都通过 Accept All 放行的氛围编程中,这条路径会直接演变成供应链事故。因此,将“新软件包先提议、再审批”固定为流程会更安全。
规则 2. 重复 — 将“创建前先搜索”写入规范
同一功能在多个地方出现的根本原因,并不是 AI 偷懒,而是 AI 会把上下文中看不到的代码视为不存在。
项目越大,完整代码库就越无法放入上下文,因此从 AI 的角度看,新建一个相似函数是合理的选择。
所以,我们通过规则强制进行搜索。
## 防止重复规则
- 创建新函数或组件之前,必须先搜索现有代码库
确认是否已经存在相同作用的代码.
- 日期处理 src/utils/date.ts, API 调用位于 src/lib/api.ts
使用已有函数。如果没有,就添加到该文件中.
- 在两个以上位置使用的逻辑,立即提取为公共模块.
- 如果看起来需要一个与已有函数几乎相同的函数,不要重新创建
先检查能否扩展已有函数,再向用户提出建议.
第二行尤其有效。相比“不要创建重复内容”这种抽象规则,“日期处理就在这个文件里”这张地图更容易发挥作用。
即使 AI 跳过搜索,规则文件中写明的路径也始终就在眼前。只要在规则文件中维护项目公共模块位置的列表,就能明显减少重复创建。
规则 3:架构——将文件夹结构和依赖方向定为宪法
三者中最容易悄无声息崩坏的是架构。安全事故发生时会被发现,重复内容搜索后就能看见;但架构往往是某天回头一看,早已变成了意大利面。
AI 倾向于编写“现在最快解决这个请求的代码”。因此,它会毫不在意地打通跨越层级的捷径。
例如,从视图直接调用数据库。
这同样可以用规则来阻止。关键是明确写出结构和依赖方向。
## 架构规则
项目结构:
- src/views/ : UI. 只处理状态和事件
- src/services/ : 业务逻辑
- src/repositories/ : 数据访问. DB·API 调用只能在这里进行
依赖方向是 views → services → repositories 单向的.
- views不会直接 repositories import
- repositories不会 views import
- 新功能也必须遵循这一 3分层结构.
如果有必须跳出该结构的理由,要在编写代码前向用户说明
这条规则真正的价值,会在初始骨架搭建完成后显现。
AI 会强烈模仿现有代码中的模式。如果初始代码遵循三层架构,后续代码也会自然而然地沿用这一脉络。
反过来,如果初期哪怕只开了一个捷径,AI 也会把它学成“这个项目允许的模式”。
所以,这篇文章的副标题是“最初的骨架”。
项目创建后,趁代码只有 10 行,先确定规则文件和文件夹结构。这比之后重构 1 万行代码便宜数百倍。
规则 4. 完成标准——区分“好像完成了”和“完成了”
从这里开始,我们将介绍前文没有涉及的、AI 编程特有的思维方式。
AI 常有这样的习惯:代码写完后,不经检查就说“已完成”。即使那段代码实际上连编译都无法通过。
在有人阅读 diff 的工作流中,问题很快就会暴露;但在氛围编程中,人们只相信“完成”这句话,然后继续提出下一个请求。因此,必须把完成的定义本身固化为规则。
## 完成标准规则
- 在宣布工作完成之前,必须 typecheck·lint·运行测试
并同时报告测试结果
- 测试失败时要修复代码。不得修改或删除测试来让它通过
如果认为测试本身有问题,不要强行让它通过,而应当
先报告,不要修改它
- 不要用 try/catch包裹错误后将其悄悄吞掉.
捕获到的错误必须记录日志,或向上层传递
第二条规则是关键。当给 AI 的目标是“让测试通过”时,它确实可能不去修复代码,而是修改失败的测试。
它找到了实现目标的最短路径。对于不阅读代码的人来说,甚至不会意识到验证机制已经失效,只会看到绿灯。
第三条规则与上一篇中的问题 1(将无法修复 bug)直接相关。
AI 常常以防御式编程为名,用会吞掉错误的 try/catch 包住代码。这样一来,即使出现问题,界面看起来也可能正常。之后真正需要的错误信息无处可寻,调试会变得更加困难。
规则 5. 作用域——只做要求的事情
AI 编程的另一个典型问题,是连没人要求的事情也一起做了,这就是所谓的 scope creep。你让它修改按钮颜色,它却“顺便”重构周边代码、提取新的辅助函数,甚至连文件结构都改了。
这看起来像是出于好意,但在 vibe coding 中却很致命。因为不读 diff,即使混入了未请求的修改也不会发现;等到之后出了问题,可能的原因就会增加好几倍。
## Scope 规则
- 只执行请求的工作。工作中发现的改进点不要修改代码,
在工作完成后以列表形式提出建议
- 不要修改与请求无关的文件
- 只有在单独收到请求时才进行重构
效果也可以用数据确认。据称,仅在规则文件中添加几行 scope 规则,就能让 revert 和范围偏离率从 41% 降至 12%。
这些数字来自一份为期 30 天的实测报告。在五类规则中,这一类的投入产出比最高。
仅靠规则还不够 — 加上双重锁定
读到这里,你可能会想:“那只要把规则写好,就不用读代码了吧?”但这里有一个陷阱:规则只能提高遵守的概率,并不能保证一定遵守。
当上下文变长时,AI 有时会忘记规则;而在情况紧急时(更准确地说,是看起来很紧急时),它也可能选择走捷径。
因此,越重要的规则越应该配合机械验证。规则是第一道锁,工具是第二道锁。
| 规则(生成时预防) | 工具(提交与 CI 时验证) |
|---|---|
| 禁止硬编码密钥 | gitleaks pre-commit 钩子 |
| 禁止重复逻辑 | 使用 jscpd 等重复检测工具 |
| 强制规定分层依赖方向 | dependency-cruiser, eslint-plugin-boundaries |
| 完成标准(测试・类型检查) | CI 流水线门禁 |
| 禁止擅自修改测试文件 | 通过 CODEOWNERS 保护测试目录 |
| 代码风格 | ESLint·Prettier·SwiftLint |
这个组合的力量在于反馈循环。工具捕获规则违规后,错误信息会再次传给 AI,AI 会重新参考规则文件并修复问题。
即使没有人介入,预防 → 验证 → 修复的循环也会运行。前文提到的“如果人不会阅读,就让机器来读”,与规则结合后才算完整。
能用 lint 规则强制执行的内容,就交给 lint。理想的分工是:规则文件保留工具无法捕获的内容(确认流程、设计意图、项目上下文)。
实战:项目开始前的 10 分钟检查清单
在新项目中开始氛围编程前,输入第一个提示词之前,先做这些事。
- 创建规则文件——包含安全性、重复、架构、完成标准和范围五个部分。复制上面的示例并按项目调整,10 分钟即可完成。
- 先提交文件夹骨架——即使文件夹为空,先建立结构后,AI 也会遵循这种脉络。
- 安装密钥扫描 Hook——只需一个 gitleaks,就能避免最严重的事故。
- 创建 .env.example——从代码库层面发出“密钥放在这里”的信号。
实际运行时只需记住一件事:如果 AI 两次犯下同样的错误,问题不在 AI,而是说明规则文件中没有这条规则。
每次发生事故,就逐行补强规则。规则文件不是写完一次就结束的文档,而是会随项目一起成长的文档。
问:听说规则文件变长后,反而更难被遵守?
答:没错。规则也会占用上下文,因此文件越长,每条规则的权重就越容易被稀释。
以“是否必须始终遵守?”为标准保持精简,能交给工具检查的就交给工具。根据经验,一旦超过一个屏幕(约 100 行),就需要精简。
问:对已经变成意大利面的项目也有用吗?
答:有用,只是顺序不同。
先让 AI 分析当前结构,生成规则文件草稿。然后在规则中明确渐进策略:“新代码遵循这些规则,已有代码则在修改时顺便修复。”
问:CLAUDE.md、.cursorrules、AGENTS.md 都需要分别管理吗?
答:通常只写一份内容,再复制文件即可。
最近也出现了将 AGENTS.md 作为标准,让其他文件引用它的做法。如果你使用多个工具,建议将 AGENTS.md 作为唯一事实来源。
总结一下:如果上篇文章的结论是“速度交给 AI,判断交给我”,那么这篇文章的结论就是:
不要每次都重新做判断,把做过一次的判断固化为规则。
读代码,是发现其中的思考;写规则,则是预防问题发生。那些通过 Vibe Coding 提升速度、同时又不会崩溃的项目都有一个共同点:关键不是华丽的提示词,而是经过良好维护的规则文件。
如果当前正在进行的项目还没有规则文件,请在要求实现下一个功能之前,先创建上面的五个部分。
规则文件与记忆功能的区别,以及哪些内容应该放在哪里,已在另一篇文章中详细介绍,建议一并阅读。
参考资料
- Claude Code Memory - Anthropic Docs
- Rules - Cursor Docs
- AGENTS.md - Agent 规则文件标准
- AI Agent Failure Modes - NimbleBrain
- CLAUDE.md Rules: How to Cut AI Coding Mistakes - DEV Community

