Mem0
Agent Memory · arXiv 2025 · 2504.19413v1

Mem0:把对话提炼成可维护的记忆,而不是反复塞上下文

长期对话里,用户上周说过“我吃素”,这周模型却在推荐鸡肉。扩大上下文窗口只能推迟遗忘,还会把每次请求变贵;传统 RAG 又把原始对话块整段检索回来,噪声很多。 Mem0 的做法是让 LLM 从对话里提取事实,再用 ADD / UPDATE / DELETE / NOOP 维护一个小而一致的记忆库。

Prateek Chhikara, Dev Khant 等 · Mem0 arXiv 2504.19413v1 ↗
TL;DR · 30 秒抓住核心

论文要解决的是多会话长期记忆:对话跨越几天、几周,内容远超上下文窗口;而真实对话又不是按主题连续的,用户会在一堆无关话题之间跳。直接把整段历史塞进上下文,成本随长度增长;把原始对话切块做 RAG,又会把大量无关文本一起检索回来。

Mem0 把记忆做成“提取—更新”循环。提取时,LLM 同时看整段对话的摘要和最近 m=10 条消息,从新的消息对里提炼候选事实。更新时,先用向量检索出 top s=10 条相似旧记忆,再把候选事实和这些旧记忆一起交给 LLM,由它通过 tool call 选择 ADD / UPDATE / DELETE / NOOP。也就是说,记忆库的一致性由 LLM 自己维护,不另训分类器。

Mem0g 把事实进一步存成有向图:实体是节点,关系是三元组;新信息进来时先做冲突检测,过时的关系标记为 invalid 而不是物理删除,以保留时间信息。图版本在 LOCOMO 的 temporal 问题上更高,但建图和检索都更贵。

在 LOCOMO 上,Mem0 的 overall J 是 66.88%,Mem0g 是 68.44%;全文上下文仍然最高,72.90%,但 p95 延迟 17.117 s、每次约 26,031 token。Mem0 把 p95 压到 1.440 s,每次查询检索的 token 降到 1,764;代价是 overall J 低 6.02 个百分点。

66.88%
Mem0 的 overall J
LOCOMO 全数据集
68.44%
Mem0g 的 overall J
比 Mem0 高 1.56 个百分点
91.6%
Mem0 的 p95 延迟降幅
17.117 s → 1.440 s
01

上下文窗口放大的是容量,不是记忆

先分清三个问题:忘掉旧信息、每次请求都变贵、检索回来的内容噪声太多。

论文用“素食者”场景开篇:用户说过自己吃素,几天后模型却推荐了鸡肉菜。这不是模型“没看到”,而是那段对话已经不在当前上下文里。LLM 的参数不会在推理时更新,固定窗口之外的信息等于不存在(§1)。

把窗口从 128k 扩到 200k/10M 甚至更大,能推迟这个问题,但推不掉。论文给了两个理由:第一,对话历史会持续增长,几周、几个月后总会超过任何有限窗口;第二,真实对话的主题并不连续,用户可能先提饮食偏好,再聊几个小时的编程,偏好信息会被大量无关内容淹没(§1)。即使能把全部历史塞进去,每次请求都要重新读一遍,token 成本和延迟都随长度上涨。

全文上下文

准确率最高,但每次都要重读全部历史

Table 2 里 full-context 的 overall J 是 72.90%,是所有方法里最高的;代价是每次请求约 26,031 token,p95 总延迟 17.117 秒。对话再长,这两个数字还会涨。

传统 RAG

检索原始文本块,噪声与无关内容一起进来

RAG 把对话切成固定长度块,按相似度取 top-k。块里往往混着与问题无关的句子,模型要在噪声里找答案。Table 2 里最好的 RAG 配置 overall J 是 60.97%,比 Mem0 低 5.91 个百分点。

Mem0 的假设是:与其在查询时从原始对话里“再找一遍”,不如在对话发生时就把显著信息提炼出来,维护成一个结构化、去重、可更新的记忆库。查询时只取相关事实,既减少 token,也减少噪声。

02

六类基线:有的准但慢,有的快但记不住

论文把对比对象分成六类,问题集中在“质量、延迟、成本”三者不能同时兼顾。

论文的基线覆盖六类(§3):已有的 LOCOMO 基准方法(LoCoMo、ReadAgent、MemoryBank、MemGPT、A-Mem)、不同 chunk 大小与 top-k 的 RAG、全文上下文、开源记忆方案 LangMem、OpenAI 的 ChatGPT memory 功能、以及记忆管理平台 Zep。Mem0 的全部 LLM 操作使用 GPT-4o-mini;可配置基线中,§3.3 只明确 LangMem 与 OpenAI 使用 GPT-4o-mini,Zep 未说明模型(§2.1、§3.3);RAG 与 LangMem 使用 text-embedding-small-3 作 embedding(§3.3);温度设为 0,除非另有说明(§3.3)。

Table 2 摘录 · 各方法的 overall J、总延迟与每次查询检索的 chunk / memory token。延迟单位是秒;RAG 行取 overall J 最高的配置(k=2, chunk 256)。
方法Overall J (%)Total p50 (s)Total p95 (s)Chunk / memory tokens
Full-context72.909.87017.11726,031
RAG (k=2, 256)60.970.8021.907256
LangMem58.1018.5360.40127
Zep65.991.2922.9263,911
OpenAI memory52.900.4660.8894,437
A-Mem48.381.4104.3742,520
Mem066.880.7081.4401,764
Mem0g68.441.0912.5903,616

Table 2 原表的 overall J 为 mean ± 1 SD(10 次独立运行,§3.2),例如 Mem0 66.88 ± 0.15%、Mem0g 68.44 ± 0.17%;本表只转录均值,± 值未转录。token 列是每次查询检索到的上下文,不是记忆库总大小(§3.2)。RAG 行的 256 是 chunk size;k=2 时每次检索两个块,不是 256 token 的检索上下文。

这张表里有两组对照最说明问题。第一组是 LangMem:记忆 token 只有 127,但搜索阶段 p50 就 17.99 秒、p95 59.82 秒,总延迟 p95 到 60.40 秒,交互场景基本不可用。第二组是全文上下文:J 最高,但 token 是 Mem0 的约 14.8 倍,p95 延迟是 Mem0 的约 11.9 倍。Mem0 想证明的是中间那条线:质量接近全文上下文;p95 延迟 1.440 s 低于最好的 RAG 的 1.907 s,但每次查询检索的 memory token 是 1,764,约为 RAG 单块 chunk size 256 token 的 6.9 倍;RAG 行是 k=2,实际拼接两个 chunk(最多约 512 token),对应约 3.4 倍。原文说的 “a fraction of the token and latency cost”(§4.3)是相对 full-context,不是相对 RAG。

Zep 是最接近的对手:overall J 65.99%,比 Mem0 低 0.89 个百分点;它的记忆 token 3,911,p95 2.926 秒。open-domain 上 Zep 的 76.60% 高于 Mem0 的 72.93%(差 3.67 个百分点),也高于 Mem0g 的 75.71%(差 0.89 个百分点)。

03

提取事实,再让 LLM 决定加、改、删还是不动

Mem0 的核心不是向量库,而是“提取 + 更新”这两个 LLM 环节;图版本只是把存储结构换成了实体—关系图。

提取:用摘要看全局,用最近消息看细节

每当有一对新消息(通常是用户消息 + 助手回复),系统不会直接存原文,而是构造一个提示:P = (S, {mt−m, …, mt−2}, mt−1, mt)。其中 S 是整段对话的摘要,后两项是最近 m 条历史消息和当前消息对。摘要由异步模块定期刷新,不阻塞主流程;论文这样设计的理由是:摘要提供全局主题,最近消息提供可能还没进摘要的细节(§2.1)。实验里 m=10。

提取函数 φ(P) 的输出是一组候选事实 Ω = {ω1, …, ωn}。这些事实是简短的自然语言陈述,不是原始对话片段;论文说这样做的目的是提高信噪比,让后续检索和回答都只面对“值得记”的内容。

更新:先找相似旧记忆,再让 LLM 选操作

每条候选事实都要和现有记忆库比对。系统先用向量检索取出 top s 条语义最相似的旧记忆(实验里 s=10),把候选事实和这 s 条旧记忆一起交给 LLM;LLM 通过 function-calling 接口从四个操作里选一个(§2.1、Appendix B Algorithm 1):

ADD

新增

没有语义等价的旧记忆,就生成一个新 id,把事实加入记忆库。

UPDATE

替换 / 补充

旧记忆包含可补充的信息时,用新事实替换旧条目;论文的伪代码还比较了信息量,只有新事实信息更多才更新。

DELETE / NOOP

删除 / 不动

新事实与旧记忆矛盾时删除旧条目;事实已存在或不重要时什么都不做。

论文强调这里没有单独训练一个分类器,而是利用 LLM 的推理能力直接判断候选事实与旧记忆的语义关系。这样做的好处是不用为“该加还是该改”标注数据;代价是每次更新都要调 LLM,记忆写入的成本比纯向量库高。

Mem0g:把事实存成有向图

图版本的存储是 G = (V, E, L):节点 V 是实体(如 Alice、San_Francisco),边 E 是关系(如 lives_in),标签 L 给节点一个语义类型(Person、City 等)。每个实体节点带三样东西:实体类型、一个 embedding、创建时间戳;关系存成三元组 (vs, r, vd)(§2.2)。

建图分两步:entity extractor 先从文本里识别实体及其类型,relationship generator 再判断实体之间是否存在有意义的关系,并给关系打标签。新信息进图时,conflict detector 找出可能冲突的已有关系,update resolver 判断哪些关系应该过时;过时的关系标记为 invalid,而不是物理删除,这样时间性推理仍然能看到“曾经成立、后来失效”的事实(§2.2、Figure 3)。

检索也分两路:一路是 entity-centric,先从 query 里识别关键实体,用语义相似度定位节点,再沿入边和出边扩展子图;另一路直接对所有关系三元组的文本做相似度检索,返回超过阈值的关系。两路结果一起作为回答上下文。实现上,图数据库用 Neo4j,实体与关系抽取仍由 GPT-4o-mini 完成(§2.2)。

04

写入按事实数调 LLM,查询只读一小段记忆

Mem0 省的是查询时重读历史的开销,付的是写入时提取与更新的事实级 LLM 调用。

写入路径的调用次数由消息对数量和候选事实数共同决定:每来一对新消息,提取器做一次 LLM 调用;每条候选事实再做一次向量检索和一次 tool-call LLM 调用(§2.1、Appendix B Algorithm 1)。它不需要在每次写入时重读整段历史,但总调用数会随消息对数量增长。Table 2 的延迟只统计查询与回答,论文只在 §4.5 给出“图构建最坏情况一分钟内完成”这一句写入侧时间,没有写入 token、延迟分布或吞吐数据。

查询侧

只把相关记忆拼进上下文

Table 2 的 token 列是每次查询检索到的记忆上下文:Mem0 为 1,764 token,Mem0g 3,616,Full-context 26,031(§3.2 定义)。Mem0 的 search 延迟 p50 / p95 为 0.148 / 0.200 秒,总延迟 0.708 / 1.440 秒。

存储侧

记忆库比单次检索上下文大

§4.5 按 conversation 统计记忆库规模:Mem0 平均约 7k token,Mem0g 约 14k,Zep 超过 600k;原始对话平均约 26k token。查询时并不会把整个库塞进上下文。

图版本的额外开销集中在构建与更新:实体抽取、关系生成与 update resolver 依赖 LLM;冲突检测的具体实现论文未展开。论文称 Mem0g 的图构建在最坏情况下也能在一分钟内完成(§4.5),但没有给出节点/边规模、并发度或失败重试的细节。作为对照,§4.5 报告 Zep 写入后立即检索常失败,数小时后重跑同样的检索,结果明显更好;论文推测这与异步 LLM 调用和后台处理有关。

查询成本不随对话历史线性增长:Mem0 只检索 top s 条相似记忆,Mem0g 只扩展相关子图与超过阈值的三元组(§2.1、§2.2)。写入成本随消息对数量和事实数量增长推断(依据 §2.1:每对消息一次提取调用,每条候选事实一次更新调用);论文没有报告多用户并发写入下的吞吐或限流策略,这两项是生产部署仍需补测的部分。

05

写入时提炼,查询时只取相关事实

上半部分是 Mem0 的写入循环,下半部分是 Mem0g 的图构建与检索。

新消息对 用户 + 助手 mt−1, mt 上下文 全局摘要 S 最近 m=10 条 异步刷新摘要 提取器 φ(P) 候选事实 Ω 自然语言陈述 检索旧记忆 top s=10 向量相似度 LLM tool call ADD / UPDATE DELETE / NOOP 不另训分类器 记忆库 M 事实 + id 持续更新 Mem0g:实体抽取 → 关系三元组 → 冲突检测 → update resolver Entity extractor 节点 + 实体类型 Person / City / Event Relationship generator (vs, r, vd) lives_in / prefers Conflict detector 找出可能冲突的关系 交给 update resolver 标记 invalid 不物理删除 保留时间信息 查询 实体扩展 + 语义检索 查询时:记忆库 / 图检索 → 相关事实拼进上下文 → LLM 生成回答
按 Figure 2、Figure 3 与 Algorithm 1 重绘:覆盖 Mem0 的提取—更新循环、四种操作、Mem0g 的实体/关系抽取、冲突检测与 invalid 标记、以及双路检索。未覆盖 prompt 全文、函数调用的具体 schema、图数据库事务与失败重试;页面不做记忆更新模拟。

两条流的共同点是“先把信息变少,再交给 LLM”。Mem0 把对话变成事实,Mem0g 把事实变成实体和关系;查询时不再是“读全部历史”,而是“读与当前 query 相关的一小部分”。这也解释了为什么它能同时降低 token 和延迟推断(依据 §2.1 的提取—更新流程:查询侧只读相关事实,写入侧才做提取与更新):省掉的是每次请求重读历史的开销,增加的是写入时的提取与更新 LLM 调用。

06

质量接近全文上下文,延迟降一个数量级

先交代评测设置,再看四类问题的 J、overall 与效率;最后指出图版本不是每个维度都更好。

评测设置:一个数据集、一个裁判、十次重复

这些数字的边界由 LOCOMO 的规模和指标决定:10 段多会话日常对话,质量分主要来自 LLM 裁判。

§3 实验设置 · 数据集、指标与实现参数。
项目设置出处
数据集LOCOMO:10 段多会话对话,每段约 600 轮、平均 26,000 token,平均 200 个问题§3.1
问题类型single-hop、multi-hop、open-domain、temporal;原数据集的 adversarial 类因没有标准答案被排除§3.1
质量指标F1、BLEU-1、LLM-as-a-Judge(J)。§3.2 称 J 从事实准确性、相关性、完整性、上下文适配四个维度评估;Appendix A 的 judge prompt 实际只要求输出 CORRECT / WRONG 并附一句理由——两处口径并列§3.2、Appendix A
效率指标search / total 的 p50 与 p95 延迟;chunk 或 memory token 数§3.2、Table 2
推理引擎Mem0 的 LLM 操作使用 GPT-4o-mini;可配置基线中 LangMem 与 OpenAI 明确使用 GPT-4o-mini,Zep 未说明模型;RAG 与 LangMem 的 embedding 用 text-embedding-small-3(§2.1 只说明向量库使用 dense embeddings)§2.1、§3.3
更新参数最近消息 m=10;相似旧记忆 s=10§2.1
温度0,除非另有说明§3.3
J 的重复每个方法在整份数据上独立跑 10 次,报告均值 ±1 SD§3.2
图存储Neo4j§2.2

这套设置有一个明确的限制:只有一个数据集,而且只覆盖多会话日常对话。LOCOMO 的 10 段对话平均 26k token,大约相当于一段较长对话,不是跨月的真实产品日志。论文用 10 次独立运行的均值来降低 J 的随机性,但没有在第二个数据集上复验。

另一个细节是 adversarial 问题被排除。这类问题测的是“识别无法回答的问题”,没有标准答案,论文说预期行为是模型应该识别出来;排除它是合理的,但也意味着这套评测没有覆盖“记忆里没有答案时会不会胡编”这一风险。

四类问题:Mem0 在 single-hop / multi-hop 最高,Mem0g 在 temporal 最高

Table 1 按问题类型拆 J。下表只转录 6 个方法;MemGPT、LoCoMo、ReadAgent、MemoryBank 等行以及 F1 / BLEU-1 列未转录。

Table 1 摘录 · LLM-as-a-Judge(J)分数,按 single-hop / multi-hop / open-domain / temporal 四类问题。
方法Single-HopMulti-HopOpen-DomainTemporal
A-Mem*39.7918.8554.0549.91
LangMem62.2347.9271.1223.43
Zep61.7041.3576.6049.31
OpenAI63.7942.9262.2921.71
Mem067.1351.1572.9355.51
Mem0g65.7147.1975.7158.13

Table 1 原表的 J 为 mean ± 1 SD(10 次独立运行,§3.2),例如 Mem0 的 single-hop 是 67.13 ± 0.65;本表只转录均值,± 值未转录。A-Mem* 为作者重跑 A-Mem 的结果,temperature=0,以生成 LLM-as-a-Judge 分数(Table 1 caption)。

交互:在质量、p95 延迟、记忆 token 之间切换

下面把 Table 2 的 8 个方法按三种指标重画。切换指标会重画全部柱子;柱高按当前指标的最大值缩放,标签是表格原值,不是归一化后的分数。陶土红是 Mem0,深陶土是 Mem0g,灰柱是基线。

当前读数
Overall J:Full-context 72.90 最高;Mem0 66.88,Mem0g 68.44;Zep 65.99;最好的 RAG 60.97
Mem0 Mem0g 基线
手算:两组读数与差值与上面的交互同一数据源

配置 A:质量。Mem0 的 overall J = 66.88,最好的 RAG = 60.97,绝对差 = 66.88 − 60.97 = 5.91 个百分点;Full-context = 72.90,比 Mem0 高 72.90 − 66.88 = 6.02 个百分点。Mem0g 比 Mem0 高 68.44 − 66.88 = 1.56 个百分点,相对提升 1.56 / 66.88 = 2.3%。柱高(当前指标最大值是 Full-context 的 72.90):Mem0 66.88 / 72.90 = 91.7%,Mem0g 68.44 / 72.90 = 93.9%。

配置 B:p95 总延迟。Full-context = 17.117 s,Mem0 = 1.440 s,降幅 (17.117 − 1.440) / 17.117 = 91.6%;Mem0g = 2.590 s,降幅 (17.117 − 2.590) / 17.117 = 84.9%。LangMem 的 p95 是 60.40 s,比 Full-context 还高。柱高(当前指标最大值是 LangMem 的 60.40):Mem0 1.440 / 60.40 = 2.4%,Mem0g 2.590 / 60.40 = 4.3%。

交互只把表格数值按当前指标的最大值缩放成柱高,不做平均或标准差;表里的 J 是 10 次独立运行的均值(±1 SD 未转录),论文没有说明延迟的重复次数,页面不重新计算。柱高缩放只影响视觉,读数与手算都用表格原值。p95 读数按原表精度显示,60.40 不补成 60.400。

反直觉 1:全文上下文仍然最准,Mem0 赢的是成本

Full-context 的 overall J 是 72.90%,比 Mem0 高 6.02 个百分点,比 Mem0g 高 4.46 个百分点。也就是说,如果只追求准确率,把全部历史塞进上下文仍然更好。Mem0 的卖点是:用 91.6% 的 p95 延迟降幅和 93.2% 的 token 降幅,换 6.02 个百分点的质量损失。这个交换在实时交互里可能值得,但不是“全面超过全文上下文”。

token 的口径是“每次查询检索到的记忆上下文”,不是记忆库总大小:Full-context 每次约 26,031 token,Mem0 检索 1,764 token,减少 93.2%;Mem0g 检索 3,616 token,减少 86.1%(两个降幅都相对 full-context 的 26,031 输入上下文)。记忆库本身按 §4.5 平均为 Mem0 约 7k tokens/conversation、Mem0g 约 14k。这里的 token 不含每次回答的生成开销,论文也没有把写入阶段的 LLM 调用 token 计入这张表。

反直觉 2:图版本不是每个维度都更好

Mem0g 的 overall J 比 Mem0 高 1.56 个百分点(相对 2.3%),temporal 上高 2.62 个百分点(58.13 对 55.51),open-domain 高 2.78 个百分点。但在 multi-hop 上,Mem0g 的 47.19% 比 Mem0 的 51.15% 低 3.96 个百分点,也低于 LangMem 的 47.92%。作者在 §4.1 和 §4.2 给出了推测性解释——图结构在复杂整合任务里可能存在 “potential inefficiencies or redundancies” / “potential overhead or redundancy”,但没有做消融;这里按 Table 1 并列,不把推测写成结论。

成本也更高:Mem0g 每次查询检索 3,616 token,约为 Mem0(1,764)的 2.05 倍;p95 总延迟 2.590 秒,比 Mem0 的 1.440 秒高。图构建本身论文说在 worst case 下也能在一分钟内完成(§4.5),但这属于写入侧开销,Table 2 的延迟只统计查询与回答。

反直觉 3:Zep 在开放域更高,LangMem 的延迟最差

Zep 的 overall J 65.99%,比 Mem0 低 0.89 个百分点,但 open-domain 是 76.60%,比 Mem0g 的 75.71% 高 0.89 个百分点,也是 J 列最高。这说明“总榜第一”不等于每个问题类型都第一。LangMem 则是另一个极端:记忆只有 127 token,但 p95 总延迟 60.40 秒,是全文上下文的约 3.5 倍。

论文摘要声称「在四类问题上均领先」,但 Table 1 的 open-domain J 最高是 Zep 的 76.60%(Mem0g 75.71%、Mem0 72.93%),两处并列,不替原文消解。

论文摘要说 Mem0 相对 OpenAI 的记忆功能在 J 上有 26% 的相对提升。按 Table 2 的 66.88 对 52.90 复算:(66.88 − 52.90) / 52.90 = 26.4%,与摘要一致。这里是相对提升,绝对差是 13.98 个百分点。

07

它解决不了:单数据集、裁判偏差、写入成本与对抗问题

这些限制决定了 Mem0 的数字能推广到哪里,以及部署时要额外补什么。

限制 1

只在 LOCOMO 上验证

10 段多会话日常对话、平均 26k token。法律、医疗、企业知识库这类领域没有实验;跨月、跨产品的真实记忆负载也没有覆盖。

限制 2

LLM 裁判不是人类裁判

J 由另一个 LLM 打分。§3.2 说它从事实准确性、相关性、完整性、上下文适配四个维度评估;Appendix A 的 judge prompt 却只要求输出 CORRECT / WRONG,并附一句理由。两处口径并列,页面不替原文调和。裁判模型可能偏爱某种风格,论文没有报告与人类评分的相关性。

限制 3

写入阶段要调 LLM

每条新事实都要检索旧记忆并做一次 tool call。Table 2 的延迟只统计查询与回答,没有把写入的 LLM 调用算进去;高频写入场景的成本需要单独测。

对抗问题被排除。LOCOMO 原有的 adversarial 类问题没有标准答案,论文把它排除在评测之外。这意味着页面上的 J 分数不包含“记忆里没有相关信息时,模型会不会编一个答案”这一维度。对生产系统来说,这个维度至少和准确率同样重要。

更新操作本身可能出错。ADD / UPDATE / DELETE / NOOP 由 LLM 判断;如果候选事实抽取错了,或者相似旧记忆检索错了,后续操作会把错误写进记忆库。论文没有给出更新操作的准确率,也没有做对抗性注入实验(例如故意让新消息与旧记忆矛盾)。

图版本的时间信息是“标记”而非“删除”。过时关系被标成 invalid,查询时是否、以及如何过滤 invalid 关系,论文在正文只说“enable temporal reasoning”,没有给出过滤策略的消融。invalid 关系长期累积会不会拖慢检索,论文没有报告。

什么时候别用:如果任务只需要单轮问答、对话不超过上下文窗口,Mem0 的提取与更新开销是多余的;如果写入频率极高而查询很少,省下的查询 token 可能抵不过写入调用。反过来,在多会话、查询频繁、上下文成本敏感的场景里,它的思路最直接:把“每次重读历史”换成“写入时提炼、查询时取事实”。