目录
你问 Claude Code 是否读过 CLAUDE.md,它回答读过,却仍然跳过你要求的测试。这时要区分指令根本没有传入模型,以及指令传入后没有得到遵守。“我读过了”这一回答无法证明任何一种情况。
Cursor 的 .cursor/rules、GitHub Copilot 的 .github/copilot-instructions.md 和 Codex CLI 的 AGENTS.md 也是如此:文件从哪里加载、何时适用,各工具并不相同。文件被加载,与模型遵守其中的指令,是两个问题。
先说结论,处理分三步。首先查看文件是否已被加载。已加载却没有被遵守的规则,改写成事后能够核实是否遵守的句子。仍然希望每次都必定执行的处理,交给 Hooks 或 CI。Claude Code 官方也说明,CLAUDE.md 是“上下文,而不是强制执行的配置”,如果想不依赖 Claude 的判断而阻止某个操作,应使用钩子。
本文依次介绍加载、压缩后的恢复、指令冲突等五项检查,以及排查步骤和规则的改写示例。
规则为什么被忽略
以及如何建立检查机制
1. AI 为什么不遵守规则:五项检查
1. 文件过长,规则被淹没
Claude Code 官方文档建议每个 CLAUDE.md 文件少于 200 行,理由是“较长的文件会消耗更多上下文,并降低遵守程度”。200 行并不是加载的截断位置,4 MiB 以内的 CLAUDE.md 会被完整加载(超过 4 MiB 的文件会被跳过)。文件过长时发生的,不是后半部分不再被读取,而是内容被读取之后,各条规则更难得到遵守。
2. 长会话中的自动压缩
Claude Code 的 /compact 会压缩对话,但项目根目录的 CLAUDE.md 会在压缩后从磁盘重新读取,并重新注入上下文。子目录中的 CLAUDE.md 和按路径适用的规则,则在读取相关文件时重新加载。根据官方文档,压缩后消失的指令必属以下三种之一:① 只在对话中交代过;② 位于尚未重新加载的子目录 CLAUDE.md 中;③ 位于尚未触及目标文件的路径规则中。想保留对话中决定的事项,就把它写进 CLAUDE.md。
3. 指令冲突与适用范围
如果“提交前先测试”和“这次跳过测试”同时存在,适用哪一条就要由模型判断。Claude Code 官方说明,两条规则相互矛盾时,Claude 可能会任意选择其中一条。应定期对照项目、个人和目录级指令,消除矛盾;如果允许例外,要写到“由谁、以何种方式指示时”为止。想阻止操作本身,应使用权限设置或 Hooks,而不是 CLAUDE.md。
4. 规则含糊或相互矛盾
面对“措辞礼貌一些”“妥善处理”等主观或抽象指令,AI 会自行解释,结果可能与你的预期不同。可以改为能够核实是否遵守的要求,例如“最多写三行”或“使用 Slack API 时调用 chat.postMessage”(改写实例见第 3 节)。
5. 规则文件膨胀或分散
从 CLAUDE.md 普通链接到 SPEC.md,不一定会在启动时加载被链接文件的全部内容。Claude Code 会在启动时展开 @path 导入,但导入内容同样占用上下文。为了整理而拆分文件,与只在需要时加载,是两回事。重复规则出现分歧时,应明确唯一正本与适用范围。
以上 Claude Code 的规格依据 Claude Code 官方记忆文档(截至 2026 年 9 月 21 日)。
2. 如何确认规则是否得到遵守
先确认当前情况。可以向 AI 提出以下问题,并检查回答:
| 问题 | 检查重点 |
|---|---|
| “请逐条列出 CLAUDE.md 中的全部规则。” | 如有遗漏的规则,用 /context 查看该文件是否已被加载 |
| “写代码前,请说明会遵守哪些 CLAUDE.md 规则。” | 在工作前让它回想重要规则。是否遵守,看工作后的差异 |
| “请列出最近五轮中可能违反 CLAUDE.md 的操作。” | 自述只作为线索,与命令历史、退出码及成果文件对照后再确定 |
“读过了”“理解了”这样的回答,既不能证明已加载,也不能证明已应用。能作为证据的,是加载列表中的显示和执行后的成果。
定位原因的四个步骤
- 查看入口。在 Claude Code 的
/context中查看 Memory files 里是否列出了目标 CLAUDE.md 和规则。如果没有,检查文件位置和排除设置(claudeMdExcludes)。如果让 Claude Code 直接加载 AGENTS.md,这份 AGENTS.md 不会出现在该列表中。在默认设置下,查看启动时是否显示no CLAUDE.md found; AGENTS.md loaded: …这一行(从 CLAUDE.md 导入的 AGENTS.md 会出现在列表中)。 - 触发规则的适用条件。对于路径规则,让智能体读取匹配的文件。压缩后若尚未读取该文件,相关规则就没有重新加载。想记录何时加载了什么,可以用
InstructionsLoaded钩子把 CLAUDE.md 和规则的加载写入日志(直接加载的 AGENTS.md 不会触发)。 - 执行小型、无害的任务。让智能体修改可丢弃的示例,并遵守“修改前说出目标文件”“完成后报告测试命令和退出码”等规则。不要用删除生产数据或发布来测试。如果用暗号测试,暗号只写在指令文件中,不要写进问题。
- 独立核验结果。检查差异中是否有意外修改,确认报告的测试确实运行,并核查检查数量是否足够。记录测试时的设置、工具版本和目标文件,其中任何一项改变后,都要重新测试。
例如,“提交前先测试”这条指令已被加载,测试却没有执行,那么改变文件位置也解决不了问题。要改的是规则的写法(见下一节的改写示例)和检查机制。把必需的 CI 检查设为合并条件,就能获得 AI 自述之外的判断依据。
如果加载列表中缺少相关 CLAUDE.md,应先修正启动位置与设置,再考虑加强措辞。确认已加载后仍有违规,再检查指令是否具体、验证流程是否有效。这样就不会把所有失败都归因于“AI 忘了”。
3. 五分钟内可以尝试的改进
1. 区分常用规则与按需读取的细节
可以参考 Claude Code 官方“少于 200 行”的建议,但重点是减少重复和多余解释,而非追求某个行数。例如:
- 核心规则(10–20 行)→ CLAUDE.md 开头
- 详细服务规格 → 独立的 SPEC-xxx.md 文件
- 历史与背景 → docs/ 目录
把细节移到其他文件后,要在入口文件写清各类任务开始前应读什么。如果每次会话仍导入全部内容,拆分文件并不会减少启动上下文。需要按条件加载时,可使用路径规则或技能。
2. 把规则改写成“能够核实是否遵守的句子”
对于已加载却没有被遵守的规则,先看其中是否写明了“做到什么才算遵守”。Claude Code 官方也建议把指令写得具体到可以验证,并举例说:不要写“测试你的更改”,而要写“提交前运行 npm test”。再进一步写出失败时的做法和例外条件,就会变成下面这样。
| 改写前 | 改写后 | 事后能判定的内容 |
|---|---|---|
| 先测试再提交 | 提交前运行 npm test,确认退出码为 0。失败时不要提交,并报告失败的测试名称。只有在用户明确指示时,才可以跳过测试 | 执行的命令、退出码、跳过的理由 |
| 把代码整理干净 | 缩进使用 2 个空格 | 查看差异就能发现违规 |
| 把文件整理好 | API 处理程序放在 src/api/handlers/ | 看新文件放在哪里就能判断 |
| 写清楚易懂的提交信息 | 第一行以 feat: fix: docs: 之一开头,并控制在 50 个字符以内 | 可以在提交历史中逐条判定 |
改写后的句子,可以通过差异、命令历史和退出码判定是否得到遵守。一旦写成可判定的形式,之后交给 Hooks 或 CI 时,也能直接作为检查条件(第 4 节)。
3. 标明优先级
重要性标记有助于人和 AI 理解意图,但标记本身不能强制执行。例如可以这样定义:
- CRITICAL:违反后可能引发生产事故
- MUST:必须执行
- SHOULD:通常应当执行
- NICE TO HAVE:有余力时可选
“CRITICAL:对生产数据库执行破坏性查询前,必须获得批准”明确了操作与审批条件。要实际拦截未经授权的操作,还需要权限设置或执行前检查。
4. 在对话中重申重要规则
在会话开始时补充“开始工作前,请列出最重要的三条规则。”用这种声明让它回想规则,是否遵守则看工作后的结果。
5. 把完成条件写进计划
在 AI 智能体的任务追踪中加入“核查规则”,明确每一步的完成条件。要求提供命令、退出码和未验证范围,而不只是“已测试”。如果证据栏为空却标记了完成,就不要视为已完成。
4. 长期保障:Hooks、审核与技能
把可判定的条件写成脚本,通过设置控制操作权限。Hooks、CI、AI 审核和技能各有用途。把它们统称为“自动强制执行”,会掩盖未检查的范围。
1. 用 Claude Code Hooks 执行检查
Claude Code 的 Hooks 功能可以在特定工具调用前后运行脚本,建立即使 AI 忘记规则,系统也能拦截操作的机制。
例如,PreToolUse 钩子可以执行以下检查:
- 在
Bash工具执行前识别危险命令(rm -rf、git push --force)并拒绝 - 在
Edit工具执行前检查目标文件权限或锁定状态 - 提交前运行项目专用测试,失败则阻止提交
如果 PreToolUse 钩子需要阻止操作,应返回退出码 2 或相应的拒绝 JSON。失败的测试若只返回 1 和普通文本输出,会被视为非阻断错误,操作仍会继续。PostToolUse 在操作之后运行,不能用于撤销已经完成的操作。
钩子只能在已配置的事件上,拦截脚本实际判定的情况。只监控 Edit 无法覆盖通过 shell 写入文件的路径,简单匹配危险字符串也不全面。应结合权限、沙箱和 CI,并同时测试应放行与应拒绝的输入。
2. 用子智能体分担审核职责
可以利用 Claude Agent SDK 或 Cursor 的子智能体能力,建立专门审核规则的智能体。由审核智能体检查主智能体写出的代码,有机会从另一个角度发现遗漏,但两者仍可能犯相同的错误或漏掉同一问题。
把需要检查的规则、差异和期望的证据(测试名称、退出码)交给审核方。返回的每项指出都应与实际文件或测试结果核对,职责范围之外的部分按未验证处理。
3. 用技能调用可重复的流程
在 Claude Code 中,可以把重复流程写进 .claude/skills/precommit/SKILL.md,并用自己创建的 /precommit 调用。这是自定义示例,并非内置命令。旧版 .claude/commands/ 中的文件仍可使用,但当前文档已将其纳入技能体系。调用流程与所有检查通过是两回事,结束时要查看检查结果。
文件位置与调用方法见官方技能文档。技能中应同时写明操作流程和合格条件,并要求提供步骤实际运行的证据。
4. 用自动化脚本检测违规
可以在 CI 或提交前钩子中,用 grep 检测禁止出现的模式,例如:
- 生产代码中遗留的
console.log - 硬编码的 API 密钥
- 文件开头缺失版权注释
脚本无法检查未实现的规则或范围之外的文件。应测试正常示例、违规示例和读取失败,并显示检查及跳过的数量。例如,十个文件有两个无法读取,其余八个通过,不等于“全部通过”。
5. 各工具的规则设计方法
主要 AI 智能体的规则设计要点
各工具的条件可查阅 Cursor 规则文档、GitHub Copilot 自定义指令和 OpenAI 的 AGENTS.md 指南。Copilot 的路径指令使用 *.instructions.md,哪些功能会读取它,因功能而异。Codex 的 32 KiB 是默认合计字节上限,并非字数或行数。
共同原则是“简洁、具体、优先级明确”。不同工具的文件名和位置不同,但写法上的原则相通。
6. 规则设计的三种反面做法
1. 只写“请遵循最佳实践”
只写这句话,并未定义“最佳实践”。应明确项目采用什么方法,以及如何验证。与其说“适当测试”,不如列出必需的测试命令,并写清失败时应暂停哪一步(第 3 节的改写示例)。
2. 在多个文件中重复同一条规则
同样的提交规范如果同时出现在 CLAUDE.md、SPEC.md 和 README.md,更新时可能造成三份内容不一致。选定唯一正本,其他文件链接到它。
3. 到处写“绝对必须”
对所有条件使用同等强调,反而难以传达优先级。只对后果确实严重的条件使用“CRITICAL”,其余用普通语言说明。强调用得过多,就会失去作用。
总结
规则没有得到遵守时,按加载条件 → 适用范围 → 指令冲突 → 执行结果的顺序排查。根目录 CLAUDE.md 在压缩后也会重新注入,所以压缩后消失的指令,要么只在对话中交代过,要么位于尚未重新加载的下级 CLAUDE.md 或路径规则中。
- 没有被加载:修正文件位置、排除设置和 AGENTS.md 的加载条件
- 已加载却没有被遵守:把规则改写成事后能够核实是否遵守的句子
- 希望每次都必定执行:用 Hooks 或 CI 检查,允许哪些操作则由权限设置规定
完成的证据是执行结果与成果文件,而不是一句“我读过了”。
常见问题
Q1. CLAUDE.md 多长比较合适?
官方建议每个文件少于 200 行,并说明文件越长,消耗的上下文越多,遵守程度也会下降。超过 200 行也不会中途停止加载(4 MiB 以内会完整加载)。只保留每次都需要的规则,只在特定文件中使用的规则移到路径规则。用 @path 导入拆出去的文件同样会在启动时加载,因此上下文用量并不会减少。
Q2. Cursor 应使用 .cursorrules 还是 .cursor/rules/*.mdc?
新配置建议使用 .cursor/rules/*.mdc,保持每个文件一条规则,用 glob 模式指定适用范围。旧版 .cursorrules 是单个文件,容易变得臃肿。
Q3. 规则写得越长,约束就越严格吗?
单凭长度不会使规则更严格。官方也说明,较长的文件会降低遵守程度。如果要补充,就补充可验证的条件和具体示例,并删掉重复和矛盾之处。
Q4. 同一个项目同时使用 Claude Code 和 Cursor 等工具怎么办?
把共享规则的正本集中在 AGENTS.md,各工具特有的设置放在各自的入口。Codex 和 Cursor 支持 AGENTS.md。Claude Code 从 v2.1.277 起,如果工作目录及其上级目录中既没有 CLAUDE.md、.claude/CLAUDE.md,也没有 CLAUDE.local.md,就会直接加载 AGENTS.md。只要存在其中任何一个,默认只会读取它们;哪怕只放了一个个人用的 CLAUDE.local.md,AGENTS.md 也不会再被读取。同时使用 CLAUDE.md 的项目,应在 CLAUDE.md 中写一行 @AGENTS.md 来导入(也可以在 /config 中把 Project instructions 设为 claude-md-and-agents-md,让两者都被读取)。通过 Amazon Bedrock 等外部提供商、关闭了遥测的会话、安装或更新后的第一个会话,以及用 disableAllHooks 等方式停用了钩子的环境中,直接加载不会生效,应改用导入。至于是通过哪条路径读取的,可以用第 2 节的第 1 步来区分。
Q5. AI 回答“读过了”,是否可能其实没读?
回答既不能证明读过,也不能证明没读过。按第 2 节的诊断步骤查看加载列表,再与差异、测试结果和执行记录对照。