AI Agent 记忆优化:从 Mem0 到三层架构的实战方案
AI Agent 记忆优化:从 Mem0 到三层架构的实战方案
一、为什么 AI Agent 需要记忆?
想象一个场景:你花了两个小时跟你的 AI 助手聊项目架构,终于把需求对齐了。第二天你说”继续昨天的方案”,它回你:
“抱歉,我不太确定您指的是哪个方案,能再描述一下吗?”
💀 每次对话都是失忆的。这就是 无状态 Agent 的核心痛点。
大语言模型本质上是一个函数:f(prompt) → response。它没有”昨天”,没有”上次”,甚至没有”刚才”——所谓的上下文,只是你在 prompt 里塞进去的历史消息。一旦 token 窗口用完或者会话重启,一切归零。
这在简单的问答场景下还能凑合。但当你想让 AI 成为一个 长期陪伴的 Agent——帮你管项目、记偏好、跟进任务——无状态就是死穴。
| 场景 | 无状态 Agent | 有状态 Agent |
|---|---|---|
| 用户说”用上次的风格” | ❌ 不知道”上次”是什么 | ✅ 检索到上次的风格偏好 |
| 连续三天跟进同一个 bug | ❌ 每天重新解释一遍 | ✅ 自动加载 bug 上下文 |
| 半年后问”我们项目的技术栈” | ❌ 完全不知道 | ✅ 从记忆中检索到 |
| 记住用户讨厌 Java | ❌ 下次照样推荐 Spring Boot | ✅ 自动避开 |
所以,记忆不是锦上添花,而是 Agent 从”工具”进化到”助手”的关键门槛。
但问题来了——怎么实现?把所有历史对话全塞进 prompt?一个月的聊天记录轻松几十万 token,不仅贵,还会因为信噪比太低导致模型”注意力涣散”,该记住的反而记不住。
这就是 Agent 记忆优化 要解决的问题:用最少的 token,让模型获取最相关的上下文。
二、业界方案调研
在自己造轮子之前,先看看别人怎么做的。
2.1 Mem0 —— 通用记忆层 ⭐25K
Mem0 的思路很直觉:把记忆当成一个独立的中间件服务。
核心流程:
用户对话 → LLM 提取记忆片段 → 向量化存储 → 下次对话时语义检索 → 注入 promptfrom mem0 import Memory
m = Memory()
# 存:从对话中自动提取记忆m.add("我喜欢用 Rust 写后端,讨厌 XML 配置", user_id="yangbo")
# 取:语义检索相关记忆results = m.search("推荐一个后端框架", user_id="yangbo")# → ["用户喜欢 Rust", "用户讨厌 XML 配置"]优点: 开箱即用,自动提取,语义检索比关键词匹配强太多。
缺点: 依赖向量数据库(Qdrant/Chroma),记忆的”提取”依赖 LLM 判断(有时会提取出无关信息或遗漏关键信息),对于长期运行的 Agent 来说,记忆条目会膨胀到难以管理。
2.2 Letta/MemGPT —— 三层记忆 ⭐13K
MemGPT(现在叫 Letta)的思路更有野心:模拟操作系统的虚拟内存机制。
它把记忆分成三层:
┌─────────────────────────────────────────┐│ Core Memory(核心记忆) ││ 始终在 context 中,类似 CPU 寄存器 ││ 存:用户画像、系统指令、关键状态 │├─────────────────────────────────────────┤│ Recall Memory(回忆记忆) ││ 对话历史的数据库,按需检索 ││ 类似内存 / RAM │├─────────────────────────────────────────┤│ Archival Memory(归档记忆) ││ 长期知识库,向量检索 ││ 类似硬盘 / SSD │└─────────────────────────────────────────┘核心思想: Agent 自己决定什么时候”翻页”——当 context 快满时,主动把不重要的内容存到外部存储,需要时再取回来。就像操作系统的 page fault:内存不够了,换页到磁盘。
优点: 理论上可以处理无限长的对话历史,Agent 有自主记忆管理能力。
缺点: 复杂。需要 Agent 学会调用 memory 工具函数,实际体验中经常出现”忘了该记住的”或”记了不该记的”。部署依赖也不轻——需要数据库、向量存储、额外的 LLM 调用。
2.3 Memori —— SQL-native 记忆基础设施
Memori 走了另一条路:用结构化 SQL 来管理记忆,而不是纯向量检索。
思路是把记忆当成数据库表——有明确的 schema、可以 JOIN、可以做精确查询。比如”用户三天前提到的那个 API 地址”这种查询,用 SQL 比向量检索靠谱得多。
适合场景: 企业级、多用户、需要精确查询的场景。
不适合: 个人 Agent、快速原型。引入 SQL 基础设施对于轻量场景来说太重了。
2.4 小结
| 方案 | 核心思路 | 存储依赖 | 适合场景 | 复杂度 |
|---|---|---|---|---|
| Mem0 | 自动提取 + 向量检索 | 向量数据库 | 通用对话记忆 | ⭐⭐ |
| MemGPT/Letta | 三层记忆 + 自主管理 | DB + 向量库 | 长对话、复杂 Agent | ⭐⭐⭐⭐ |
| Memori | SQL 结构化记忆 | SQL 数据库 | 企业级多用户 | ⭐⭐⭐ |
| 文件系统三层架构 | 分层 + 蒸馏 | 无(纯文件) | 个人 Agent | ⭐⭐ |
看完这些方案,我的判断是:对于个人 Agent 场景,这些方案都太重了。 我不需要向量数据库,不需要额外的服务进程,我需要的是一个 简单、可维护、纯文件系统 的方案。
三、设计一个轻量级三层记忆架构
受 MemGPT 三层记忆的启发,但砍掉所有基础设施依赖,只用文件系统实现。
整体架构
workspace/├── MEMORY.md ← L1 核心记忆(≤50行,每次必读)├── memory/│ ├── index.md ← L2 索引(目录,知道什么信息在哪)│ ├── project-A.md ← L2 主题文件(按需加载)│ ├── tech-stack.md ← L2 主题文件│ ├── 2026-04-07.md ← L3 每日归档│ ├── 2026-04-08.md ← L3 每日归档│ └── 2026-04-09.md ← L3 每日归档(今天)L1 核心记忆(Core)—— 始终在线
规则:≤50 行,每次会话启动必读。
这是 Agent 的”身份证 + 速记卡”。存什么?
- 用户身份和偏好(“用户是开发者,偏好 Rust,讨厌 XML”)
- 当前进行中的关键任务
- 重要决策和约定
- 需要长期记住的规则
<!-- MEMORY.md 示例 -->## 用户画像- 开发者,全栈,偏好 TypeScript + Rust- 有一台 4G 内存的 Ubuntu VPS,构建大项目需要 swap- 博客用 Astro,代码托管 Gitee
## 当前任务- 博客迁移到新主题(进行中)- AI Agent 记忆系统优化(本周重点)
## 重要约定- 部署前必须先在沙盒测试- 不要在群聊里暴露服务器信息- 用户不喜欢等太久,长任务用子 Agent 异步处理为什么限制 50 行? 因为这部分每次都要读,直接占用 context 窗口。50 行大约 1000-1500 token,是一个合理的固定开销。超过了就该下沉到 L2。
L2 工作记忆(Working)—— 按需加载
规则:索引文件 + 主题子文件,提到才读。
索引文件 memory/index.md 是一个目录,告诉 Agent “什么信息在哪个文件里”:
<!-- memory/index.md 示例 -->## 项目- project-blog.md — 博客相关:主题、部署流程、历史问题- project-tools.md — My Tools 站点:功能清单、部署方式
## 技术- tech-stack.md — 技术栈偏好、选型记录- infra.md — 服务器配置、域名、SSL
## 人际- contacts.md — 常联系的人、沟通偏好当用户说”帮我看看博客部署的问题”,Agent 看到 index 里有 project-blog.md,就加载它。不相关的文件完全不碰——零 token 开销。
这和 MemGPT 的 recall memory 异曲同工,只是检索方式从向量搜索变成了 人类可读的索引文件。简单粗暴,但在个人 Agent 场景下,效果出奇地好。
L3 归档记忆(Archive)—— 原始日志
规则:每日一个文件,记录当天发生的一切。
<!-- memory/2026-04-09.md 示例 -->## 2026-04-09
### 09:00 博客文章- 写了一篇 AI Agent 记忆优化的文章- 部署到 boke.hackerdream.xyz- 构建时遇到 OOM,加了 swap 解决
### 14:30 服务器维护- 更新了 nginx 配置- SSL 证书还有 60 天过期,记得续L3 是最”脏”的一层——什么都记,不做过滤。它的价值在于 可追溯性:三个月后你想知道”当时为什么选了这个方案”,翻日志就能找到。
但 L3 绝不应该每次都读。只有在需要回顾特定日期的上下文时才加载。
三层记忆的读取策略
用伪代码表示 Agent 每次启动时的逻辑:
def on_session_start(): # L1: 必读(固定开销 ~1000 token) core = read("MEMORY.md")
# L2: 读索引(~200 token),但不读子文件 index = read("memory/index.md")
# L3: 只读今天的日志(获取最近上下文) today = read(f"memory/{date.today()}.md")
return core + index + today # 总共 ~2000 token
def on_user_message(msg): # 按需加载 L2 子文件 if mentions_project(msg, "blog"): context = read("memory/project-blog.md")
# 极少数情况才翻 L3 历史 if asks_about_specific_date(msg): context = read(f"memory/{extract_date(msg)}.md")启动成本约 2000 token,相比把所有历史对话塞进去(轻松 20000+ token),这是一个数量级的优化。
四、蒸馏机制 —— 从日志到知识
三层架构的关键在于 信息在层间流动:
L3 原始日志 ──蒸馏──→ L2 主题文件 ──提炼──→ L1 核心记忆 ↑ │ │ 定期清理过期内容 │ └─────────────────────────────────────────┘什么是蒸馏?
类比人类学习:你每天上课记了一堆笔记(L3),周末整理成知识点(L2),考试前再浓缩成一页速记卡(L1)。
蒸馏 = 从原始日志中提取有价值的信息,合并到主题文件中。
蒸馏的触发时机
我的实践是 每 3 天做一次蒸馏,可以用 cron 任务或者在 Agent 空闲时(heartbeat)自动执行:
def distill(): # 1. 读取最近 3 天的 L3 日志 logs = [read(f"memory/{d}.md") for d in last_3_days()]
# 2. 用 LLM 提取有价值的信息 prompt = f""" 以下是最近 3 天的工作日志: {logs}
请提取: 1. 新的技术决策或发现 2. 需要长期记住的用户偏好 3. 项目进展和状态变更 4. 踩过的坑和解决方案
按主题分类输出。 """ insights = llm(prompt)
# 3. 更新 L2 对应的主题文件 for topic, content in insights: append(f"memory/{topic}.md", content)
# 4. 如果有足够重要的信息,更新 L1 if has_critical_update(insights): update("MEMORY.md", critical_items)蒸馏示例
L3 原始日志:
2026-04-07: 部署博客时 OOM 了,加了 2G swap 解决2026-04-08: 又 OOM 了,swap 不够,改成 4G2026-04-09: 博客构建稳定了,4G swap 是最低要求蒸馏到 L2(infra.md):
## 博客构建- Astro 构建需要 4G+ swap(4G 物理内存不够)- 不要在沙盒构建,只能在服务器上构建提炼到 L1(MEMORY.md):
- 博客构建必须在服务器上(需要 4G swap),沙盒会 OOM三天的试错经验,浓缩成一行核心记忆。下次再遇到构建任务,Agent 直接就知道该怎么做,不用再踩一遍坑。
五、实际效果
这套架构我已经在自己的 Agent 上跑了一段时间,分享几个关键数据:
Token 消耗对比
| 方案 | 每次会话启动 token | 趋势 |
|---|---|---|
| 全量历史塞 prompt | 15,000 - 50,000+ | 📈 线性增长,越用越贵 |
| Mem0 向量检索 | 3,000 - 8,000 | 📊 相对稳定,但检索结果有噪音 |
| 三层文件架构 | 1,500 - 2,500 | 📉 稳定,L1 固定 + L2 按需 |
token 消耗降低约 50-70%,而且不会随着使用时间增长而膨胀——因为 L1 有 50 行硬限制,L2 按需加载,L3 虽然在增长但不会被读取。
信噪比提升
全量历史的问题是:90% 的内容跟当前对话无关。模型的注意力被大量无关信息稀释,反而容易”忘记”重要的东西。
三层架构的 L1 是 纯信号(人工/蒸馏提炼过的),L2 是 高信号(按主题组织),只有 L3 是原始噪音——但 L3 平时不读。
实际体验:Agent 对用户偏好的遵守率明显提高,“我不是说过不要用 Java 吗”这种对话基本消失了。
可维护性
半年后回头看:
MEMORY.md始终保持 50 行以内,干净利落memory/index.md有十几个主题文件,结构清晰- L3 日志积累了 180+ 个文件,但完全不影响性能(不读就不占资源)
- 任何人(包括未来的你)打开 workspace 都能快速理解整个记忆结构
这是纯文件方案最大的优势:人类可读、可编辑、可 git 管理。出了问题你可以直接打开文件看,不用去翻数据库。
六、什么时候该上数据库?
文件系统方案虽好,但不是万能的。以下是我的判断标准:
继续用文件系统 ✅
- 单用户 / 个人 Agent
- 记忆条目 < 1000 条
- 不需要复杂的语义检索(关键词 + 文件组织够用)
- 想保持简单、零依赖
- 需要人类直接编辑记忆
该上 SQLite 🗄️
- 需要结构化查询(“最近 7 天提到过的所有项目名”)
- 记忆条目 1000 - 100,000
- 需要事务保证(多个 Agent 并发写入)
- 仍然想保持单文件部署的简洁
import sqlite3
db = sqlite3.connect("memory.db")db.execute(""" CREATE TABLE IF NOT EXISTS memories ( id INTEGER PRIMARY KEY, topic TEXT, content TEXT, importance INTEGER DEFAULT 0, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, last_accessed TIMESTAMP )""")
# 按重要性 + 相关性检索memories = db.execute(""" SELECT content FROM memories WHERE topic = ? ORDER BY importance DESC, last_accessed DESC LIMIT 10""", ("blog",)).fetchall()该上向量数据库 🔍
- 需要真正的语义检索(“跟微服务架构相关的所有记忆”)
- 记忆条目 > 100,000
- 多模态记忆(文本 + 图片 + 代码)
- 多用户场景,需要隔离
该上 MySQL/PostgreSQL 🏢
- 多 Agent 协作,需要强一致性
- 企业级场景,需要审计日志
- 与现有业务数据库集成
我的建议:从文件系统开始,遇到瓶颈再升级。 过早引入数据库是最常见的过度工程——你的 Agent 可能永远也不需要处理十万条记忆。
七、总结
AI Agent 的记忆问题,本质上是一个 信息管理 问题:
- 存什么 —— 不是所有信息都值得记住(蒸馏机制)
- 怎么存 —— 分层存储,热数据在上,冷数据在下(三层架构)
- 怎么取 —— 固定读 L1 + 按需读 L2 + 极少读 L3(读取策略)
这和人类的记忆机制其实很像:你不会把每天吃了什么都记住,但你会记住”那家餐厅的鱼很难吃,别再去了”。好的记忆系统不是记得多,而是记得对。
如果你也在做 AI Agent,不妨从最简单的方案开始:
- 创建一个
MEMORY.md,手动写入关键信息 - 每天记个日志
memory/YYYY-MM-DD.md - 每周花 10 分钟做一次蒸馏
- 遇到瓶颈再考虑 Mem0 或向量数据库
记住:最好的架构不是最复杂的,而是最适合你当前阶段的。 一个维护得当的文件系统,比一个没人管的向量数据库有用得多。
如果你对 AI Agent 开发感兴趣,欢迎关注后续文章。下一篇我们聊聊 Agent 的工具调用优化——如何让你的 Agent 少犯”手滑”的错误。 🛠️
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!