CLAUDE.md:项目上下文工程的艺术
系列文章
本篇是 Claude Code 系列的第 4 篇。系列将从安装入门到高级实战,由浅入深地拆解这个终端原生 Coding Agent 的每一个能力。
入门篇
核心篇
3. 内置命令全解:从 /compact 到 /doctor 的实战指南
4. CLAUDE.md:项目上下文工程的艺术(本文)
进阶篇
5. 多文件重构与复杂任务实战
6. Hooks、MCP 与能力扩展
7. Headless 模式与 CI/CD 集成
8. 多 Agent 协作:从 Claude Code 到 Codex
引言:每次重启都是「失忆」
你有没有遇到过这样的场景:
你花了 20 分钟和 Claude Code 讨论项目的六边形架构,Claude 终于理解了你的端口-适配器分层,写出了符合你团队风格的代码。你满意地关掉终端。第二天打开新会话,Claude 又开始往 Controller 里写业务逻辑。
每次新会话,Claude 的记忆都是空白的。
这不是 Claude 的 bug,而是 LLM 的本质——上下文窗口是唯一的”内存”,会话结束就清空。你在上一个会话里教给它的所有项目知识,随着会话一起消失了。
CLAUDE.md 就是 Anthropic 给出的解决方案:一个持久化的”项目记忆”文件,在每次会话开始时自动注入 Claude 的上下文窗口。它不是配置文件,不是文档,而是一份给 AI 的项目说明书。
但写好 CLAUDE.md 是一门艺术——写得太少,Claude 还是会犯老错误;写得太多,Claude 会选择性忽略你的指令。本文将从理论到实践,系统性地拆解这门”上下文工程”。
从 Prompt Engineering 到 Context Engineering
一个术语的进化
2023 年,Riley Goodside(Gray Swan AI 的 prompt engineering 负责人)提出了一个区分:prompt engineering 实际上包含两件事——context engineering(选择和准备相关上下文)和 prompt programming(编写清晰的指令)。
2025 年 6 月,Andrej Karpathy(前 Tesla AI 总监、OpenAI 联合创始人)在社交媒体上写道:
“+1 for ‘context engineering’ over ‘prompt engineering’… 在每一个工业级 LLM 应用中,context engineering 都是在上下文窗口中填充恰到好处信息的精细艺术和科学。”
Shopify CEO Tobi Lutke 更直接:
“我更喜欢 ‘context engineering’ 这个术语。它更好地描述了核心技能:为 LLM 提供足以解决任务的所有上下文的艺术。”
Prompt engineering 关注的是”怎么问”,context engineering 关注的是”给什么信息”。 当你的 AI 应用从单次对话进化到多轮自主 Agent 时,后者的重要性指数级增长。
为什么 Coding Agent 尤其需要上下文工程?
一个聊天机器人只需要理解当前对话。但一个 Coding Agent 需要理解:
- 项目结构:哪些模块在哪里,依赖关系是什么
- 编码规范:命名风格、分层架构、异常处理策略
- 构建系统:怎么编译、怎么测试、怎么部署
- 历史决策:为什么选了 Redis 而不是 Memcached,为什么用六边形架构
- 团队约定:PR 命名规则、commit message 格式、分支策略
这些信息分散在代码、文档、Slack 聊天、和老员工的脑子里。LLM 读代码可以推断出一部分,但很多隐性知识是代码无法表达的。
CLAUDE.md 就是把这些隐性知识显性化的载体。
CLAUDE.md 的加载机制
文件层次结构
Claude Code 在启动时会从多个位置加载 CLAUDE.md,按优先级从低到高:
1 | ┌─────────────────────────────────────────────────────┐ |
关键加载行为
1. 目录树遍历: Claude Code 从当前工作目录向上遍历目录树,每层都检查 CLAUDE.md。如果你在 ~/projects/myapp/ 启动 Claude,它会加载:
~/projects/myapp/CLAUDE.md~/projects/CLAUDE.md(如果存在)~/CLAUDE.md(如果存在)
2. 拼接而非覆盖: 所有发现的文件会被拼接到上下文中,顺序从文件系统根目录到工作目录。靠近你启动位置的文件排在后面,这意味着项目级指令会覆盖用户级指令(因为它们被读到的顺序更靠后,在注意力机制中权重更高)。
3. 子目录按需加载: 子目录下的 CLAUDE.md 不会在启动时加载,而是当 Claude 读取该子目录的文件时才注入。这是一种惰性加载策略,避免浪费上下文窗口。
4. /compact 之后的行为: 项目根目录的 CLAUDE.md 在 /compact 后会被重新从磁盘读取。但子目录的 CLAUDE.md 不会自动重新注入。
5. HTML 注释被剥离: CLAUDE.md 中的 <!-- 注释内容 --> 在注入前会被移除,所以你可以用 HTML 注释给人类留备注,不消耗 token。
6. 导入语法: 可以用 @path/to/file 语法导入其他文件的内容:
1 | # CLAUDE.md |
最大导入深度为 4 层。
编写 CLAUDE.md 的核心原则
原则一:只写 Claude 猜不到的事
Claude 已经”读过”互联网上几乎所有公开的代码和文档。Java 的命名规范、Spring Boot 的标准结构、RESTful 的设计原则——这些它都知道。
你需要写的是项目特有的、非显而易见的信息:
1 | # ✅ 值得写 |
Anthropic 官方给出的测试标准是:对每一行问自己——如果删掉这行,Claude 会犯错吗?如果不会,就删掉。
原则二:控制在 200 行以内
这不是建议,而是硬性约束。CLAUDE.md 越长,Claude 对每条指令的遵从度越低。超过 200 行后,Claude 会开始”选择性失聪”——排在中间的指令最容易被忽略。
为什么? 从注意力机制的角度理解:CLAUDE.md 作为 user message 注入上下文窗口。当内容过长时,模型的注意力会被稀释,尤其是中间部分(”Lost in the Middle” 问题)。
如果规则确实很多怎么办? 拆分到 .claude/rules/ 目录:
1 | .claude/ |
原则三:强调关键规则
在关键指令前加上 IMPORTANT 或 YOU MUST 可以显著提高遵从度:
1 | ## Database |
原则四:像代码一样维护
CLAUDE.md 不是”写完就忘”的文档。它应该:
- 提交到 Git(团队共享价值)
- 出问题时首先检查(Claude 又犯老错?看看 CLAUDE.md 是不是漏了什么)
- 定期修剪(删除 Claude 已经能自动做对的规则)
- Code Review(规则变更应该像代码变更一样被审查)
实战:为 Java/Spring Boot 项目编写 CLAUDE.md
完整模板
以下是一个面向中大型 Spring Boot 项目的 CLAUDE.md 模板。每一节都标注了”为什么要写这个”:
1 | # 项目:用户中心服务 |
为什么这样组织?
| 节 | 写的原因 |
|---|---|
| 构建与运行 | Claude 无法猜到你的多模块 Maven 结构和具体命令 |
| 项目结构 | 告诉 Claude 在哪里找代码,避免搜错目录 |
| 编码规范 | 团队偏好,尤其是”禁止字段注入”这类非默认选择 |
| 数据库 | Flyway 约定和审计字段要求是团队特有的 |
| 测试规范 | 测试框架选择、命名约定、断言库偏好 |
| API 设计 | URL 风格、版本策略、错误格式 |
| 常见陷阱 | 最有价值的部分——这些是 Claude 反复踩坑的地方 |
.claude/rules/ 目录:模块化管理
为什么需要拆分?
当项目规则超过 200 行,或者不同模块有不同的编码规范时,单一 CLAUDE.md 就力不从心了。.claude/rules/ 提供了模块化方案。
基本结构
1 | .claude/ |
所有 .md 文件会被递归发现,子目录也支持。
路径特定规则(Path-specific Rules)
这是 rules 目录最强大的特性。通过 YAML frontmatter 的 paths 字段,可以让规则只在 Claude 处理特定文件时才加载:
1 | # .claude/rules/migration-rules.md |
1 | # .claude/rules/controller-rules.md |
没有 paths 字段的规则会在启动时无条件加载,和 CLAUDE.md 主文件行为一致。
与 Skills 的区别
| 维度 | Rules | Skills |
|---|---|---|
| 加载时机 | 每次会话启动 / 匹配文件时 | 仅在调用时 / Claude 判断相关时 |
| 内容类型 | 编码规范和约束 | 工作流和操作步骤 |
| 示例 | “使用 4 空格缩进” | “如何执行数据库迁移:步骤 1, 2, 3…” |
Rules 是约束(”不要做什么”),Skills 是能力(”怎么做什么”)。
CLAUDE.md vs Hooks vs Skills:选择正确的工具
Claude Code 提供了三种持久化机制,各有适用场景:
CLAUDE.md:建议性的项目上下文
1 | ## 编码规范 |
特点: Claude 会”尽量遵守”,但不是 100% 保证。适合编码风格、架构决策、命名约定等”软规则”。
Hooks:强制性的自动化
1 | { |
特点: 100% 执行,无例外。适合格式化、lint、安全检查等”硬规则”。
Skills:按需加载的工作流
1 | # .claude/skills/database-migration.md |
特点: 只在需要时加载,不占用每次会话的上下文。适合复杂的多步骤工作流。
选择决策树
1 | 你需要持久化什么? |
Auto Memory:Claude 的”笔记本”
除了你手动编写的 CLAUDE.md,Claude Code 还有一套自动记忆系统——Auto Memory。
工作原理
当 Claude 在工作中发现有价值的信息(比如”这个项目用 ./gradlew 而不是 ./mvnw“),它会主动记录到自己的笔记本中:
1 | ~/.claude/projects/<project>/memory/ |
与 CLAUDE.md 的区别
| 维度 | CLAUDE.md | Auto Memory |
|---|---|---|
| 谁写的 | 你 | Claude 自己 |
| 内容 | 指令和规则 | 学习到的模式和经验 |
| 加载方式 | 每次会话 | MEMORY.md 每次会话(前 200 行),其余按需 |
| 共享 | 提交到 Git,团队共享 | 机器本地,不共享 |
| 可控性 | 你完全控制 | Claude 决定记什么 |
管理 Auto Memory
- 查看:
/memory命令列出所有记忆文件 - 关闭: 在 settings.json 中设置
"autoMemoryEnabled": false - 编辑: 直接编辑
~/.claude/projects/<project>/memory/下的文件 - 限制: 每个项目 25KB 或 200 行(取先到者)
最佳实践: 让 Auto Memory 记录 Claude 自己发现的项目细节,而你在 CLAUDE.md 中写团队共识和编码规范。两者互补,不冲突。
横向对比:CLAUDE.md vs Cursor Rules vs Copilot Instructions
AI 编码助手普遍采用了”项目配置文件”的思路,但实现方式各有不同:
文件格式对比
| 工具 | 配置文件 | 格式 | 特点 |
|---|---|---|---|
| Claude Code | CLAUDE.md |
纯 Markdown | 最简单,无特殊语法 |
| Cursor | .cursor/rules/*.mdc |
Markdown + YAML frontmatter | 支持条件激活(globs、alwaysApply) |
| GitHub Copilot | .github/copilot-instructions.md |
纯 Markdown | 最简单,单文件 |
| AGENTS.md | AGENTS.md |
纯 Markdown | 跨工具标准(新兴) |
条件激活能力
Cursor Rules 的 frontmatter 支持精细的条件控制:
1 | # .cursor/rules/security.mdc |
CLAUDE.md 通过 .claude/rules/ 的 paths 字段实现类似功能:
1 | # .claude/rules/security.md |
两者思路相同,但 Cursor 的 alwaysApply: false + description 组合更灵活——它可以根据描述自动判断是否需要加载规则,而不仅仅是路径匹配。
生态系统对比
| 能力 | Claude Code | Cursor | GitHub Copilot |
|---|---|---|---|
| 项目规则 | CLAUDE.md + rules/ | .cursor/rules/ | copilot-instructions.md |
| 全局规则 | ~/.claude/CLAUDE.md | Team Rules (Console) | Organization settings |
| 自动记忆 | Auto Memory | 无 | 无 |
| Hooks | 8 种事件钩子 | 有限 | 无 |
| MCP 集成 | 完整 | 完整 | 有限 |
| 子 Agent | 原生支持 | 无 | Copilot Workspace |
| 自定义命令 | .claude/commands/ | .cursor/commands/ | 无 |
Claude Code 的优势在于生态系统完整度——CLAUDE.md 只是记忆层的一部分,配合 Hooks、Skills、Sub-agents、MCP 可以构建完整的自动化工作流。
AGENTS.md:跨工具标准的崛起
AGENTS.md 是一个新兴的跨工具标准,GitHub Copilot、Cursor 等都在逐步支持。如果你的团队同时使用多个 AI 编码工具,AGENTS.md 可以作为共享的基础配置:
1 | # 让 CLAUDE.md 引入 AGENTS.md 的内容 |
或者用符号链接:
1 | ln -s AGENTS.md CLAUDE.md |
反模式:CLAUDE.md 写错了比不写更糟
反模式 1:教程式 CLAUDE.md
1 | # ❌ 错误 |
Claude 不需要你教它什么是 Spring Boot。它需要知道的是你的项目怎么用 Spring Boot。
反模式 2:冗长的 API 文档
1 | # ❌ 错误(500 行 API 文档) |
反模式 3:互相矛盾的规则
1 | # ❌ 矛盾 |
Claude 会随机选择一条遵守。定期审查,消除冲突。
反模式 4:”写好代码”式的废话
1 | # ❌ 无意义 |
这些话没有任何信息量。具体才能执行:
1 | # ✅ 具体 |
反模式 5:经常变化的信息
1 | # ❌ 频繁变化 |
这些信息一周后就过期了。用 Auto Memory 或 Skills 来管理临时状态。
高级技巧
技巧 1:用 # 前缀快速添加规则
在交互会话中,输入 # 前缀可以快速将指令添加到 CLAUDE.md:
1 | > # 禁止使用 @Transactional 在 Controller 层 |
Claude 会将这条规则追加到项目的 CLAUDE.md 中。适合在工作中发现 Claude 的错误后立即修正。
技巧 2:/init 自动生成
对新项目,运行 /init 让 Claude 分析代码库自动生成 CLAUDE.md。它会检测:
- 构建系统和命令
- 测试框架
- 代码风格和模式
- 项目约定
/init 不会覆盖已有的 CLAUDE.md,而是建议改进。
技巧 3:符号链接共享团队规则
1 | # 团队共享的编码规范 |
技巧 4:HTML 注释留人类备注
1 | <!-- |
HTML 注释在注入上下文前被剥离,不消耗 token。
技巧 5:与 AGENTS.md 兼容
1 | # CLAUDE.md |
知识边界:CLAUDE.md 做不到什么
CLAUDE.md 是建议性的,不是强制性的。对于以下场景,CLAUDE.md 力不从心:
| 场景 | CLAUDE.md 的局限 | 正确方案 |
|---|---|---|
| 格式化代码 | Claude 可能忘记 | Hooks(PostToolUse + google-java-format) |
| 阻止危险命令 | Claude 可能忽略 | Hooks(PreToolUse + 安全检查脚本) |
| 强制运行测试 | Claude 可能跳过 | Hooks(Stop + 测试运行) |
| 跨会话保持状态 | 只有指令,没有状态 | Auto Memory |
| 复杂的多步骤流程 | 占用太多上下文 | Skills(按需加载) |
记住:CLAUDE.md 管”知道什么”,Hooks 管”必须做什么”,Skills 管”怎么做”。
总结
CLAUDE.md 不是一个配置文件,而是你与 AI 编码助手之间的项目契约。它回答了一个核心问题:**”Claude,你需要知道什么才能在我们的项目里正确工作?”**
核心要点回顾:
- 上下文工程 > Prompt Engineering——对于 Coding Agent,”给什么信息”比”怎么问”更重要
- 只写 Claude 猜不到的——编码规范、构建命令、架构决策、常见陷阱
- 200 行以内——超出就拆分到
.claude/rules/ - 强调关键规则——
IMPORTANT和YOU MUST显著提高遵从度 - 像代码一样维护——提交到 Git,定期修剪,Code Review
- 选择正确的工具——CLAUDE.md 管建议,Hooks 管强制,Skills 管流程
- 路径特定规则——
.claude/rules/配合paths字段,精准注入
下一篇我们将进入 Claude Code 系列的进阶篇,探讨多文件重构与复杂任务实战——当你的需求不再是”改一个方法”,而是”重构整个认证模块”时,Claude Code 的多文件编辑能力和任务规划能力将如何发挥。
参考资料