Claude Code 上下文与记忆:CLAUDE.md、规则与自动记忆
Posted on Sat 26 September 2026 in AI 编程 • Sucre Liu
一个反直觉的事实
你在 CLAUDE.md 里写:
不要修改 .env 文件。
然后它改了。你恼火地把它加粗、加星号、换成"严禁",下次它还是可能改。
原因不是它不听话,而是机制层面的错配:CLAUDE.md 的内容是作为一段普通上下文喂给模型的,不是系统级的硬约束。模型会读,会尽量遵守,但没有"必须"。想真正挡住一个动作,得用 PreToolUse 钩子——那是执行层的拦截,不是请求。
理解这条边界,是有效使用记忆系统的前提。本文讲清 Claude Code 的两套记忆机制,以及各自的正确用法。
两套机制,分工不同
Claude Code 靠两个东西跨会话传递知识:
| CLAUDE.md | 自动记忆(auto memory) | |
|---|---|---|
| 谁写 | 你 | Claude 自己 |
| 写什么 | 指令、规则 | 学到的东西、你的偏好 |
| 作用域 | 项目 / 用户 / 组织 | 按仓库,跨 worktree 共享 |
| 加载 | 每次会话 | 每次会话(前 200 行或 25KB) |
| 适合 | 编码规范、构建命令、架构约定 | 你的偏好、你纠正过它的地方 |
一句话:CLAUDE.md 是你让它知道的,自动记忆是它自己记下的。
CLAUDE.md 的加载顺序
CLAUDE.md 可以放在多个位置,作用域从大到小:
| 作用域 | 位置 | 用途 |
|---|---|---|
| 托管策略 | Linux/WSL:/etc/claude-code/CLAUDE.md |
组织级规范,个人设置无法排除 |
| 用户 | ~/.claude/CLAUDE.md |
你所有项目的个人偏好 |
| 项目 | ./CLAUDE.md 或 ./.claude/CLAUDE.md |
团队共享的项目约定 |
| 本地 | ./CLAUDE.local.md |
你的个人项目偏好,记得加进 .gitignore |
关键点:这些文件不是互相覆盖,而是全部拼接进上下文,顺序从文件系统根目录往下到你启动的目录。所以越靠近工作目录的指令,它在读的时候越靠后。同一目录里,CLAUDE.local.md 排在 CLAUDE.md 之后。
还有一层:子目录里的 CLAUDE.md 不会在启动时加载,而是在它读那个子目录的文件时才带进来。这给了你一个天然的"按需加载"武器。
怎么写出它真会遵守的指令
官方给的核心建议是:具体到可验证、简短、结构化。对照着看:
| 别写 | 改成 |
|---|---|
| 正确格式化代码 | 使用 2 空格缩进 |
| 改完测试一下 | 提交前运行 npm test |
| 保持文件组织清晰 | API 处理器放在 src/api/handlers/ |
长度上有个硬参考:单个 CLAUDE.md 控制在 200 行以内。超过之后,消耗的上下文变多,遵守率反而下降。如果你发现它开始"忘"约定,先看长度,再看具体性,最后看有没有互相冲突的条文。
冲突是个隐蔽杀手。用户级的 ~/.claude/CLAUDE.md 说"用 pnpm",项目级说"用 npm",模型可能任选一个。定期清理,比出问题时抓瞎强。
.claude/rules/:把大文件拆开
项目一大,CLAUDE.md 容易膨胀。解法是把指令拆进 .claude/rules/,一个文件一个主题:
your-project/
├── .claude/
│ ├── CLAUDE.md
│ └── rules/
│ ├── code-style.md
│ ├── testing.md
│ └── security.md
更实用的是按路径限定加载。给规则文件加 YAML frontmatter:
---
paths:
- "src/api/**/*.ts"
---
# API 开发规则
- 所有接口必须有输入校验
- 统一使用标准错误响应格式
这条规则只在它读 src/api/**/*.ts 匹配的文件时才进入上下文,平时不占空间。对多团队的大型仓库,这个机制能显著降低噪声。
顺带一个细节:CLAUDE.md 里可以用 @path/to/file 导入其他文件,导入内容在启动时就展开加载。如果你想提及某个路径而不导入,用反引号包起来——`@README` 是文字,@README 会真的把文件读进来。
自动记忆:它自己记了什么
自动记忆默认开启。它会写下四类东西(存成带 type 字段的 markdown):
user:你的角色、专业领域、工作偏好;feedback:你给过的纠正和确认过的做法;project:进行中的工作、决定、它从代码里推不出的信息;reference:外部信息在哪(issue 跟踪、看板等)。
存放位置是每个项目一份:
~/.claude/projects/<project>/memory/
├── MEMORY.md # 索引,每行一条,每次会话加载
├── user_role.md
├── feedback_testing.md
└── ...
只有 MEMORY.md 的前 200 行(或 25KB,先到为准)会在会话开始时加载;具体主题文件是按需读取的。<project> 由 git 仓库推导,所以同一仓库的所有 worktree 共享一份记忆。
几个容易踩的点:
- 它是机器本地的,不跨机器、不同步到云端。
- 它不会从代码里能推出来的东西里记(架构、文件路径、报错修复)。
- 主会话的自动记忆不会注入子代理——除非是 fork 出来的子代理。子代理想要自己的记忆,要单独配置。
想让它记住偏好,直接说就行:"以后用 pnpm,不要用 npm"。它会存进自动记忆。想放进 CLAUDE.md,就说"把这条加到 CLAUDE.md"。
什么时候该把东西挪走
CLAUDE.md 不是垃圾桶。按这个顺序升级你的配置:
| 信号 | 动作 |
|---|---|
| 同一个约定它错第二次 | 写进 CLAUDE.md |
| 多步流程、参考资料 | 放进 skill(按需加载) |
| 只对某类文件生效 | 用带 paths 的 rule |
| 必须每次发生、不能靠模型决定 | 写成 hook |
最后一条再强调一次:"必须"级别的事,别用提示词保证,用 hook 保证。 下一篇讲权限与安全时会展开。
排查:它为什么不照做
按顺序查:
/context——在 Memory files 下确认文件真的被加载了。不在列表里,它根本看不到。- 位置对不对——项目
CLAUDE.md是否在会被加载的目录层级。 - 够不够具体——模糊指令遵守率天然低。
- 有没有冲突——多个文件给了相反指示。
如果你用的是 AGENTS.md(比如项目同时要给别的编码工具用),注意一个默认行为:只有当工作目录及其上层没有 CLAUDE.md / CLAUDE.local.md 时,它才读 AGENTS.md。想两个都读,需要在 /config 里把 Project instructions 设为 claude-md-and-agents-md,或在一个 CLAUDE.md 里用 @AGENTS.md 导入。
小结
CLAUDE.md是常驻上下文,不是硬约束;"必须"的事交给 hook。- 用 200 行作红线,具体到可验证,按路径拆进
.claude/rules/。 - 自动记忆是它自己写的笔记,本地、按仓库、前 200 行常驻,不注入子代理。
- 排障先跑
/context,确认"加载了没有"再谈"遵不遵守"。
下一篇讲权限与安全:权限模式怎么选、沙箱 Bash 到底隔离了什么、settings.json 里哪些规则值得一开始就配。