主题
CLAUDE.md 深度分析
一、为什么需要 CLAUDE.md
1.1 核心问题:每次对话都是"失忆"的
Claude Code 每次新会话都从一个全新的上下文窗口开始。它不知道:
- 项目用什么构建命令
- 团队有什么编码规范
- 架构上有哪些约定和"坑"
没有 CLAUDE.md,你每次都要重复解释这些背景信息。
1.2 设计动机
CLAUDE.md 本质上是一种持久化的项目记忆。Anthropic 的设计原则是:
把你会反复向新同事解释的事情,写进 CLAUDE.md。
适合放入的内容:
- 构建、测试、lint 命令
- 编码约定和命名规范
- 项目架构的关键决策
- "永远做 X" 类的硬性规则
不适合放入的内容:
- 多步骤的操作流程(应该用 Skill)
- 只对某个子目录有效的规则(应该用
.claude/rules/) - 通用的开发常识(浪费 token)
1.3 与同类方案的对比
| 特性 | CLAUDE.md | .cursorrules | .github/copilot-instructions.md |
|---|---|---|---|
| 层级体系 | 全局 → 项目 → 子目录,多层合并 | 单文件,项目级 | 单文件,项目级 |
| 动态加载 | 子目录文件按需加载 | 全量加载 | 全量加载 |
@import 引用 | 支持(最深 5 层) | 不支持 | 不支持 |
| 路径条件作用域 | .claude/rules/ 支持 glob 匹配 | 不支持 | 不支持 |
| 个人 vs 团队分离 | CLAUDE.local.md(gitignore) | 无 | 无 |
| 组织级策略 | 支持 Managed Policy 位置 | 无 | 无 |
二、CLAUDE.md 的实现规则与规范
2.1 文件层级与加载顺序
CLAUDE.md 存在五个层级,优先级从低到高:
优先级低 ──────────────────────────────────────────── 优先级高
Managed Policy 用户级 项目级 本地个人 子目录
/etc/claude-code/ ~/.claude/ ./CLAUDE.md ./CLAUDE. 子目录/
CLAUDE.md CLAUDE.md .claude/CLAUDE.md local.md CLAUDE.md
(gitignore) (按需加载)加载机制:
- 启动时,从当前工作目录向上遍历目录树,收集所有
CLAUDE.md和CLAUDE.local.md - 同一目录内,
CLAUDE.local.md追加在CLAUDE.md之后 - 所有文件拼接(concatenate)而非覆盖
- 子目录的 CLAUDE.md 不在启动时加载,而是在 Claude 读取该子目录文件时才加入上下文
- Managed Policy 位置的文件不可被排除,确保组织级规则始终生效
2.2 @import 引用机制
markdown
# CLAUDE.md 中的引用语法
参考 @README.md 了解项目概述,参考 @package.json 了解可用命令。
# 额外指引
- Git 工作流 @docs/git-instructions.md规则:
- 支持相对路径和绝对路径
- 相对路径基于包含引用的文件所在目录解析,而非工作目录
- 最大递归深度 5 层
- 首次遇到外部引用时会弹出审批对话框
2.3 .claude/rules/ 条件规则
markdown
---
paths:
- "src/api/**/*.ts"
---
# API 开发规则
- 所有 API 端点必须包含输入验证
- 使用标准错误响应格式- 没有
paths前置字段的规则文件在启动时无条件加载 - 有
paths的规则仅在 Claude 读取匹配文件时触发 - 支持 glob 模式和花括号展开:
src/**/*.{ts,tsx}
2.4 大小与格式规范
| 维度 | 建议 |
|---|---|
| 长度 | 每个 CLAUDE.md 控制在 200 行以内 |
| 格式 | Markdown 标题 + 列表结构化组织 |
| 指令 | 具体可验证("使用 2 空格缩进" 而非 "格式化好代码") |
| 一致性 | 不同文件间不要有矛盾规则,否则 Claude 会随意选一个 |
| 注释 | HTML 块注释 <!-- --> 会被剥离不消耗 token,代码块内的注释保留 |
2.5 claudeMdExcludes 排除机制
大型 monorepo 中可排除不相关的 CLAUDE.md:
json
// .claude/settings.local.json
{
"claudeMdExcludes": [
"**/monorepo/CLAUDE.md",
"/home/user/monorepo/other-team/.claude/rules/**"
]
}三、CLAUDE.md 如何与 System Prompt 结合
3.1 五层注入架构
Claude Code 采用分层上下文注入:
┌─────────────────────────────────────────────────────────┐
│ Layer 1: System Prompt │
│ 核心安全规则、工具定义、行为约束 │
│ → 持久存在于整个会话 │
├─────────────────────────────────────────────────────────┤
│ Layer 2: CLAUDE.md + system-reminder │
│ 项目约定,包裹在 <system-reminder> 标签中 │
│ → 每条消息都注入 │
├─────────────────────────────────────────────────────────┤
│ Layer 3: Slash Commands │
│ 用户触发的一次性工作流指令 │
├─────────────────────────────────────────────────────────┤
│ Layer 4: Skills │
│ 按需加载的能力模块(从 SKILL.md 加载) │
├─────────────────────────────────────────────────────────┤
│ Layer 5: Sub-Agents │
│ 隔离执行环境,仅返回最终结果 │
└─────────────────────────────────────────────────────────┘3.2 具体注入方式
关键事实:CLAUDE.md 内容作为 user message 注入,位于 system prompt 之后,而非 system prompt 的一部分。
这是 Anthropic 官方文档明确说明的:
CLAUDE.md content is delivered as a user message after the system prompt, not as part of the system prompt itself.
注入时使用 <system-reminder> 标签包裹,并标注来源:
xml
<system-reminder>
CLAUDE.md (project root):
# CLAUDE.md
本文件为 Claude Code 在本仓库中工作时提供指导。
## 常用命令
...
</system-reminder>这种设计的含义:
<system-reminder>标签告诉模型:这是上下文背景,而非强制指令- Claude 会尽力遵循,但不保证严格执行
- 模型会根据当前任务的相关性自行判断是否采纳某条规则
- 如果需要 system prompt 级别的强制注入,应使用 CLI 的
--append-system-prompt参数
3.3 与 /compact 的交互
- 项目根目录的 CLAUDE.md 在
/compact后会从磁盘重新读取并重新注入 - 子目录的 CLAUDE.md 不会自动重新注入,需等到 Claude 再次访问该子目录
- 仅在对话中口头说的指令在 compact 后会丢失——这正是写入 CLAUDE.md 的价值
四、如何验证 CLAUDE.md 的有效性
4.1 基础验证:确认文件被加载
# 在 Claude Code 会话中执行
/memory/memory 命令会列出当前会话加载的所有 CLAUDE.md、CLAUDE.local.md 和 rules 文件。如果文件未出现在列表中,说明 Claude 根本看不到它。
也可以使用 InstructionsLoaded Hook 来记录哪些指令文件被加载、何时加载、为什么加载:
json
// .claude/settings.json
{
"hooks": {
"InstructionsLoaded": {
"command": "echo \"Loaded: $CLAUDE_INSTRUCTIONS_FILES\" >> /tmp/claude-instructions.log"
}
}
}4.2 金丝雀测试(Canary Test)
在 CLAUDE.md 中放入一条容易验证的特殊规则:
markdown
## 编码约定
- 所有新函数必须以 `# MARK:` 注释标记所属模块然后让 Claude 生成代码,检查是否遵循。如果这条规则被忽略,其他规则很可能也被忽略。
4.3 对比实验
| 步骤 | 操作 |
|---|---|
| 1. 基线 | 移除/重命名 CLAUDE.md,向 Claude 提问一个代码生成任务 |
| 2. 实验 | 恢复 CLAUDE.md,用同样的提问重新开始会话 |
| 3. 对比 | 检查生成代码的风格、命令使用、架构决策是否符合 CLAUDE.md 中的规则 |
可量化的指标:
- token 效率:有 CLAUDE.md 时平均减少约 63% 的输出 token(减少不必要的解释和客套话)
- 代码评审迭代次数:维护 CLAUDE.md 的团队减少约 34% 的代码评审轮次
- 格式/命名错误率:减少约 80%
4.4 直接对话测试 vs CLAUDE.md 对比
- 在对话中直接告诉 Claude 一条规则,验证它能否遵循
- 把同样的规则只写在 CLAUDE.md 中,开启新会话验证
如果规则在直接对话中有效但在 CLAUDE.md 中无效,说明是注入/加载问题(文件位置错误、被排除等),而非规则本身的问题。
4.5 注意力衰减的诊断
CLAUDE.md 越长,后面的规则越容易被忽略。诊断方法:
markdown
# CLAUDE.md
## 规则 A(靠前位置)
所有变量用 snake_case
## 规则 B(靠后位置)
所有函数必须包含 docstring分别让 Claude 生成代码,统计规则 A 和规则 B 的遵循率。如果 B 的遵循率明显低于 A,说明文件过长导致注意力衰减。
缓解策略:
- 将最重要的规则放在开头
- 控制总长度在 200 行以内
- 将低频规则移到
.claude/rules/中按路径条件加载 - 使用
@import将详细内容拆分到外部文件
4.6 长会话中的持久性验证
在一个较长的会话中(20+ 轮对话后),再次要求 Claude 执行一个受 CLAUDE.md 规则约束的任务。如果规则不再被遵循:
- 使用
/compact压缩上下文(根目录 CLAUDE.md 会被重新注入) - 或开启新会话
这验证了 CLAUDE.md 在长会话中的衰减程度以及 /compact 的恢复效果。
五、总结
CLAUDE.md 不是配置文件,而是"给 AI 同事的备忘录"。
它的执行依赖模型的理解和遵循意愿,而非代码层面的强制。
写得越具体、越简洁、结构越清晰,被遵循的概率越高。核心认知:
- 注入位置:作为 user message(非 system prompt),用
<system-reminder>包裹 - 加载机制:向上遍历目录树拼接,子目录按需加载
- 非强制性:Claude "尽力遵循"而非"必须执行"
- token 成本:每次会话都消耗上下文窗口空间
- 有效性随长度递减:200 行以内效果最好,超过后注意力衰减显著