Claude Code 不遵守 CLAUDE.md 怎么办:原因分析与解决思路
有开发者反馈 Claude Code 在 CLAUDE.md 里写明限制后仍频繁越界,而同期的 Codex 表现更稳定。本文区分「模型能力波动」与「约束机制没生效」两类问题,分析 CLAUDE.md 被忽略的常见原因,并给出从规则重写、权限与钩子拦截到任务拆分、会话管理的可操作方案。
不少人在同时使用两个 CLI 编程助手时,会遇到一种很具体的落差:一边要求它别动某些目录、别改某些文件,它在会话里答应得很好,回头检查 diff 却发现早就越界了;指出问题后它立刻认错,下一次照旧。另一边的助手却表现稳定,几乎不犯同类错误。于是很自然的结论是——是不是模型变笨了?
这个判断有可能对,但往往不是全部。把「模型能力波动」和「约束机制根本没生效」分开看,能省下很多反复换模型、反复调参数的时间。下面从原因到做法梳理一遍。
先分清两件事
第一类是能力问题:模型在某些推理、重构、跨文件理解任务上确实表现不如预期,或者在不同时间段体感差异明显。这类问题用户能做的有限,主要是换任务类型、换模型、等版本更新。
第二类是机制问题:你写下的规则从头到尾只是一段文本提示,模型「读到」和「遵守」之间隔着一整套执行链路,任何一环松动都会表现为「不听话」。绝大多数「我明明写了它却不听」的抱怨,落在第二类。
判断方法很简单:把同一个任务、同一段规则、同样的仓库状态重复跑三次。如果三次都在同一个位置越界,那基本是机制问题;如果时好时坏、毫无规律,才更可能是能力或采样波动。
CLAUDE.md 为什么会被忽略
规则只是提示,不是权限
CLAUDE.md 通常会在会话开始时被读入上下文,但它是上下文里的建议,不是沙箱、不是校验器,也不会阻止任何一次工具调用。模型完全可以一边「知道」这条规则,一边在下一步调用编辑工具。指望一段文字去约束行为,等于把执行权完全交给模型的当场判断。
长会话里指令会被稀释
会话越跑越长,早期的指令在上下文中的权重会下降,中间还可能经历压缩。表现就是开头几轮很守规矩,跑到后面开始自作主张。有些情况下新开会话也未必立刻读取,需要显式要求它先读规则文件再动手。
写法太软、太散
「不要随便改动其他模块」「保持代码风格一致」这类表述对人是够用的,对模型却是模糊的:哪个算「随便」?风格以谁为准?相比之下,「只允许修改 src/parser/ 下的文件;其余目录只读;改完必须运行 npm test 并贴出输出」是可判定的。规则越接近验收标准,被遵守的概率越高。
多层配置互相打架
用户级、项目级、子目录级的规则文件可能同时存在,内容还可能互相矛盾。一条说「提交前必须跑全量测试」,另一条说「不要执行耗时命令」,模型只能挑一个执行。规则冲突时,它不会报错,只会安静地选一个。
effort 调高不等于更听话
把 effort、thinking 拉满,收益主要体现在复杂推理和长链条规划上。对于「别碰这个文件」这种边界约束,更高的推理预算有时反而意味着更多的探索动作、更多的工具调用,越界机会也随之增加。日常小改动用中档配置往往更快也更稳,难题再拉满。
把软约束变成硬约束
精简并重写规则文件
- 只保留「不写就一定会犯错」的条目,删掉常识性建议,控制篇幅。
- 用祈使句 + 明确路径 + 明确命令,避免形容词。
- 正向描述优先:「修改 X 时同步更新 Y 的测试」比「不要忘记测试」有效。
- 把「完成的定义」写清楚:改哪些文件、跑哪条命令、输出什么证据。
- 排除冲突:检查用户级与项目级规则是否重复或矛盾,只保留一份权威版本。
让它先复述,再开工
在会话第一步加一句固定开场:先读规则文件,然后用三行复述本项目的三条硬性约束和本次任务的验收标准,确认后再动手。复述不是为了形式,而是把规则从「背景文本」提到「当前任务」的位置。任务中途如果发现它开始跑偏,让它重新复述一次,比笼统地说「你又不听话了」有效得多。
用工具层拦截兜底
真正可靠的边界要在模型之外实现,思路有三层:
- 权限白/黑名单。在项目设置里声明允许与禁止的操作,例如把敏感目录的编辑、危险命令、推送操作放进拒绝列表。字段名与匹配语法各版本可能有差异,以官方最新文档为准,改完务必用一次真实的越界操作验证是否真的被拦下。
{
"permissions": {
"deny": [
"Edit(infra/**)",
"Edit(.env*)",
"Bash(git push:*)",
"Bash(rm:*)"
]
}
}
-
工具调用前钩子。支持钩子的工具可以在编辑类调用发生前跑一段脚本,命中受保护路径就直接拒绝并返回原因。这比写在规则文件里强得多,因为拦截发生在执行前,模型没有「先做了再说」的机会。事件名、返回格式同样以官方文档为准。
-
版本控制与 CI 兜底。在独立分支或 worktree 里干活,提交前看 diff;用 pre-commit 钩子和 CI 跑 lint、测试、目录白名单检查。模型可以犯错,但不合规的改动进不了主干。
把任务切小
一次只给一个明确目标:「只修改 src/parser/index.ts 中的错误处理分支,其他文件保持不动,改完运行对应测试并把失败信息贴出来」。大而全的任务描述会逼模型自己规划范围,而规划范围正是越界的高发环节。复杂改造先让它出方案、你确认,再进入执行。
管理会话与环境
- 关键决策、当前进度写进仓库里的文件(如进度记录、决策记录),而不是只留在对话里,压缩或重开后仍然可查。
- 任务切换时开新会话,别在一个长会话里堆十几个不相关的需求。
- 高风险操作前先让它列出「准备执行的动作清单」,你确认后再放行。
如果越界往往伴随着工具调用超时、流中断、跑到一半连接断掉,问题可能出在本地网络或机器休眠上。把这类长任务放到一台长期在线、网络稳定的远程机器上跑,是一种可选做法,例如整机放在境外机房的远程 Mac,按月租用、远程连接使用,能减少因本地环境中断导致的半途状态。但这只解决稳定性,不解决指令遵循,别指望换个环境就变听话。
关于「最近变差」的分歧
讨论里存在两种典型立场。一种认为就是模型侧的能力波动,抱怨集中在某几天的体感,结论是换工具;另一种认为是指令依从度本来就有限,需要靠工程手段约束,配置到位后问题消失。
客观地说,两方都有道理,但体感样本很不可靠:一两天、几个任务,很容易被任务难度、上下文长度、当天是否手滑调了参数所干扰。可行的做法是自建一个小型对照集——挑三到五个有代表性的真实任务,固定提示词和仓库状态,分别用不同配置跑,记录越界次数和返工次数。有了这个基线,再判断是换模型还是改配置,才不至于每隔几天就推翻一次结论。
另外,模型与服务端会持续调整,具体版本行为请以官方发布说明为准;本文不针对任何特定版本做能力判断。
检查清单
| 检查项 | 通过标准 |
|---|---|
| 规则文件 | 篇幅精简、无矛盾、条目可判定 |
| 会话开场 | 已要求复述硬性约束与验收标准 |
| 权限配置 | 实测一次越界操作,确认被拦截 |
| 钩子/CI | 受保护路径的改动无法通过校验 |
| 任务粒度 | 单次目标唯一,含可验证的完成条件 |
| 版本控制 | 独立分支、提交前审查 diff |
| 对照基线 | 有固定任务集,能对比不同配置 |
小结
「写了规则却不听」通常不是因为模型读不懂,而是因为规则停留在建议层,缺少执行层的兜底。优先级排序是:先用权限和钩子把真正的红线焊死,再把规则文件改写成可判定的短句,接着把任务切小并明确验收标准,最后才是调 effort、换模型这类参数层面的尝试。至于「是不是变笨了」,与其靠体感下结论,不如花半小时搭个固定任务集自己测一遍——这个投入的回报,比反复换工具高得多。