为什么不用 RAG 做记忆系统 ——压缩上下文与 memory.md 的架构选择

对话记忆 ≠ 知识检索。用向量数据库存对话历史,就像用 Google 搜索来记住你昨天吃了什么。

先摆结论

在做 AI 应用落地时,有些团队把 RAG(检索增强生成)当成万金油------知识库用 RAG,对话历史也用 RAG,用户偏好还是用 RAG。但是实际用下来会发现 AI 总是失忆,用户体验糟糕。

根本原因在于:RAG 是为查找外部知识而设计的,不是为记住对话上下文设计的。

这两件事虽然都需要存储 + 检索,但底层需求完全不同。

RAG 是什么,它本来解决什么问题

RAG(Retrieval-Augmented Generation)的工作流程:

flowchart LR A[文档/FAQ/手册] -->|切片 + 向量化| B[(向量数据库)] C[用户提问] -->|向量化| D{语义相似度搜索} B --> D D -->|召回 top-k 片段| E[拼入 Prompt] C --> E E --> F[模型生成回答]

这个场景是 RAG 的主战场:大规模、相对静态、面向事实查询的知识库

✅ RAG 真正擅长的问题:

  • "我们公司的退款政策是什么?"
  • "合同第 7 条款说了什么?"
  • "Python asyncio 的最佳实践是什么?"

这些都是主动查询外部事实的场景,RAG 完全胜任。

当 RAG 遇到对话记忆

很多团队会把用户的对话历史也存入向量数据库,逻辑看似合理:"我把每次对话都存下来,下次用户问相关问题时,检索出来给 AI 看,AI 就有记忆了。"

实际上呢?

让我们看一个真实的失败场景。

案例:某 AI 私人助手,对话历史存入向量数据库

第一天的对话:

👤 我最近在学 Rust,帮我规划一下学习路径

🤖 好的!建议你从所有权系统开始......(详细规划)

👤 顺便说一下,我的技术背景是 Python,做了 5 年后端

三天后,新的对话:

👤 帮我写一个 Rust 的 HTTP 客户端示例

🤖 ❌ 好的,这是一个基础的 HTTP 客户端示例。首先你需要了解什么是 HTTP 协议......(从零开始解释基础概念)

为什么失败?

用户的查询是写 HTTP 客户端,而历史中我有 5 年 Python 后端经验这句话,和这个查询的语义相似度极低,向量检索根本不会召回它。

flowchart TD Q["用户查询:帮我写 Rust HTTP 客户端"] DB[(向量数据库\n存有对话历史)] Q -->|向量化 + 相似度搜索| DB DB -->|"❌ 未召回:我有5年Python经验\n语义距离太远"| X[关键信息丢失] DB -->|"✅ 召回了:Rust HTTP 相关片段\n但缺少用户背景"| Y[回答缺乏个性化] X --> Z["AI 把用户当初学者,从头解释 HTTP"] Y --> Z

RAG 用于记忆系统的四大结构性缺陷

缺陷 1:相关性 ≠ 重要性

向量检索召回的是语义最相似 的内容,不是最重要的内容。

用户说"我不喜欢废话连篇的回答"------这是极其重要的偏好,但它和绝大多数技术问题的语义距离都很远,几乎永远不会被检索到。

缺陷 2:上下文是整体,不是碎片

对话中"我、我老婆、我们的项目"是一个整体叙事。但是被切片存储后,人称关系断裂,AI 拿到孤立片段,很容易产生理解错误。

比如"她不喜欢这个方案"存入向量库后,下次检索出来,AI 已经不知道"她"是谁了。

缺陷 3:增加了不确定性

RAG 召回的 top-k 策略是概率性的。同一个问题,在不同时机、不同 embedding 模型版本下,可能召回完全不同的历史片段,导致 AI 行为难以预测和调试。

缺陷 4:维护成本高

问题 影响
需要运维向量数据库(Pinecone / Weaviate...) 增加基础设施复杂度
embedding 模型版本更新 历史数据要重新向量化
用户信息发生变化 旧向量还在库里持续干扰

那既然有这么多缺陷,我们实际落地时要怎么办呢?

方案一:压缩上下文(Context Compression)

压缩上下文的核心思路:不要让 AI 去检索记忆,而是直接把精炼过的记忆放进 context 里。

flowchart TD A["对话进行 N 轮\ntoken 快到上限"] --> B["触发压缩\nAI 将 N 轮浓缩为结构化摘要"] B --> C["摘要存入普通 KV 数据库\n无需向量化"] C --> D["丢弃原始对话\n用摘要继续对话"] D --> E["新对话继续积累"] E -->|"再次触发压缩"| B

效果对比

同样的问题,换了方案之后。

注入 system prompt 的摘要:

csharp 复制代码
【用户背景】
- 5 年 Python 后端经验,熟悉 FastAPI 和 async 编程
- 目前正在学习 Rust,已完成所有权章节
- 偏好:代码示例简洁,不需要解释基础概念

【上次对话摘要 (2025-03-18)】
用户询问了 Rust 学习路径,决定下一步学习 async/await。
用户明确表示不喜欢理论解释,更喜欢直接看代码。

对话效果:

👤 帮我写一个 Rust 的 HTTP 客户端示例

🤖 ✅ 直接上代码,用 reqwest 库。考虑到你熟悉 Python async,这里的 .await 语法应该很眼熟:

rust 复制代码
use reqwest;
async fn fetch(url: &str) -> Result<String, reqwest::Error> {
    reqwest::get(url).await?.text().await
}

AI 知道用户是老手,直接给代码;知道用户学过 Python async,做了类比------一切关键上下文都完整保留了。

方案二:memory.md(结构化记忆文件)

压缩上下文解决了会话历史的问题,但还有另一类记忆:关于用户本身的长期事实性记忆。比如职业背景、沟通偏好、正在进行的项目......

这些不应该每次都从对话历史中重新推断,而应该有一个固定的用户档案------这就是 memory.md

示例文件:

markdown 复制代码
## 基本信息
- 职业:后端工程师,5 年经验,主力语言 Python
- 时区:Asia/Shanghai,上班时间 10:00-19:00
- 沟通偏好:简洁直接,代码优先,不需要废话

## 正在进行的项目
- **Rust 学习**:进度到第 8 章(错误处理),目标是重写内部数据管道
- **工作项目**:某 SaaS 产品 API 性能优化,技术栈 FastAPI + PostgreSQL

## 重要偏好
- 不喜欢过度解释显而易见的概念
- 喜欢类比 Python 来理解新语言特性
- 代码示例:真实可运行 > 简化示例

## 最近的关键决策
- 2025-03-15:决定用 tokio 作为 Rust 异步运行时
- 2025-03-10:选择了 reqwest 作为 HTTP 客户端库

## 待跟进
- 等用户确认是否需要帮助设计数据库 schema

memory.md 的关键特性:

特性 说明
人类可读可编辑 用户可直接打开查看、修改,完全透明
确定性读取 全文注入 prompt,不存在召回率问题
轻量易维护 普通文本文件,不依赖任何外部向量服务
信息密度高 1000 token 可覆盖几个月的关键记忆
AI 自动维护 发现新重要信息时,自动更新对应字段

两个方案如何配合

两层架构,解决不同时间尺度的记忆问题:

flowchart TD subgraph 短期["🔵 短期记忆(会话内)"] A1[对话轮次 1] A2[对话轮次 2] A3[对话轮次 N] end subgraph 长期["🟢 长期记忆(跨会话)"] C["memory.md\n用户长期档案"] end A1 & A2 & A3 -->|"触发压缩"| B["压缩摘要\n(当前会话精华)"] B --> SP["System Prompt\n= memory.md + 压缩摘要"] C --> SP SP --> AI[AI 回答] AI -->|"发现新信息时自动更新"| C

关键点:两层记忆都不需要向量检索,都是确定性地注入 system prompt 的。

这避免了所有的召回率问题,让 AI 的行为变得可预测、可调试。

那 RAG 什么时候用?

判断标准只有一个:

这条信息,是用户主动问 出来的(查询外部知识),还是在对话中被动透露的(积累的上下文)?

  • 前者 → 用 RAG
  • 后者 → 用 memory.md + 压缩上下文
场景 推荐方案
用户对话历史 压缩上下文摘要
用户偏好 / 背景 memory.md
公司内部文档 / FAQ RAG(向量检索)
正在进行的任务状态 memory.md 待跟进字段
大规模技术文档语义搜索 RAG(向量检索)

业界是怎么做的

这套思路并不是凭空而来,看几个真实的工业级产品,会发现殊途同归。

OpenAI Codex / Claude Code :这类工具在启动时会扫描项目目录,把 README.md、目录结构、关键配置文件直接读入上下文,同时在对话中自动维护一份"当前任务状态"的结构化摘要。它们几乎不用向量检索来回忆之前的操作------而是靠不断压缩和更新的 working memory 来维持任务连贯性。

OpenClaw / Cursor 等 : Cursor 的 .cursorrules 文件本质上就是 memory.md 的工程化实现------一个由开发者手写(或 AI 辅助维护)的项目级偏好文件,每次对话都全量注入。用户发现告诉 AI 一次就永远记住的最可靠方式,不是让 AI 检索历史对话,而是直接写进这个文件。

Anthropic Claude 和 ChatGPT 的 Memory 功能 :官方记忆功能正是生成结构化的用户档案 Markdown 片段,在每次对话开始时注入 system prompt。

落地时的注意事项

1. 压缩摘要的触发时机

不要等到 context 真的撑满了再压缩,那时候已经来不及了。推荐的策略:

  • 固定轮数触发:每 15-20 轮对话压缩一次,简单可靠
  • token 阈值触发:当 context 用量超过模型上限的 60%-70% 时触发,留出压缩本身需要的空间
  • 话题切换触发:检测到用户开始讨论新话题时,把旧话题先压缩归档

2. 压缩摘要的 Prompt 设计

压缩质量直接决定记忆质量,这步不能偷懒。一个有效的压缩 prompt 应该明确告诉 AI 要保留什么:

markdown 复制代码
请将以下对话压缩为结构化摘要,必须保留:
1. 用户透露的个人背景和偏好
2. 已经做出的决策和选择(不要省略)
3. 未完成的任务和待跟进事项
4. 重要的上下文约束(如技术栈、团队规范)

不需要保留:
- 具体的代码细节(除非是核心架构决策)
- 过程中的错误尝试
- 礼貌性寒暄

输出格式为 Markdown,使用 ## 分节。

3. memory.md 的更新策略

不要让 AI 在每轮对话后都去判断要不要更新 memory.md,这会引入大量无意义的写操作,也会让 AI 分心。更好的做法:

  • 异步更新:在每次对话结束后(用户关闭会话),单独跑一次提炼新信息的任务
  • 增量 diff:让 AI 只输出新增/修改/删除的字段,不要每次重写整个文件
  • 版本控制memory.md 最好用 git 管理,方便回滚和审计

4. memory.md 的大小控制

肯定不是越大越好。

注入 prompt 是有 token 成本的,而且太长的 memory.md 反而会稀释重要信息的权重。

我的粗浅的经验值:500-1500 token 是可靠区间,超过 2000 token 就要考虑归档旧内容了。可以给 memory.md 做个分层:

  • memory.md:当前活跃的核心信息(≤1000 token,每次注入)
  • memory_archive.md:历史归档(不注入,只在用户主动询问时检索)

5. 警惕污染

AI 自动维护 memory.md 时,偶尔会写入错误信息------比如误解了用户的意思,或者把临时性的表述当成了长期偏好。

应对方法:

  • 在 UI 上给用户提供查看或者编辑记忆的入口,让用户能随时纠正
  • memory.md 的写操作做人工确认(至少在产品早期),积累足够样本后再改成全自动

写在最后

我之前一直写 Java 相关的技术文章,框架、性能调优、微服务架构......写了很多年,也算积累了一些东西。

但这一阵开始转向 AI 应用落地,刚开始是有点迷茫的。这个领域变化太快,概念满天飞,每隔几天就有新的模型、新的框架、新的最佳实践冒出来,感觉自己永远在追赶。

于是我就干脆停下来,不追热点了,老老实实地去做项目、踩坑、复盘。这篇文章里关于 RAG 做记忆系统的问题,就是我们团队实际踩过的坑。在我看来,这些东西才是应该认真沉淀和分享的,而且这些经验,只有真正做过落地才知道。

以后我会慢慢把这些心得整理出来分享,关于 AI 应用架构、prompt 工程、agent 设计......都是从实际项目里提炼的精华。

最后,想跟大家说:不要怕被 AI 淘汰。

我在实际做 AI 应用的过程中,越来越清楚地感受到一件事------AI 现在有多强大,就有多需要人来掌舵。 至少目前的阶段仍然如此。

模型不知道你的业务边界在哪里,不知道你的用户真正在意什么,不知道一个决策背后的组织博弈,不知道什么时候该停下来让人工介入。这些判断,现阶段全都需要人来做。

所以现在这个阶段,真正的竞争不是"你 vs AI",而是 "会用 AI 的你 vs 不会用 AI 的你"

掌握足够的 AI 使用和应用技能,不只是不被淘汰,更可能是借着这波浪潮,做出以前根本没条件做的东西。

共勉。

相关推荐
Dxy12393102167 分钟前
Python如何结合AI解决数据分析问题
人工智能·python·数据分析
锋行天下9 分钟前
LangGraph简单图结构
人工智能
制造业的搬运工12 分钟前
智能家居工控PCB可靠性检测规范与制程管控实践
大数据·网络·人工智能·制造·pcb工艺
蓝羽飞鸟28 分钟前
什么是自监督学习
人工智能·深度学习
wing9830 分钟前
从codex转战workbuddy使用一周的感受
前端·人工智能·后端
AI产品测评官34 分钟前
从L3寻源智能体到全链路闭环ATS:拆解世纪云猎新一代AI招聘系统架构
人工智能·系统架构
EatFan37 分钟前
Java接入支付宝 JSAPI 支付保姆教程(二):流程讲解与前后端代码讲解
前端·spring boot·后端·微信小程序·小程序·uni-app
Java成神之路-42 分钟前
RAG 工程最优解:意图路由分流架构
人工智能·ai应用开发·springaialibaba
余槐i1 小时前
Firecrawl 实战:将网站转换为大模型可用数据
人工智能·python·工具·firecrawl
hsg771 小时前
简述: 人工智能 + 行动意见
人工智能