首页 > 教程攻略 > ai教程 >我让 Claude Code 修一个 Bug,它却重构了半个项目

我让 Claude Code 修一个 Bug,它却重构了半个项目

来源:互联网 时间:2026-07-14 07:22:06

我让 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 更像是 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 编程真正难的地方,从来不是让它开始动手。

而是让它知道什么时候该停下来。