Files
claude-code/docs/context/project-memory.mdx
claude-code-best fedce003a5 docs: 重写项目记忆,从源码走读改为记忆系统设计分析
移除源码路径、TypeScript 函数和实现常量,
增加文件 vs 数据库的选型对比表、四类型分类法的设计约束分析、
智能召回架构和记忆漂移防御的设计考量。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 09:33:03 +08:00

138 lines
6.6 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: "项目记忆"
description: "AI 没有真正的记忆。Claude Code 如何通过文件系统构建跨会话的记忆?理解存储架构、四类型分类法、智能召回和漂移防御设计。"
keywords: ["项目记忆", "MEMORY.md", "AI 记忆", "跨对话", "自动记忆"]
---
## 核心问题
AI 的每次 API 调用都是无状态的——模型只看到当前请求中的内容。这意味着每次新会话AI 都从零开始,不知道你之前讨论过什么、你喜欢什么风格、项目有什么特殊约束。
记忆系统的目标:**让 AI 在跨会话中保持连贯性**。
## 存储架构:纯文件
Claude Code 的记忆系统是**纯文件**的——没有数据库、没有向量存储,只有 Markdown 文件和目录结构。
```
~/.claude/projects/<项目目录>/memory/
├── MEMORY.md ← 入口索引(每次对话加载)
├── user_role.md ← 用户记忆
├── feedback_testing.md ← 反馈记忆
├── project_mobile_release.md ← 项目记忆
└── reference_linear_ingest.md ← 参考记忆
```
### 为什么选择文件而非数据库
| 方案 | 优势 | 劣势 |
|------|------|------|
| **Markdown 文件** | 用户可直接编辑、git 友好、零依赖 | 查询需要扫描文件 |
| SQLite 数据库 | 查询高效 | 用户无法直接编辑、需要额外依赖 |
| 向量数据库 | 语义搜索强大 | 过度工程、引入复杂依赖 |
选择文件的核心理由:**记忆应该是用户可以审查、编辑和删除的**。Markdown 文件让用户完全掌控 AI 记住了什么。如果 AI 记住了错误的信息,用户可以直接打开文件删除它。
### MEMORY.md 索引
`MEMORY.md` 是记忆系统的入口。每次对话开始时完整加载到上下文中。它不是记忆内容本身,而是一个链接索引:
```markdown
- [用户角色](user_role.md) — 深度 Go 开发者React 新手
- [测试反馈](feedback_testing.md) — 集成测试必须使用真实数据库
```
索引有双重上限(行数和字节数),防止索引本身占用过多 token。超过上限时自动截断——这确保记忆系统不会成为新的 token 负担。
## 四类型分类法
记忆被约束为一个封闭的四类型系统,每种类型有明确的用途和保存时机:
| 类型 | 存储内容 | 设计目的 |
|------|---------|----------|
| **user** | 用户角色、偏好、技术背景 | 让 AI 理解"用户是谁" |
| **feedback** | 用户对 AI 行为的纠正和确认 | 防止 AI 重复犯错或偏离已验证的工作方式 |
| **project** | 无法从代码推导的项目上下文 | 记录"为什么这样决定"而非"代码长什么样" |
| **reference** | 外部系统的指针 | 告诉 AI 去哪里找信息 |
### 关键设计约束
**只存储无法从当前项目状态推导的信息。** 代码架构、文件路径、git 历史都可以实时获取,不需要记忆。
这条约束防止记忆系统变成冗余缓存。如果某个信息可以通过读代码获得,那就不应该记下来——因为代码是最新的,而记忆可能已经过时。
### 反馈的双通道捕获
反馈类型特别强调不仅要在用户纠正时保存("不要这样做"),也要在用户确认时保存("对,就是这样")。
**设计考量**如果只记录纠正AI 会避免过去的错误,但也会偏离用户已经验证过的工作方式,变得越来越保守。记录"成功路径"和记录"失败路径"同等重要。
### 每条记忆的结构
每条记忆文件都有 frontmatter 元数据:
```markdown
---
name: 测试反馈
description: 集成测试的数据库使用偏好
type: feedback
---
集成测试必须使用真实数据库,不能 mock。
**Why:** 上季度发生过 mock 通过但生产迁移失败的事故。
**How to apply:** 所有涉及数据库的测试用真实实例。
```
`description` 字段不是给人读的摘要——它是给 AI 召回系统做相关性判断的搜索关键词。`Why` 和 `How to apply` 行帮助 AI 理解"为什么有这条规则"和"什么时候该应用它"。
## 智能召回
不是所有记忆都适合每次对话。用户可能在 50 个记忆文件中积累了大量信息,但一次对话通常只需要其中 3-5 条。
### 召回架构
系统使用一个轻量级的独立 AI 查询来筛选最相关的记忆:
```
用户消息
→ 扫描所有记忆文件的元数据
→ 独立 AI 查询:从所有记忆中选出最相关的 ≤5 条
→ 只加载选中的记忆文件内容
```
**设计考量**:为什么不直接加载所有记忆?因为记忆文件会随时间增长,全部加载可能占用大量 token。使用独立查询筛选虽然多花一次 API 调用,但可以显著减少主对话的 token 消耗。
### 去噪设计
- **近期工具去噪**:当 AI 正在使用某个工具时,不召回该工具的使用文档(对话中已有工作上下文)。但仍召回关于这些工具的**警告和已知问题**——这正是使用时最关键的信息。
- **已展示去重**:之前轮次已展示过的记忆不再重复召回,让有限的召回预算花在新的候选上。
## 记忆漂移防御
记忆可能过时。系统在 AI 的行为指令中设置了专门的防御:
> 一条记忆提到某个函数或文件,只是声明它**在记忆被写入时**存在。它可能已被重命名、删除或从未合并。在推荐之前,先验证它是否还存在。
这个指令从"行动导向"的角度设计——不是告诉 AI"记忆可能不准确"(太抽象),而是直接告诉它"在推荐之前先检查"(可操作)。
### 忽略记忆的严格语义
当用户说"忽略记忆"时AI 必须做到真正的忽略——不应用、不引用、不比较、甚至不提及记忆内容。
这解决了一个常见的 AI 反模式:用户说"忽略关于 X 的记忆"AI 虽然正确识别了代码,但仍加上"不像记忆中说的 Y"——这不是"忽略",而是"承认然后覆盖"。
## 与上下文压缩的联动
记忆系统与上下文压缩深度集成。当 Session Memory 功能启用时,压缩优先使用已提取的记忆作为摘要——不需要额外的 AI 调用生成摘要,更快、更便宜、且不会丢失信息。
这形成了一个正向循环:
1. 对话中积累信息 → 提取为记忆
2. 上下文需要压缩时 → 使用记忆作为摘要
3. 下次对话开始 → 通过智能召回加载相关记忆
## 接下来
- **自动记忆整理** — 了解 KAIROS 模式下的每日日志和蒸馏机制
- **上下文压缩** — 理解记忆如何与压缩策略联动
- **令牌预算** — 了解记忆加载的 token 开销管理