我让 Claude Code 修一个 Bug,它却重构了半个项目
# 我让 Claude Code 修一个 Bug,它却重构了半个项目
有一次,我让 Claude Code 帮我修一个很小的 Bug。
问题真的不复杂。页面上有一个按钮,点击之后 loading 状态没有正常恢复。按照我当时的理解,这种问题最多就是少写了一行状态重置,或者请求结束后没有把 loading 改回 false。
我把问题丢给 Claude Code 之后,就去看别的东西了。过了一会儿,它告诉我已经修好了。
我打开 diff,整个人愣了一下。
它确实修了按钮状态,但不只是修了按钮。它顺手改了状态管理,又调整了一个公共 hook,还把几个组件里的判断逻辑一起整理了。更离谱的是,它还动了一个我根本没提到的工具函数,说是为了“统一处理状态”。
那一刻我脑子里只有一个想法:
我只是让你修门锁,你怎么开始拆墙了?
刚开始我以为,这是 Claude Code 又不稳定了。毕竟用 AI 写代码的人应该都遇到过这种情况:你明明只是让它改一个小问题,它最后给你一大坨 diff。代码可能还能跑,但你完全不敢直接接受,因为你不知道它到底改了多少地方,也不知道哪个地方会在未来变成新的坑。
但这件事后来我越想越不对。
Claude Code 真的完全做错了吗?好像也不是。它改的很多东西,如果单独拎出来看,都能解释得通。状态管理确实可以更清晰,公共 hook 确实可以少一点重复逻辑,工具函数也确实可以统一一下。
问题在于,这些都不是我这次要它做的事。
我后来才意识到,AI 编程最危险的时候,不是它不会做,而是它太想把事情做好。
我以前一直在写“目标”,却很少写“边界”
以前我给 Claude Code 下任务,最关心的是需求有没有说清楚。比如我要修这个按钮 Bug,我会这样写:
修复提交按钮 loading 状态结束后没有恢复的问题。
这句话看起来没毛病。问题明确,目标也明确。如果是发给一个人类同事,对方大概率能理解:先定位问题,尽量小改,别顺手动无关的东西。
但 AI 不一定会这样理解。
它看到“修复 loading 状态问题”,可能会继续往下推:为什么 loading 状态会乱?是不是状态管理设计不好?是不是组件封装有问题?是不是多个地方都有类似逻辑?既然我已经看到了,要不要顺便统一一下?
从它的角度看,这叫“主动解决问题”。
从我的角度看,这叫“影响范围失控”。
这就是我之前最容易忽略的地方:我一直在告诉它“你要去哪”,却没有告诉它“哪里不能去”。
目标很重要,但边界同样重要。尤其是 Claude Code 这种能读代码、改文件、跑命令的工具,一旦边界没说清楚,它不是只会回答你一段建议,而是真的会动手改你的项目。
这也是为什么我后来重新看了一遍自己的 Claude Code 设置时,突然发现最重要的不是那些很复杂的规则,而是一条特别朴素的话:
只改要求的部分,禁止顺便优化。
以前我觉得这句话太普通了,普通到不像什么高级技巧。现在回头看,它可能是我整套 Rules 里最救命的一条。
我做了一个很小的实验
为了确认这不是错觉,我后来找了一个类似的小问题做测试。
还是按钮状态问题,只不过这次不是登录页,而是一个表单提交按钮。第一次,我只写了一句很普通的提示:
修复提交按钮 loading 状态结束后没有恢复的问题。
结果和之前差不多。Claude Code 先分析了一下,然后开始改代码。最后问题确实解决了,但它改了好几个文件,其中有些修改我看完之后只能说:不是不能改,但没必要在这次改。
比如它把某个判断逻辑抽成了函数,又顺手整理了一个 hook 的返回值。站在“代码洁癖”的角度,这些改动可能还挺舒服;但站在“修 Bug”的角度,这些改动让我很难受。
因为我现在要检查的不再是“按钮状态有没有修好”。
而是“这几个额外改动有没有引入新问题”。
第二次,我把代码恢复,然后加了一段边界说明:
修复提交按钮 loading 状态结束后没有恢复的问题。
要求:
1. 只解决这个 Bug,不做额外重构。
2. 优先选择最小改动方案。
3. 不允许修改 package.json、路由配置、公共工具函数。
4. 如果你认为必须修改其他文件,先说明原因,不要直接修改。
5. 修改前先说明你判断的问题原因。
这一次,结果明显不一样。
Claude Code 还是会分析问题,但它没有到处改。它先说明自己怀疑是请求结束后的状态恢复遗漏,然后只在按钮组件附近做了一个很小的修改。最后 Bug 修好了,diff 很干净,我也能很快看完。
这个实验给我的冲击其实挺大的。
因为模型没有变,项目没有变,问题类型也差不多。真正变化的只是我多写了一段“不要做什么”。
以前我总觉得,提示词写得越详细,是为了让 AI 多做一点。后来我发现,有时候提示词写得详细,是为了让 AI 少做一点。
这两个方向完全不一样。
但我很快发现,不能每次都靠手动提醒
这次实验之后,我一开始的想法很简单:那以后每次修 Bug,我都加一段边界提示不就行了吗?
比如:
只解决当前问题。
不要顺手优化。
不要修改无关文件。
如果必须扩大范围,先问我。
这确实有用。
但用了几次之后,我发现它有一个问题:太依赖我当时有没有想起来。
今天状态好,我会写得很完整。明天赶时间,我可能只写一句“帮我修一下这个 Bug”。结果 Claude Code 又开始自由发挥,我又要回头看一大堆 diff。
这时候我突然意识到,一条规则如果每次都要靠临时想起来,那它其实还不算规则。
它只是提醒。
提醒解决一次问题,Rules 才解决重复问题。
后来我去翻 Claude Code 官方文档,本来只是想确认 CLAUDE.md 和 rules 到底是怎么加载的,结果这个问题反而变清楚了。
官方文档里提到,.claude/rules/ 可以把项目指令拆成多个 Markdown 文件,让规则更模块化,也可以按路径范围加载。也就是说,Rules 不是随便写几句口号,它本来就适合承载那些会反复出现的工作习惯。
比如代码风格、测试要求、提交规范,以及我这次踩坑后得到的这条:
修 Bug 时,只改和当前问题直接相关的部分。
这时我才把 Rules 的位置摆正。
Rules 不是装饰品。
Rules 也不是可有可无的提示词收藏夹。
Rules 更像是 Claude Code 的工作制度。它不能保证 Claude Code 永远不犯错,但它能让 Claude Code 每次进入项目时,都先看到一套稳定的工作方式。
没有 Rules 的 Claude Code,很像一个能力很强但习惯不稳定的临时队友。今天很谨慎,明天很激进;这次只改一行,下次顺手重构半个模块。
而 Rules 的价值,就是把你被坑出来的经验,变成它下一次做事时默认会看到的习惯。
我后来把这条边界写进了 Rules
所以我后来没有满足于每次手动写“不要顺手优化”。
我把它整理成了一条 Bugfix 边界规则。
大概是这样:
# Bugfix 边界规则
当任务是修复 Bug 时:
1. 先定位原因,再修改代码。
2. 默认采用最小改动方案。
3. 只修改与当前 Bug 直接相关的文件。
4. 禁止顺便重构、顺便优化、顺便升级依赖。
5. 如果需要扩大修改范围,必须先说明原因并等待确认。
6. 交付时必须说明:
- 改了哪些文件
- 为什么必须改这些文件
- 如何验证问题已经修复
这段规则不复杂,但它解决的是一个很真实的问题:
我不想每次都重新教 Claude Code 怎么修 Bug。
我希望它一进入这个项目,就知道我的默认工作习惯是什么。
以前我觉得 Rules 应该写得很“技术”,比如命名规范、函数长度、错误处理、测试覆盖。后来我发现,有些看起来不技术的规则,反而更重要。
比如:
只改要求的部分。
不要顺手优化。
不确定先问。
修改前先分析。
交付前先验证。
这些话不像高级技巧,更像工作习惯。
但 Claude Code 最缺的,有时候恰恰是这种工作习惯。
它不是没有能力,而是太容易在一个任务里做太多事。Rules 的价值,就是把你的工作习惯写下来,让它每次进入项目时都能重新看到。
这也是我现在对 Rules 最大的理解:
Rules 不是为了让 Claude Code 突然变聪明。
Rules 是为了让 Claude Code 做事越来越像同一个稳定的人。
Rules 不是低级配置,它是第一层制度
这里有一个地方我之前也想错过。
我一开始以为,既然 Rules 不能百分百强制执行,那它是不是地位不高?是不是最后还是得靠 Hooks 和 permissions?
后来我发现这个理解太粗糙了。
更准确的关系应该是:
临时提示词,是一次性提醒。
Rules,是长期制度。
Hooks 和 permissions,是高风险动作的硬拦截。
这三层不是互相替代的关系,而是分工不同。
比如“修 Bug 时不要顺手重构”,这件事适合写进 Rules。因为它是一种工作习惯,应该在大多数 Bugfix 任务里都生效。
但如果是“禁止读取 .env”“禁止 rm -rf”“禁止 force push”,这种就不能只靠 Rules。因为这类事情一旦发生,后果太严重,应该交给 permissions 或 Hooks 去硬拦截。
官方文档里也有类似的区分:CLAUDE.md 和 rules 更像是行为指导,会影响 Claude Code 的工作方式;而 hooks 会在特定生命周期事件里自动执行,适合做固定时机的检查或拦截。
这句话让我一下子想通了。
Rules 不是没用。
Rules 是制度。
Hooks 是执法。
制度解决大多数日常行为问题,执法处理高风险越界问题。你不能指望制度拦住所有危险动作,但也不能因为有执法,就不制定制度。
所以第四篇我想讲的不是“我写了一个提示词”。
而是:
我被 Claude Code 顺手重构坑过之后,终于把“边界”沉淀成了 Rules。
我现在最怕的不是 Claude Code 写错代码,而是它改太多代码
很多人用 Claude Code 的痛点,其实不是“它不会写”。
恰恰相反,它太会写了。
你让它修 Bug,它顺手重构。你让它改按钮,它顺手整理组件。你让它解决一个报错,它顺手升级依赖。你让它优化一个函数,它可能一路优化到调用方。
它做这些事的时候,语气通常还很自信:
“我已经修复了问题,并顺便优化了相关逻辑。”
以前我看到这句话,还会觉得挺贴心。现在我看到“顺便”两个字,会本能地警觉一下。
因为在真实项目里,“顺便”经常是事故的开始。
顺便改一个工具函数,可能影响十几个调用方。顺便升级一个依赖,可能引入新的兼容问题。顺便整理一个状态管理,可能让原来的边界变得更模糊。
AI 不一定知道你这次任务的真实风险。
它只知道从代码角度看,这里好像可以变得更好。
但开发不是把每一处代码都改到理论最优。开发很多时候是在控制影响范围。
一个好的 Bugfix,不是 diff 越大越厉害,而是问题解决了,改动很小,别人一眼能看懂为什么这么改。
这也是我后来把“只改要求的部分,禁止顺便优化”放进核心规则的原因。
它不是一句废话,而是在提醒 Claude Code:
这次任务的目标不是把项目变完美,而是在最小范围内解决一个具体问题。
如果你也经常被 Claude Code 背刺,可以先抄这条 Rule
如果你也遇到过这种情况:让 Claude Code 修一个小 Bug,结果它改了一堆文件;让它优化一个函数,结果它顺手重构半个模块;让它解决一个报错,结果最后你反而要花更多时间查它改了什么。
你可以不要急着换模型,也不要急着怪 Claude Code 不靠谱。
先做一个很小的实验。
找一个你最常重复提醒 Claude Code 的要求,不要只写在聊天框里,把它沉淀成一条 Rule。
比如你可以新建一个:
.claude/rules/bugfix-boundary.md
然后写入:
# Bugfix 边界规则
当任务是修复 Bug 时:
- 必须先定位原因,再修改代码。
- 默认采用最小改动方案。
- 只修改与当前 Bug 直接相关的文件。
- 禁止顺便重构、顺便优化、顺便升级依赖。
- 如果需要扩大修改范围,必须先说明原因并等待确认。
- 修改完成后,必须说明改了哪些文件、为什么改、如何验证。
如果你不想单独建文件,也可以先把它放进自己的代码质量规则里。
重点不是文件名,而是这个动作:
把一次有效提醒,变成长期规则。
然后下一次修 Bug 的时候,你再观察 Claude Code 的行为。
看它还会不会动一堆无关文件。
看你检查 diff 的成本有没有下降。
看它是不是开始更像一个有稳定工作习惯的队友。
如果结果和我类似,你大概率会发现:Claude Code 不是突然变聪明了,而是它终于知道这次任务该在哪里停下来。
这篇文章真正想说的
我以前以为,会用 Claude Code 的关键,是把需求描述清楚。
后来发现,只描述需求还不够。
一个成熟的任务,至少应该包含三件事:
你要它做什么。
你允许它怎么做。
你不允许它碰什么。
但更重要的是,如果某条边界你已经重复提醒过很多次,就不要让它继续停留在对话框里。
把它写进 Rules。
临时提示词解决一次问题。
Rules 解决重复问题。
而当某些事情绝对不能发生,比如删除文件、读取密钥、强推代码,那就不要只靠 Rules,下一层要交给 Hooks 和 permissions。
这也是我现在越来越强烈的感觉:
Claude Code 真正好用,不是因为它一次能写多少代码,而是因为你能不能把自己的工作习惯,一层一层沉淀进系统里。
第一层,是 CLAUDE.md,让它知道什么时候该做什么。
第二层,是 Rules,让它形成稳定的工作习惯。
第三层,是 Hooks 和 permissions,在它越界的时候拦住它。
这篇先讲 Rules,因为大多数人第一步缺的不是复杂自动化,而是最基本的边界感。
AI 编程真正难的地方,从来不是让它开始动手。
而是让它知道什么时候该停下来。
欢迎来到我的成长实验。
AI 不会替你成长。
但它能让成长更快发生。
更多推荐



所有评论(0)