AI Agent 记忆优化:从 Mem0 到三层架构的实战方案

3795 字
19 分钟
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 提取记忆片段 → 向量化存储 → 下次对话时语义检索 → 注入 prompt
from 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⭐⭐⭐⭐
MemoriSQL 结构化记忆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 不够,改成 4G
2026-04-09: 博客构建稳定了,4G swap 是最低要求

蒸馏到 L2(infra.md):

## 博客构建
- Astro 构建需要 4G+ swap(4G 物理内存不够)
- 不要在沙盒构建,只能在服务器上构建

提炼到 L1(MEMORY.md):

- 博客构建必须在服务器上(需要 4G swap),沙盒会 OOM

三天的试错经验,浓缩成一行核心记忆。下次再遇到构建任务,Agent 直接就知道该怎么做,不用再踩一遍坑。

五、实际效果#

这套架构我已经在自己的 Agent 上跑了一段时间,分享几个关键数据:

Token 消耗对比#

方案每次会话启动 token趋势
全量历史塞 prompt15,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 的记忆问题,本质上是一个 信息管理 问题:

  1. 存什么 —— 不是所有信息都值得记住(蒸馏机制)
  2. 怎么存 —— 分层存储,热数据在上,冷数据在下(三层架构)
  3. 怎么取 —— 固定读 L1 + 按需读 L2 + 极少读 L3(读取策略)

这和人类的记忆机制其实很像:你不会把每天吃了什么都记住,但你会记住”那家餐厅的鱼很难吃,别再去了”。好的记忆系统不是记得多,而是记得对。

如果你也在做 AI Agent,不妨从最简单的方案开始:

  1. 创建一个 MEMORY.md,手动写入关键信息
  2. 每天记个日志 memory/YYYY-MM-DD.md
  3. 每周花 10 分钟做一次蒸馏
  4. 遇到瓶颈再考虑 Mem0 或向量数据库

记住:最好的架构不是最复杂的,而是最适合你当前阶段的。 一个维护得当的文件系统,比一个没人管的向量数据库有用得多。


如果你对 AI Agent 开发感兴趣,欢迎关注后续文章。下一篇我们聊聊 Agent 的工具调用优化——如何让你的 Agent 少犯”手滑”的错误。 🛠️

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

AI Agent 记忆优化:从 Mem0 到三层架构的实战方案
https://boke.hackerdream.xyz/posts/ai-agent-memory-optimization/
作者
晴天
发布于
2026-04-09
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
晴天
Hello, I'm 晴天.
公告
欢迎来到我的博客!这是一则示例公告。
音乐
封面

音乐

暂未播放

0:00 0:00
暂无歌词
分类
标签
站点统计
文章
125
分类
17
标签
287
总字数
257,955
运行时长
0
最后活动
0 天前

目录