1. 为什么你的 Claude Code 每次会话都像“失忆”
如果你用 Claude Code 写过几天代码,大概率遇到过这种场景:昨天刚跟它强调过“这个项目所有接口必须做参数校验”,今天新开一个会话,它又给你生成了一段裸奔的 controller;上周纠正过它“别用 moment.js,我们统一用 dayjs”,这周它又默默 import 了 moment。每次会话都从零开始解释项目规范,时间全花在重复沟通上。
这不是模型变笨了,而是 AI 编程助手的一个天然短板——会话之间没有持久记忆。每次启动,它看到的只有当前工作目录的代码和你在本次对话里说过的话。你昨天说的、上周纠正的,全都不在上下文里。
Claude Code 用一套分层记忆系统来解决这个问题。这套系统由两大部分组成:你主动写给 Claude 的指令记忆(CLAUDE.md 体系),和 Claude 自己写给自己的自动记忆(Auto Memory)。前者是“你告诉它该怎么做”,后者是“它自己记下做过什么、踩过什么坑”。
这篇文章面向需要长期维护上下文一致性的开发者,目标很明确:把记忆配置落到可复制的 settings.json 骨架和CLAUDE.md 模板里,并给出验证记忆是否真的生效的具体动作。不是概念科普,是能直接抄进项目的操作手册。
先给一个全局认知:Claude Code 的记忆不是“一个文件”,而是五层作用域 + 两类记忆源的组合。理解这个分层,你才知道一条规则该写在哪、为什么有时候写了却不生效。
五层作用域从“管得最宽”到“管得最细”依次是:
| 层级 | 位置 | 作用范围 | 谁能改 |
|---|---|---|---|
| 托管策略 | 系统级路径(如/etc/claude-code/CLAUDE.md) | 整台机器所有用户 | IT 统一下发,无法排除 |
| 用户记忆 | ~/.claude/CLAUDE.md | 你本人的所有项目 | 你自己 |
| 项目记忆 | <项目根>/CLAUDE.md或<项目根>/.claude/CLAUDE.md | 随仓库提交,全团队共享 | 团队 |
| 本地记忆 | <项目根>/CLAUDE.local.md | 只属于你、只在本项目 | 你自己(应加 .gitignore) |
| 子目录记忆 | <子目录>/CLAUDE.md | 按需懒加载 | 对应模块负责人 |
加载机制是向上遍历 + 拼接。假设你在D:\projects\my-app\backend启动 Claude Code,它会从当前目录一路向上遍历到文件系统根,把沿途所有CLAUDE.md/CLAUDE.local.md收集起来,按“根 → 当前目录”的顺序拼接进上下文。注意是拼接,不是覆盖——所有指令都会被模型看到并综合权衡。
这里有个很多人误解的点:没有硬性的“后加载覆盖先加载”规则。LLM 的上下文不像 CSS 那样有明确的层叠优先级。Claude Code 确实故意把离工作目录更近(更具体)的文件排在后面加载,位置靠后、离当前对话更近的内容在注意力上通常权重略高,所以项目规则倾向于压过用户全局规则——但这只是软倾向,不是保证。官方文档明确警告:如果两条指令真的互相矛盾,Claude 可能任选其一,行为不可预测。
所以正确的做法不是依赖“后写的赢”,而是定期审查各层文件,主动消除冲突。这也是后面排查章节要重点讲的内容。
2. TaoToken 前置:把 Base URL、Key、Model ID 三件套配好
在深入记忆配置之前,得先把 Claude Code 的接入环境搭好。因为记忆系统的验证动作(比如让它读文件、执行命令、观察是否遵守规则)都需要一个能正常工作的模型端点。我用的是 TaoToken 的接入方式,它兼容 Anthropic 的 API 协议,配置起来比较直接。
Claude Code 的接入核心是三个东西:Base URL、API Key、Model ID。这三件套缺一不可,而且必须写对位置。很多人配完发现报 401 或者local proxy failed,八成是这三个里有一个没对上。
先说 Base URL。TaoToken 的 API 端点是:
https://taotoken.net/api注意这里不加任何 UTM 参数,就是干净的 API 地址。Claude Code 会往这个地址发 Anthropic 格式的请求。
然后是 API Key。你需要去控制台生成一个:
https://taotoken.net/console生成后复制那串sk-开头的密钥,妥善保存——它只显示一次。
最后是 Model ID。Claude Code 默认会用 Anthropic 的模型名,但通过 TaoToken 接入时,你需要确认可用的模型标识。可以在模型对话页面先试一下:
https://taotoken.net/model-chat在对话界面里选一个模型发条消息,确认能正常返回,再把这个 Model ID 填进配置。
三件套的配置位置有两个选择:环境变量,或者 Claude Code 的 settings.json。环境变量适合临时测试,settings.json 适合长期使用。我建议直接用 settings.json,因为记忆系统的很多配置(比如autoMemoryEnabled、claudeMdExcludes)也在这个文件里,集中管理更清晰。
一个最小的 settings.json 骨架长这样:
{ "env": { "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_API_KEY": "sk-你的密钥", "ANTHROPIC_MODEL": "你的模型ID" }, "autoMemoryEnabled": true }这个文件放在~/.claude/settings.json(用户级)或<项目根>/.claude/settings.json(项目级)。项目级的会覆盖用户级的同名配置。
如果你更习惯用环境变量,在 shell 里这样写:
export ANTHROPIC_BASE_URL="https://taotoken.net/api" export ANTHROPIC_API_KEY="sk-你的密钥" export ANTHROPIC_MODEL="你的模型ID"Windows PowerShell 用:
$env:ANTHROPIC_BASE_URL="https://taotoken.net/api" $env:ANTHROPIC_API_KEY="sk-你的密钥" $env:ANTHROPIC_MODEL="你的模型ID"配完之后,先别急着搞记忆系统,跑一个最简单的验证:启动 Claude Code,问它一句“你现在用的是什么模型”。如果它能正常回答,说明三件套通了。如果报错,对照第 5 节的排查表处理。
这里要强调一点:记忆系统的所有验证动作都依赖模型端点正常工作。如果 Base URL 或 Key 配错了,你看到的“Claude 不遵守 CLAUDE.md”可能根本不是记忆问题,而是请求压根没发出去。所以先把接入层跑通,再谈记忆。
另外,如果你打算长期用 Claude Code 做编码和 Agent 任务,可以考虑 Coding Plan,它在连续编码场景下的额度更划算:
https://taotoken.net/coding-plan接入文档在这里,遇到配置细节可以查:
https://taotoken.net/doc3. 可复制配置:settings.json 骨架与 CLAUDE.md 模板
这一节是全文的核心,直接给你能抄的配置。分三块:settings.json 完整骨架、CLAUDE.md 项目模板、以及.claude/rules/的路径作用域规则。
3.1 settings.json 完整骨架
先给一个覆盖记忆系统关键配置的 settings.json。放在<项目根>/.claude/settings.json:
{ "env": { "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_API_KEY": "sk-你的密钥", "ANTHROPIC_MODEL": "你的模型ID" }, "autoMemoryEnabled": true, "autoMemoryDirectory": "~/.claude/projects/my-app-memory", "claudeMdExcludes": [ "**/monorepo/other-team/CLAUDE.md", "**/monorepo/legacy/.claude/rules/**" ] }逐个字段说明:
autoMemoryEnabled控制自动记忆开关,默认是true。如果你想临时关掉,改成false,或者用环境变量CLAUDE_CODE_DISABLE_AUTO_MEMORY=1。
autoMemoryDirectory自定义自动记忆的存储位置。必须是绝对路径或~/开头。不写的话默认在~/.claude/projects/<项目标识>/memory/。写在项目级 settings 时,需要先通过工作区信任确认。
claudeMdExcludes用 glob 模式排除不需要加载的 CLAUDE.md。这个在 monorepo 场景特别有用——当你在team-b/frontend/工作时,向上遍历会把仓库根、甚至中间层其他团队的 CLAUDE.md 全加载进来,白白消耗上下文还可能引入矛盾指令。注意托管策略层的 CLAUDE.md 无法被排除,这是唯一的例外。
如果你用 Claude Code 的本地配置(不进 git),可以再建一个.claude/settings.local.json,把个人偏好放进去:
{ "autoMemoryDirectory": "~/my-personal-memory" }3.2 CLAUDE.md 项目模板
项目根的 CLAUDE.md 是团队共识的沉淀地。官方建议控制在 200 行以内,写具体可验证的指令,比如“用 2 空格缩进”而不是“格式规范一点”。下面是一个可直接用的模板:
# 项目:my-app ## 技术栈 - 后端:Node.js 20 + TypeScript 5 - 前端:React 18 + Vite - 数据库:PostgreSQL 15 ## 构建与测试 - 安装依赖:`pnpm install` - 启动开发:`pnpm dev` - 跑测试:`pnpm test` - 提交前必须跑:`pnpm lint && pnpm test` ## 编码规范 - 缩进用 2 空格 - 所有接口必须做输入校验,用 zod - 日期统一用 ISO 8601 格式 - 禁止使用 moment.js,统一用 dayjs ## 架构约定 - API 层在 `src/api/`,业务逻辑在 `src/services/` - 数据库查询统一走 repository 层,不直接在 service 里写 SQL ## 工作流 - git 提交信息用 Conventional Commits - 详见 @docs/git-instructions.md <!-- 维护说明:本文件由团队共同维护,改动请提 PR -->注意最后那行 HTML 注释——CLAUDE.md 支持 HTML 块级注释<!-- ... -->,注入上下文前会被剥离,所以可以用来写只给人看的维护说明,不占模型上下文。
@docs/git-instructions.md是@import语法,把外部文件内容“钉”进上下文。语法要点:
- 相对路径相对于包含该导入的文件解析,不是工作目录
- 支持绝对路径和
~/家目录路径 - 最大递归深度 4 层
- 代码块和行内代码中的
@xxx不会被解析,想字面提到路径用反引号包住:`@README` - 项目里首次遇到外部导入时会弹一次批准对话框
这里有个关键取舍:@import和纯文本提及路径的本质区别在于内容进不进上下文。@docs/api.md会在启动时立即注入整个文件内容,保证 Claude 看到,但每次会话都消耗 token;而纯文本写“参见 docs/api.md”只是一个字符串,零成本,但 Claude 需要自己决定去读,可能读也可能不读。
选择原则:每次会话都必须遵守的规则用 @import(保证在场);偶尔才需要的参考资料用文本路径提及(省 token,按需读取)。官方那句提醒很到位——“import 帮你组织文件,但不省 token”,它本质上等于把内容复制进了 CLAUDE.md。
3.3 .claude/rules/ 路径作用域规则
当项目规则越写越多,塞在一个 CLAUDE.md 里既难维护又浪费上下文。.claude/rules/目录允许把指令拆成模块化文件,目录下所有.md会被递归发现:
your-project/ ├── .claude/ │ ├── CLAUDE.md │ └── rules/ │ ├── code-style.md │ ├── testing.md │ └── frontend/ │ └── react.md最有价值的能力是路径作用域规则——通过 YAML frontmatter 声明paths,让规则只在 Claude 操作匹配文件时才加载:
--- paths: - "src/api/**/*.ts" --- # API 开发规范 - 所有接口必须做输入校验 - 使用标准错误响应格式 - 每个 handler 必须有对应的单元测试没有paths字段的规则文件则与 CLAUDE.md 一样,启动时无条件加载。个人通用规则可以放在~/.claude/rules/(先于项目规则加载,因此项目规则的实际影响力更高);跨项目共享规则可以直接用符号链接。
顺带解释一下 YAML frontmatter:指 Markdown 文件开头用两行---包起来的元数据块,内容是 YAML 格式的键值对。它给“读这个文件的程序”提供结构化信息,正文才是给人或模型看的内容。这个约定最早来自 Jekyll 等静态博客生成器,如今已是 Markdown 生态的通用惯例。Claude Code 生态里多处用到它:rules 文件的paths、技能文件(SKILL.md)的name/description、子代理定义的模型与工具声明,以及自动记忆文件的元信息。
4. 验证请求:确认记忆真的生效了
配置写完不代表生效。这一节给你一套可执行的验证动作,从接入层到记忆层逐级确认。
4.1 第一步:确认模型端点通
启动 Claude Code,先跑一个不依赖记忆的基础请求:
claude "用一句话说明你现在能做什么"如果正常返回,说明 Base URL、Key、Model ID 三件套没问题。如果报 401,看第 5 节。
4.2 第二步:用 /memory 查看加载了哪些记忆
这是排查记忆问题的第一命令。在 Claude Code 会话里输入:
/memory它会列出当前会话到底加载了哪些记忆文件。你应该能看到:
- 用户级
~/.claude/CLAUDE.md(如果存在) - 项目级
<项目根>/CLAUDE.md - 本地级
<项目根>/CLAUDE.local.md(如果存在) - 自动记忆的
MEMORY.md索引
如果某个你期望的文件没出现在列表里,说明它没被加载——可能是路径不对,或者被claudeMdExcludes排除了。
4.3 第三步:验证 CLAUDE.md 指令被遵守
在 CLAUDE.md 里写一条可验证的具体规则,比如:
## 编码规范 - 所有新建的 TypeScript 文件必须包含文件头注释 `// @file: <文件名>`然后让 Claude 创建一个新文件:
claude "在 src/utils/ 下新建一个 formatDate.ts,导出一个格式化日期的函数"打开生成的文件,看开头有没有// @file: formatDate.ts。有,说明项目记忆生效了;没有,说明 CLAUDE.md 没被加载或指令不够具体。
4.4 第四步:验证自动记忆在工作
自动记忆的验证看界面提示。当 Claude 在会话中读写记忆时,界面会出现“Writing memory”或“Recalled memory”提示。
你可以主动触发一次:在会话里纠正它一个习惯,比如“以后这个项目里所有日期都用 dayjs,不要用原生 Date”。然后观察是否出现 “Writing memory” 提示。如果有,说明 Claude 把这条经验记下来了。
再验证读取:新开一个会话,问它“这个项目里日期处理用什么库”。如果它回答 dayjs,说明自动记忆被成功召回。
你也可以直接去看存储目录:
ls ~/.claude/projects/<项目标识>/memory/应该能看到MEMORY.md和若干主题文件(如debugging.md、api-conventions.md)。全是纯 Markdown,随时可以打开审查、编辑或删除。
4.5 第五步:验证路径作用域规则
在.claude/rules/下建一个带paths的规则文件,比如api-rules.md,声明paths: ["src/api/**/*.ts"],里面写一条“所有 API handler 必须返回{ code, data, message }结构”。
然后让 Claude 在src/api/下改一个文件,观察它是否遵守这条规则。再让它在src/services/下改文件,观察这条规则是否不生效(因为路径不匹配)。如果两次行为符合预期,说明路径作用域规则工作正常。
4.6 第六步:验证 @import 生效
在 CLAUDE.md 里写@docs/api-conventions.md,然后在那个文件里写一条独特规则。新开会话,用/memory确认该文件被加载,再让 Claude 执行一个相关任务,看它是否遵守。
如果@import没生效,检查:路径是否相对于包含导入的文件、递归深度是否超过 4 层、是否在代码块里被反引号包住了。
5. 本篇常见错排查:401、local proxy failed、reading choices、OAuth
这一节对照真实报错,逐个给排查路径。这些错误我在配置过程中基本都踩过一遍。
5.1 401 Unauthorized
现象:启动 Claude Code 后任何请求都返回 401。
原因:API Key 不对,或者 Base URL 配错导致请求发到了错误的端点。
排查:
- 确认
ANTHROPIC_API_KEY是sk-开头且没有多余空格 - 确认
ANTHROPIC_BASE_URL是https://taotoken.net/api,结尾没有斜杠,也没有多余路径 - 去控制台重新生成一个 Key 试试:
https://taotoken.net/api-keys - 检查是否有多个配置源冲突——环境变量和 settings.json 同时存在时,环境变量通常优先
如果 Key 是对的但还报 401,可能是 Key 被禁用或额度耗尽,去控制台确认。
5.2 local proxy failed
现象:报local proxy failed或类似的连接失败。
原因:通常是 Base URL 写错,或者本地网络无法到达端点。
排查:
- 用 curl 直接测端点连通性:
curl -X POST https://taotoken.net/api/v1/messages \ -H "x-api-key: sk-你的密钥" \ -H "anthropic-version: 2023-06-01" \ -H "content-type: application/json" \ -d '{"model":"你的模型ID","max_tokens":100,"messages":[{"role":"user","content":"hi"}]}'如果 curl 能通但 Claude Code 不通,说明是 Claude Code 的配置问题,检查 settings.json 的env字段是否被正确读取。
- 确认没有多余的代理环境变量干扰,比如
HTTP_PROXY、HTTPS_PROXY指向了不可用的地址。
5.3 reading choices 相关报错
现象:报错信息里出现reading choices或响应解析失败。
原因:这通常是响应格式不匹配——请求发出去后,返回的不是 Anthropic 期望的格式。常见于 Base URL 指向了一个 OpenAI 兼容端点而非 Anthropic 兼容端点。
排查:
- 确认 Base URL 是
https://taotoken.net/api,这个端点走的是 Anthropic 协议 - 确认 Model ID 是 Anthropic 系列模型,不要填成 GPT 系列的模型名
- 如果之前配过其他端点,检查环境变量里有没有残留的
ANTHROPIC_BASE_URL覆盖了 settings.json
5.4 OAuth 相关报错
现象:提示需要 OAuth 登录,或者OAuth token expired。
原因:Claude Code 某些功能(比如 Claude Code 官方订阅)走 OAuth 流程。如果你用的是 API Key 接入,不应该触发 OAuth。
排查:
- 确认你没有同时启用官方 OAuth 登录和 API Key 接入,两者会冲突
- 检查
~/.claude/下是否有残留的 OAuth 凭证文件,有的话清理掉 - 确认 settings.json 里没有
oauth相关字段
5.5 Claude 不遵守 CLAUDE.md
这是记忆系统最典型的“软故障”,没有报错,但行为不对。
排查顺序:
- 跑
/memory确认文件确实被加载了 - 检查指令是否够具体——“格式规范一点”这种模糊指令模型无法执行,改成“用 2 空格缩进”
- 排查多层文件之间有没有互相矛盾的规则——冲突时 Claude 可能任选其一
- 需要精确诊断时,用
InstructionsLoadedhook 记录哪些指令文件在何时、为何被加载
5.6 /compact 之后指令丢了
现象:上下文压缩后,之前说的规则不生效了。
原因:项目根的 CLAUDE.md 会在压缩后自动重新注入,但子目录的嵌套 CLAUDE.md 不会——要等 Claude 下次读取那个目录的文件才重新加载。只在对话里口头说过的指令,压缩后就没了。
解决:重要的规则一定要落到 CLAUDE.md,不要只在对话里说。
5.7 CLAUDE.md 太大了
现象:CLAUDE.md 越写越长,启动上下文被占满。
解决:
- 拆成路径作用域规则,放到
.claude/rules/下 - 删掉不是每次会话都需要的内容
- 注意
@import拆分只改善组织结构、不减少 token——它等于把内容复制进来 - 用 HTML 注释
<!-- ... -->写维护说明,注入前会被剥离
6. 选型与长期维护:规则给 CLAUDE.md,经验给 Auto Memory
把两类记忆放在一起对比,选型就清晰了:
| 维度 | CLAUDE.md | Auto Memory |
|---|---|---|
| 谁来写 | 你 / 团队 | Claude 自动 |
| 内容性质 | 规则、指令、标准 | 经验、发现、习惯 |
| 上下文成本 | 全文加载 | 仅索引前 200 行 / 25KB |
| 适合放什么 | 编码规范、架构决策、工作流 | 构建命令、调试心得、易变信息 |
更广义的选型原则——记忆系统不是万能的,官方明确建议分流:
稳定的项目规则 → CLAUDE.md。目标控制在 200 行以内,写具体可验证的指令。
只对某些目录/文件生效的规则 → .claude/rules/ 路径作用域规则。用pathsfrontmatter 精准投放,不占全局上下文。
多步骤操作流程 → Skills。按需加载,不占每次启动的上下文。
必须在固定时机强制执行的动作(如每次提交前 lint)→ Hooks。这一条尤其重要:Hooks 由客户端强制执行,不依赖 Claude 的判断;而 CLAUDE.md 只是“影响行为”,不是硬约束。
经常变化的信息 → 交给自动记忆。构建命令、调试发现、你的纠正反馈,让 Claude 自己积累。
关于自动记忆的存储结构,再补充一下细节。每个项目在用户主目录下有独立目录:
~/.claude/projects/<项目标识>/memory/ ├── MEMORY.md # 索引文件(启动时加载前 200 行或前 25KB) ├── debugging.md # 主题文件(按需读取) ├── api-conventions.md # 主题文件(按需读取) └── ...项目标识基于 git 仓库派生,同一仓库的所有 worktree 和子目录共享一份记忆;不在 git 仓库中则按项目根目录计算。记忆是本机私有的,不跨机器同步。全部是纯 Markdown,你可以随时打开审查、编辑或删除。
自动记忆的加载设计很精巧:启动时只加载MEMORY.md的前 200 行或前 25KB(先到为准),因此 Claude 会主动保持索引精简,把细节挪到主题文件;主题文件不占启动上下文,Claude 需要时才用普通文件工具按需读取。
开关控制有三种方式:/memory命令中直接切换、settings.json 里设"autoMemoryEnabled": false、环境变量CLAUDE_CODE_DISABLE_AUTO_MEMORY=1。子代理(subagent)也可以单独启用自己的持久记忆。
最后说一个日常操作技巧:#快捷键。消息以#开头,内容会被存入记忆:
# 提交前必须先跑测试存储目标不是固定的。较早版本会弹选择器让你挑目标文件;引入自动记忆后的版本由 Claude 根据内容性质判断归属——像“规则/指令”的内容倾向写入 CLAUDE.md,像“经验/发现”的内容倾向写入自动记忆。想精确控制去向,直接在消息里说明:
# 把这条加到项目 CLAUDE.md:所有日期用 ISO 8601 格式。还有一个/init命令值得用:分析代码库自动生成初始 CLAUDE.md(已存在则给出改进建议而非覆盖),会自动发现构建命令、测试方式和项目约定,还会读取.cursorrules、AGENTS.md、.windsurfrules等其他工具的规则文件并吸收其内容。设置环境变量CLAUDE_CODE_NEW_INIT=1可启用交互式多阶段初始化流程。
关于 AGENTS.md 这个跨工具约定,Claude Code 有两条支持路径:一是导入复用,在 CLAUDE.md 里写一行@AGENTS.MD,通用规则放 AGENTS.md 供所有工具共享,Claude 专属规则继续写在 CLAUDE.md 里;二是/init初始化时自动读取并整合其内容。团队同时用多个 AI 编程工具时,这个约定能省掉重复维护规范的麻烦。
用好记忆系统的关键不在于把所有东西都塞进去,而在于理解每类信息的正确归宿:规则给 CLAUDE.md,流程给 Skills,强制动作给 Hooks,经验交给自动记忆。当你发现自己第三次向 Claude 解释同一件事时,那就是该写入记忆的信号。
如果你还没配好接入环境,先去 API Keys 页面生成密钥:
https://taotoken.net/api-keys配置细节查接入文档:
https://taotoken.net/doc想先试试模型对话确认端点通不通:
https://taotoken.net/model-chat长期做编码和 Agent 任务的话,Coding Plan 的额度更合适:
https://taotoken.net/coding-plan