《Claude Code 工程化实战》第 3 讲 CLAUDE.md 记忆系统
本讲摘要本讲是记忆层的第一讲、核心目的是把Claude Code 没记忆、所以每次都从零开始这个根本问题讲透。Claude Code 的记忆系统由四个层级组成、按优先级从低到高是用户级~/.claude/CLAUDE.md、项目级./CLAUDE.md、本地级./CLAUDE.local.md、规则目录./.claude/rules/*.md。高层级覆盖低层级同名内容、合并后的总 prompt 在每次启动 Claude Code 时自动注入上下文。本讲的三条主线第一、“为什么要分四级?”——它们对应个人偏好 / 团队规范 / 个人项目笔记 / 分类规则四种不同的治理粒度、单一文件无法同时满足。第二、“CLAUDE.md 应该写什么?”——四条原则精简CLAUDE.md 本身吃 token、具体不要写代码要规范、要写用 ruff 强制 line-length100、回答 WHY/WHAT/HOW、使用渐进式披露主体精简、细则下沉到 rules/。第三、“怎么避免把记忆写崩?”——给出一组反例 vs 正例、以及每周五下午 5 点审查一次 CLAUDE.md的可执行节奏。学完本讲、你应该能为自己的项目写出一份 200 行内、覆盖项目目标 / 技术栈 / 代码风格 / 禁区 / 常用命令五大要素的 CLAUDE.md、并能用claude --debug看到它真的被加载了。 详细内容为什么 Claude Code 需要记忆?这是一个看似废话、实则核心的问题。Claude Code 的本质是一个无状态的 LLM 调用包装器每次你启动claude、它读到的世界就是当前目录的文件 你的 prompt、没有上次我们聊到哪了的概念。你在周一告诉它我们这个项目用 uv 管理依赖、不用 pip、到了周三它已经忘了——你必须再说一遍。这就是 CLAUDE.md 存在的原因。它是 Claude Code 的项目入职文档、在每次启动时自动加载到 system prompt。效果上、它把 Claude Code 的每次重置变成每次都从入职第一天读起、从而让 LLM 的无状态特性不再是个缺陷。很多团队低估了这件事的工程意义。一个 5 万行代码的微服务项目、新人包括 AI需要消化的隐含信息包括用了什么 ORM、单元测试用什么框架、哪个目录是给财务团队保留的、PR 必须跑通哪些检查、commit message 怎么写……这些信息如果靠每次对话口述、既慢又容易漏。CLAUDE.md 一次性沉淀、每次都生效。从工程治理角度、CLAUDE.md 还有一个隐含价值它把项目惯例从老员工的脑子里外化到机器可读的文本、新人包括 AI不再需要师徒制才能学会。文档化本身就是治理。四级记忆层级从个人偏好到分类规则Claude Code 的记忆不是单一文件、而是四个层级的文件树。它们按加载顺序低优先级先加载、高优先级后加载、可覆盖低优先级组成最终注入上下文的 system prompt:层级 1用户级 (~/.claude/CLAUDE.md)位置在用户家目录下、跨项目生效。典型的内容个人编码偏好“我偏好 type hint 优先于 docstring”、个人快捷命令“请用 ripgrep 不用 grep”、个人禁区“不要替我发邮件、推 git”。这是你作为独立开发者的偏好、不带项目属性。治理粒度全局。一般 50-200 行就够、超过 500 行就该拆。层级 2项目级 (./CLAUDE.md)位置在项目根目录、与代码一起提交到 git。典型内容项目目标、用户画像、技术栈、目录结构、代码风格、PR 流程、禁区“不要碰 src/billing/”、常用命令测试、lint、build。这是项目 DNA、新人包括 AI读完就能上手。治理粒度团队共享。必须 commit 到 git、所有协作者都受益。层级 3本地级 (./CLAUDE.local.md)位置也在项目根目录、但加入.gitignore、不进版本库。典型内容本机特有的路径“我的 dev DB 在 localhost:5433、不是默认端口”、个人项目笔记“我刚发现 fastapi 的一个边界行为、记住一下”、调试用提示“现在在排查 race condition、所有改动都跑 3 次”。治理粒度个人、只对本机有效。适合临时性、个人性的项目笔记。层级 4规则目录 (./.claude/rules/*.md)位置在.claude/rules/目录下、按主题拆成多个 .md 文件。典型拆分rules/python-style.md(PEP 8 细则、rules/db-migration.md迁移流程、rules/security.md安全审计清单、rules/api-design.md(RESTful 规范。每个文件可以加 frontmatter 声明生效条件比如只在 src/api/ 下生效。治理粒度主题分类。当 CLAUDE.md 主体超过 300 行时、就该拆出 rules/。层级位置进 git?典型内容行数建议加载优先级用户级~/.claude/CLAUDE.mdn/a在家目录个人编码偏好、个人快捷命令、个人禁区50-200最低项目级./CLAUDE.md✅ 必入项目目标、技术栈、目录结构、代码风格、禁区、常用命令100-300中本地级./CLAUDE.local.md❌ 必须 gitignore本机特殊路径、个人项目笔记、调试上下文20-100中规则目录./.claude/rules/*.md✅ 必入分类版按主题拆分的细则数据库迁移、错误处理、安全、API 风格每个 50-200追加到末尾合并规则与优先级四级从低到高合并用户级 → 项目级 → 本地级 → 规则目录。同名配置项、本地级覆盖项目级、项目级覆盖用户级。规则目录的所有 .md 文件按文件名排序后追加到末尾。最终的合并结果会作为 system prompt 的一部分、在每次启动 Claude Code 时注入到上下文窗口。可以用claude --debug命令查看实际的合并结果详见实战代码段。CLAUDE.md 的编写原则四条铁律CLAUDE.md 不是写得越多越好。Claude Code 的上下文窗口是有限的默认 200K tokens、但每次对话都会消耗,CLAUDE.md 本身占用的部分就是机会成本——你写 1000 行的 CLAUDE.md、意味着留给真正对话的空间少了 1000 行对应的容量。原则有四条原则 1精简能 50 行讲清楚的事不要写 200 行。每个项目 CLAUDE.md 在 100-300 行之间最佳超过 500 行就该拆出 rules/。精简的方法用列表不用段落、用代码块不用描述、只写AI 不知道的事AI 已经知道 Python 怎么写、不需要你再说一遍。原则 2具体不要写代码要规范、要写用 ruff,line-length100、启用 isort。不要写测试要全面、要写pytest、覆盖率门槛 80%、新代码必须 100%“。越具体、AI 越不需要猜。判断标准把这条规则删掉、AI 会犯什么错?如果会犯具体可描述的错、就保留如果只是更好而非必须”、就删掉。原则 3回答 WHY/WHAT/HOW好的 CLAUDE.md 不仅是做什么、还包括为什么。例“我们用 uv 不用 poetry(because:uv 比 poetry 快 10 倍、CI 节省 3 分钟/次”。AI 知道 WHY 后、在边缘情况下能自己判断只知道 WHAT 时、遇到规则没说的情况就会乱猜。WHAT具体行为用什么工具、跑什么命令、禁止什么操作。WHY行为背后的原因为什么不用 poetry、为什么不让 AI 碰 src/billing/。这让 AI 在规则没说的情况下仍能做出合理判断。HOW执行细节具体命令、具体参数、具体路径。原则 4渐进式披露CLAUDE.md 主体只写最高频 20% 的规则、剩下的 80% 拆到 rules/ 或外部文档用参见 docs/xxx.md引用。Claude Code 支持按需加载它会根据当前任务自动决定要不要读 rules/ 下的某个文件、而不需要你每次手动指定。渐进式披露的实现要点CLAUDE.md 主体不超过 300 行每条 rules/*.md 控制在 50-200 行用清晰的文件名让 AI 一眼看出这个 rules 文件管什么比如 rules/db-migration.md 比 rules/rules1.md 好;rules 文件首行用一句话说明本文件何时被加载。一个反例 vs 一个正例看一个真实项目中常见的错误CLAUDE.md:# 项目说明 这是一个 Web 项目。请写好代码,注意测试,做好文档。 ## 技术 - 后端:Python - 前端:React - 数据库:PostgreSQL ## 注意事项 - 注意性能 - 注意安全 - 注意代码质量这个 CLAUDE.md 等于没写。它只告诉了 AI这项目用 PythonAI 看 requirements.txt 就知道了、其他全是空话。AI 看完后行为不会有任何变化。同一个项目的正确CLAUDE.md:# CLAUDE.md —— OrderFlow 订单系统 ## 项目目标 OrderFlow 是 B2B 订单流转系统,服务 200 中小电商客户,日均处理 50K 订单。 核心约束:**订单一旦支付,不能丢**。 ## 技术栈 - Python 3.12 FastAPI 0.115 - PostgreSQL 15(主库) Redis 7(缓存/锁) - SQLAlchemy 2.0(async) Alembic 迁移 - 前端:React 18 TypeScript 5(由前端组维护,不要碰) - 部署:Kubernetes ArgoCD ## 目录结构(只列AI 经常动的) - src/orders/ # 订单核心逻辑 - src/payments/ # 支付集成(高风险,改动前必须 review) - src/billing/ # 财务(交给财务组,**绝对禁区**) - migrations/ # Alembic 迁移 - tests/unit/ # 单元测试 - tests/integration/ # 集成测试 ## 代码风格 - ruff(line-length100,target-versionpy312) - mypy strict 模式 - 优先 type hint 优先于 docstring - 公开函数必须有 docstring(Google 风格) ## 禁区(碰之前先问) - src/billing/ 整个目录(财务组专用) - 任何修改 migrations/ 已发布文件的 PR(必须新建迁移文件) - 涉及 user_pii 字段的代码改动(隐私合规) ## 常用命令 - 跑测试: make test(等价于 pytest -x --covsrc --cov-fail-under80) - 跑 lint: make lint(等价于 ruff check . mypy src) - 起 dev: docker compose up -d uvicorn src.main:app --reload - 跑迁移: alembic upgrade head(永远不要手动改 migrations/ 里的文件) ## 渐进式披露:详细规范按主题拆分 - 数据库迁移规范:见 [rules/db-migration.md](.claude/rules/db-migration.md) - 错误处理规范:见 [rules/error-handling.md](.claude/rules/error-handling.md) - 安全审计清单:见 [rules/security.md](.claude/rules/security.md)两份 CLAUDE.md 字数相近都约 100 行、但后者让 AI 的行为产生 10 倍差异它知道项目的绝对禁区、知道测试覆盖率门槛、知道迁移文件不能手动改。这些都是不写出来 AI 就会犯的错。原则反例正例精简800 行的 CLAUDE.md、什么都写200 行主体 拆出 rules/具体“代码要规范”“用 ruff,line-length100、启用 isort”WHY/WHAT/HOW“我们用 uv”“我们用 uv 不用 poetry(uv 比 poetry 快 10 倍、CI 节省 3 分钟/次”渐进式披露所有规则挤在 CLAUDE.md 主体主体写高频 20%、细则在 rules/ 按需加载Auto Memory跨会话的自动记忆CLAUDE.md 是显式记忆——你写什么它记什么。但还有一种隐式记忆Auto Memory。当 Auto Memory 开启时、Claude Code 会在以下场景自动写一条记忆到~/.claude/memories/:场景 1你纠正了 Claude 的错误“不对、这里用 uv 不用 poetry”——Claude 会自动写一条项目用 uv 不用 poetry到记忆库。场景 2Claude 重复犯了同一个错——会自动写一条以后处理 X 任务时、先做 Y作为提醒。场景 3你让 Claude 长期跟踪某个项目——Claude 会写用户正在做 Z 项目、关注点包括 A/B/C。Auto Memory 的本质是LLM 自我反省的副产品——它把我之前犯过这个错沉淀成可复用的记忆。但要注意Auto Memory 是基于概率的、不是 100% 准确。AI 可能会记住错的偏好比如你某次临时用了 pip、它会记住用户偏好 pip。所以关键性规则必须显式写在 CLAUDE.md 里、不要依赖 Auto Memory。建议Auto Memory 当作草稿本用、关键规则显式写 CLAUDE.md。两层都启用、效果最好。记忆系统与其他模块的关系CLAUDE.md 不是孤立的、它和后续模块深度耦合。理解这些耦合能帮你避免单点失败与 SubAgents 的关系SubAgent 会继承主对话加载的 CLAUDE.md、除非子代理目录里有自己的 CLAUDE.md子代理级的覆盖主对话。所以写子代理时、在子代理目录放一份子代理专用的 CLAUDE.md、比让主 CLAUDE.md 写得很长更好。与 Rules 的关系Rules 是 CLAUDE.md 的分类版。CLAUDE.md 写主体、Rules 写细则。两者都进 system prompt。区别Rules 支持 frontmatter 声明生效条件“只在 src/api/ 下生效”,CLAUDE.md 不支持。与 Skills 的关系Skills 的 description 字段会引用 CLAUDE.md 里的项目背景比如用 uv 不用 poetry。CLAUDE.md 写清楚了、Skill 的 description 才能写准确。与 Hooks 的关系Hooks 经常需要读 CLAUDE.md 来理解项目比如 PreToolUse 拦截修改 src/billing/就需要 CLAUDE.md 声明这个目录是禁区。这个关系链意味着CLAUDE.md 写错了、会污染下游所有模块CLAUDE.md 写好了、下游模块的描述/配置都可以更精简。第 3 讲看似只是一个文件、实际上是整个工程治理的根。️ 实战代码 第 3 讲配套一个真实可用的 CLAUDE.md 最小完整版# CLAUDE.md —— 项目名 ## 1. 项目目标 - 服务谁:用户群体 - 解决什么问题:一句话核心价值 - 关键约束:3-5 条不可妥协的约束,例如数据不能丢/延迟必须 100ms ## 2. 技术栈 - 语言:版本 - 框架:核心框架 版本 - 数据库:主库 缓存 - 部署:运行环境 ## 3. 目录结构(只列AI 经常动的) - src/module1/ # 职责 - src/module2/ # 职责 - src/禁区/ # 为什么是禁区 ## 4. 代码风格 - linter:工具名 关键配置 - formatter:工具名 关键配置 - type checker:严格程度 - 命名约定:几条最重要的 ## 5. 禁区(碰之前先问) - 目录/文件 1:为什么 - 操作类型 1:为什么 ## 6. 常用命令 - 跑测试:命令 - 跑 lint:命令 - 起 dev:命令 - 跑迁移:命令 ## 7. 渐进式披露 - 详细规范见 [.claude/rules/](.claude/rules/) - API 文档见 [docs/api.md](docs/api.md) 第 3 讲配套验证 CLAUDE.md 真的被加载了# 方法 1:用 --debug 启动 Claude Code,看实际注入的 system promptclaude--debug# 启动后看输出里的system prompt部分,# 应该能看到你的 CLAUDE.md 内容被合并注入# 方法 2:在对话里直接问 Claude# 请告诉我,你读到了几个 CLAUDE.md?分别是什么内容?# Claude 会列出它加载的所有 CLAUDE.md(用户级/项目级/本地级)# 方法 3:用 /memory 命令(如果版本支持)# /memory# Claude 会展示当前会话加载的所有记忆文件路径# 方法 4:把加载验证作为 CLAUDE.md 自身的一部分# 在 CLAUDE.md 末尾加:# ## 自检# 每次启动时,在第一条响应里报告:你读到了哪些 CLAUDE.md? 来自哪几个层级? 第 3 讲配套CLAUDE.local.md 的典型场景# CLAUDE.local.md —— 只在本机生效,不入 git ## 本机特殊配置 - 数据库:localhost:5433(不是默认 5432,因为我本地有旧项目占用了 5432) - Redis:localhost:6380 - 测试用的 S3 mock 在 ~/mock-s3/ ## 当前调试上下文 - 正在排查订单超时的 race condition - 涉及文件:src/orders/timeout.py、src/payments/callback.py - 改了之后跑 make test-orders 3 次,确认无 flaky ## 个人偏好 - 解释代码时,先用一句话说意图,再贴代码 - 不要主动加我不需要的 type hint - 涉及 SQL 的改动,先列 SQL 再写 Python 第 3 讲配套用 Rules 拆分类规范# 在项目根目录建分类规则目录mkdir-p.claude/rules# 按主题拆 CLAUDE.md 里的细则touch.claude/rules/db-migration.mdtouch.claude/rules/error-handling.mdtouch.claude/rules/security.mdtouch.claude/rules/api-design.mdtouch.claude/rules/frontend-style.md--- # .claude/rules/db-migration.md # 加载条件:任何涉及 migrations/ 目录或 alembic 命令的任务 --- # 数据库迁移规范 ## 绝对禁止 - 不要手动修改已经合并到 main 的迁移文件 - 不要在迁移里写数据回填(SQLAlchemy 迁移应该只改 schema) ## 正确流程 1. 新建迁移: alembic revision --autogenerate -m add user_phone 2. 在 upgrade()/downgrade() 里只写 schema 变更 3. 数据回填单独写一个一次性脚本 4. 跑 alembic upgrade head 验证 5. PR 标题前缀:[migration] 方便 reviewer 识别⚠️ 常见坑⚠️ CLAUDE.md 写成百科全书最常见的错误把 CLAUDE.md 当成项目文档、什么都往里塞——架构图、API 列表、数据库 schema、部署流程……结果一个 CLAUDE.md 写了 1000 行、占满了上下文窗口、真正对话的空间被挤掉。判断标准CLAUDE.md 超过 500 行就该拆。CLAUDE.md 写的应该是AI 不知道就会犯的错、不是项目的所有信息。⚠️ 写模糊规则“注意代码质量”、“测试要全面”、“考虑性能”——这类规则等于没写。AI 读完不知道该做什么具体动作。规则必须具体到可执行工具名、参数、阈值、具体行为。判断标准把这条规则给一个新来的 AI 工程师、他能立刻知道下一步做什么吗?如果不能、就是模糊规则。⚠️ CLAUDE.local.md 不加 .gitignore本地级记忆包含本机特有的路径“我的 dev DB 在 localhost:5433”、调试上下文、个人偏好——这些信息提交到 git 会污染团队。其他协作者拉下来会看到一堆和我无关的配置、甚至和他们的环境冲突。务必在 .gitignore 里加CLAUDE.local.md。这是团队协作的硬规矩。⚠️ 写完不更新CLAUDE.md 不是写一次就完事。项目在演化新框架、新禁区、新命令。如果 CLAUDE.md 三个月没更新、它就已经是历史档案而不是项目 DNA了。建议每周五下午 5 点、花 15 分钟审查 CLAUDE.md——删掉过时的、补上新的、合并重复的。让 CLAUDE.md 保持当下有效的状态。 一句话备忘CLAUDE.md 是项目的宪法写得短而精、胜过写得长而空。下游所有模块的整洁、都依赖这一份文件的克制。