跳转至

Claude Code 记忆与上下文机制详解

Claude Code 没有真正的"记忆"——每次对话都是全新的。但它通过一套文件系统实现了持久化的"伪记忆"。理解这套机制,才能高效利用它。

CLAUDE.md 层级体系

Claude Code 的 CLAUDE.md 不只有一个——它有三层,从全局到局部合并加载:

层级 路径 作用域 用途
用户级 ~/.claude/CLAUDE.md 所有项目通用 个人偏好,如"我用 pnpm 不用 npm"
项目级 <项目根>/CLAUDE.md 当前项目 架构约定、构建命令、编码规范(主力文件
目录级 <子目录>/CLAUDE.md 特定模块 模块专属规则,进入该目录时按需加载

加载顺序

  1. 会话启动时,用户级和项目级 CLAUDE.md 作为 user message 注入
  2. 子目录级的 CLAUDE.md 在 Claude 读取到该目录时按需加载
  3. 三层内容合并,从宽泛到具体,具体的覆盖宽泛的

Token 缓存机制

Claude Code 对 CLAUDE.md 启用了 Prompt Caching

  • 首次请求:按完整输入 Token 价格计费
  • 5 分钟内的后续请求:按缓存读取价格计费(远低于标准价格)
  • 文件修改会使缓存失效,下次请求重新按完整价格计费

所以 CLAUDE.md 频繁编辑反而会增加成本。写好后尽量稳定。

CLAUDE.md 应该写什么

推荐写入(控制在 ~200 行以内):

  • 构建、测试、lint、本地运行命令
  • 命名约定、错误处理、文件布局规则
  • 三句话的架构概述
  • 硬性约束(如"测试禁止写入生产数据")
  • 新人常踩的坑

不要写:

  • 完整的 API 文档
  • 变更日志或历史记录
  • 一眼就能看出来的目录结构
  • 团队实际不遵守的"理想规则"

三层记忆架构

第一层:自动加载(每次对话必定消耗 Token)

来源 说明 建议大小
CLAUDE.md 项目根目录的指令文件,每次对话自动注入 system prompt 尽量精简,< 100 行
MEMORY.md 记忆索引文件,每行一个指针 < 200 行(超出会被截断)

这两个文件的内容每次对话都会消耗 Token,无论是否用到。所以:

  • CLAUDE.md 只写规则和流程,不写数据
  • MEMORY.md 只写一行摘要 + 文件链接,不写记忆正文

第二层:按需读取(仅在相关时消耗 Token)

来源 触发条件 Token 消耗
记忆文件(user_*.mdreference_*.md 等) Claude 判断与当前任务相关时,主动 Read 仅读取时消耗
项目文件(代码、文档等) 用户要求或任务需要时 仅读取时消耗
每日记录(recent.md CLAUDE.md 中配置了"必须读取"规则 每次对话消耗一次

这是省 Token 的核心: MEMORY.md 的索引让 Claude 知道"有什么可以查",但只在需要时才真正去读文件内容。

第三层:不存在的能力

  • 跨对话记忆:没有。每次对话从零开始,除非读取了持久化文件
  • 对话历史回顾:看不到之前的对话内容
  • 自动学习:不会从对话中自动提取知识,必须显式写入文件
  • 主动触发:无法在没有对话的情况下自行启动

记忆类型

Claude Code 的记忆文件分四种类型,每种有不同的用途:

类型 存什么 示例
user 用户角色、背景、偏好 "CISP-PTE 方向,macOS 环境"
feedback 用户纠正过的行为 "不要在回复末尾加总结"
project 正在进行的项目状态 "博客合并冻结到 4 月 20 日"
reference 外部资源位置 "OpenClaw 配置在 ~/.openclaw/"

记忆文件格式

---
name: 记忆名称
description: 一行描述(用于判断是否相关)
type: user/feedback/project/reference
---

记忆正文内容

description 字段很重要——Claude 通过它判断是否需要读取这条记忆。描述越精确,误读越少。

信息流向图

┌─────────────────────────────────────────────────┐
│                每次对话开始                        │
│                                                   │
│  自动加载 ─┬─ CLAUDE.md(规则指令)    ← 每次消耗  │
│            └─ MEMORY.md(索引)        ← 很小     │
│                                                   │
│  按需读取 ─┬─ 记忆文件(*.md)        ← 相关时读   │
│            ├─ recent.md(每日记录)    ← 规则触发   │
│            └─ 项目文件(代码/文档)    ← 任务需要   │
│                                                   │
│  对话进行中                                        │
│            ├─ 用户消息                              │
│            ├─ 工具调用结果                           │
│            └─ Claude 回复                           │
│                │                                   │
│                ▼ 上下文接近窗口上限时                 │
│            旧消息被压缩(丢失细节)                   │
│                                                   │
│  对话结束 ── 一切消失,除非写入了文件                 │
└─────────────────────────────────────────────────┘

省 Token 的实践策略

1. CLAUDE.md 保持精简

# 好的写法 — 只写规则
每次对话先读 recent.md

# 坏的写法 — 把数据塞进去
用户的服务器 IP 是 xxx,密码是 xxx,上次操作了 xxx...

2. MEMORY.md 只放索引

# 好的写法 — 一行摘要 + 链接
- [OpenClaw 参考](reference_openclaw.md) — 目录 ~/.openclaw,配置在 openclaw.json

# 坏的写法 — 把内容直接写在索引里
- OpenClaw 是一个自托管 Gateway 网关,支持 Discord、Slack...(长段文字)

3. 记忆文件的 description 要精准

# 好的 — 精确描述,减少误读
description: OpenClaw 工具目录位置及 Web Token 查找方法

# 坏的 — 模糊描述,导致不相关时也被读取
description: 一个工具的信息

4. 大文件拆小,按需读取

# 好的 — 按主题拆分,只读需要的
memory/
├── reference_openclaw.md      # 只在问 OpenClaw 时读
├── reference_shennong.md      # 只在问神农时读
└── user_security_learner.md   # 只在需要了解用户背景时读

# 坏的 — 全部塞一个文件
memory/
└── everything.md              # 每次都要读完

5. recent.md 控制在 7 天以内

每日记录如果无限增长,每次对话都会读入大量历史。保持只有最近 7 天,旧的归档:

daily/
├── recent.md           # ≤ 7 天,每次对话读取
└── archive/2026-04.md  # 旧数据,不自动读取

什么时候让 Claude "记住"

场景 操作
希望 Claude 下次对话也知道 写入记忆文件(user/feedback/project/reference
只在当前对话需要 直接说,不需要存文件
纠正了 Claude 的行为 说"记住这个",存为 feedback 类型
知道某个资源位置 存为 reference 类型

常见误区

误区 真相
"Claude 会记住我们之前的对话" 不会,每次从零开始
"CLAUDE.md 写越详细越好" 错,越长每次消耗越大
"记忆文件越多越好" 不一定,description 模糊会导致不相关文件被误读
"对话里说了就等于记住了" 错,对话结束一切消失,必须写入文件
"切换模型会保留记忆" 对话内切换保留,新对话不保留

七个提示词习惯

高效使用 Claude Code 的关键不只是配置记忆,还在于怎么和它说话

1. 说结果,不说步骤

# 好的 — 说你要什么
"把 UserService 的数据库查询改成批量获取,减少 N+1 问题"

# 差的 — 手把手教步骤
"打开 user_service.py,找到第 42 行,把 for 循环改成..."

让 Claude 自己决定怎么做,它通常比你预想的路径更好。

2. 贴完整错误

# 好的 — 完整堆栈
"运行 pytest 报错:
  File 'tests/test_api.py', line 23
  AssertionError: expected 200, got 403
  ..."

# 差的 — 模糊描述
"测试跑不过"

3. 大任务先规划

多文件修改前,按两次 Shift+Tab 进入计划模式,或用 /plan。让 Claude 先分析再动手,避免改到一半发现方向错了。

4. 用 @ 指向已知文件

看一下 @src/auth/middleware.ts 里的鉴权逻辑有没有绕过风险

@路径 语法直接把文件内容注入上下文,比描述文件位置更高效。

5. 明确定义"完成"

# 好的 — 有验收标准
"添加分页功能,要求:测试通过、和现有 handler 风格一致、支持 limit/offset 参数"

# 差的 — 开放式
"加个分页"

6. 一次对话一个任务

不相关的任务用 /clear 分开。项目记忆会保留,但上下文不会被无关内容污染。

7. 像同事一样纠正

# 好的 — 精确纠正
"这样改会破坏公开 API,保持函数签名不变,只改内部实现"

# 差的 — 重新描述整个需求

上下文窗口与压缩

Claude 有一个上下文窗口(约 200k Token)。当对话内容接近上限时:

  1. 系统自动压缩早期消息(保留要点,丢失细节)
  2. 被压缩的内容无法恢复
  3. 长对话后期可能"忘记"早期的细节

应对策略:

  • 重要信息写入文件,不要只在对话里说
  • 超长任务拆成多次对话,每次通过文件传递上下文
  • 关键结论让 Claude 写入 recent.md 或记忆文件

常用命令速查

目标 命令
生成初始 CLAUDE.md /init
查看当前记忆 /memory
添加会话规则 打开 /memory 编辑,或让 Claude "记住这个"
重启对话、保留记忆 /clear
在提示中引用文件 @path/to/file
压缩上下文释放空间 /compact
进入只读计划模式 /planShift+Tab 两次