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 保证。 下一篇讲权限与安全时会展开。

排查:它为什么不照做

按顺序查:

  1. /context——在 Memory files 下确认文件真的被加载了。不在列表里,它根本看不到。
  2. 位置对不对——项目 CLAUDE.md 是否在会被加载的目录层级。
  3. 够不够具体——模糊指令遵守率天然低。
  4. 有没有冲突——多个文件给了相反指示。

如果你用的是 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 里哪些规则值得一开始就配。