MemForest:当 Agent 的"记忆"被当成数据库问题来做,写吞吐量直接 6 倍
一个困扰长上下文 Agent 半年的问题:你以为是检索质量不够,其实是写入路径根本卡死了。
写在前面
最近在调一个长程多轮对话的 Agent,碰到一个很扎心的现象——上线第一周还挺欢实,跑到第三周整个系统就开始变"重"。每问一个问题要等 8 秒、10 秒,看日志才发现,时间根本不花在生成回答上,全花在"更新记忆"上了。
我之前以为这是召回的问题,疯狂调 embedding 模型、调 chunk 切分、加 re-rank。结果发现都没用——因为瓶颈压根不在读,而在写。
每来一段新对话,Agent 要把它"消化"进现有记忆里。现在主流的 Mem0、MemoryOS、EverMemOS 这一类系统,都是用 LLM 边读边改:把相关记忆全捞出来 → 让 LLM 决定哪些要更新、哪些要合并 → 再写回去。听起来挺聪明,但有一个致命问题:LLM 卡在写入路径上,每次写都要让 LLM 跑一遍,记忆越多越慢,慢到根本没法用。
这篇 MemForest 是新加坡国立 + Zero Gravity Labs 在 2026 年 5 月挂到 arXiv 的 paper(投 VLDB),它做的事其实只有一句话:别再用 LLM 串行地维护全局摘要了,把记忆当成一个写优化的时序数据库来管理。
我读完之后第一反应是:终于有人从数据库的角度认真看 Agent 记忆这件事了。前置工作里那些"记忆 OS""三级缓存"的命名其实都在装数据库,但没有一个真把 B+树/LSM 这些写优化结构的本质拿过来用。MemForest 把这层窗户纸捅破了。
效果也确实给力:在 LongMemEval-S 上 pass@1 拿到 79.8%(30B 模型下最强有状态基线),写吞吐量比 EverMemOS 快约 6 倍,写入路径关键路径从 O(M) 直接降到 O(log N) 量级。
下面我把这篇论文掰开揉碎讲一下——它的痛点诊断是怎么做的、为什么它的方案能 work、哪些数据值得信、哪些地方我觉得还有问题。
论文信息
- 标题:MemForest: An Efficient Agent Memory System with Hierarchical Temporal Indexing
- 作者:Han Chen, Zining Zhang, Wenqi Pei, Bingsheng He(新加坡国立大学),Ming Wu, Jason Zeng, Michael Heinrich, Wei Wu, Hongbao Zhang(Zero Gravity Labs)
- arXiv:2605.23986 (2026-05-16, cs.DB)
- 代码:github.com/Concyclics/MemForest
- 会议目标:VLDB(数据库顶会)
一、问题:现有 Agent 记忆系统到底卡在哪?
一张图看懂痛点

图1:左边是各家系统单次写入的延迟分解,写入耗时被维护操作(深色那段)严重拖累;右边是吞吐量-准确率帕累托前沿,MemForest 在两个指标上同时拿下最优。
这图我盯着看了一会儿。左边最让我意外的是 EverMemOS 那条柱子——大部分系统时间不是花在生成答案,也不是花在召回,而是花在"维护"上。说白了就是:用户问一句,系统忙着整理它的笔记,整理完了才有空回答你。
作者把现有系统的瓶颈拆成两个,我觉得拆得挺准:
瓶颈 1:串行 LLM-in-the-loop 抽取
当前主流系统(Mem0、MemoryOS、EverMemOS、LightMem)的写入流程几乎都长成这样:
每来一段对话,至少触发 2 次 LLM 调用,而且这两次都在写入的关键路径上。LLM 调用 = 几百毫秒到几秒,这就是延迟的源头。
瓶颈 2:粗粒度全状态重写
更要命的是,很多系统采用"全局摘要"或者"扁平合并"的策略——新来一段对话,要把它跟整个历史摘要重新揉一遍。这意味着维护成本随累积记忆 M 增长,而不是随新增证据 N 增长。记得越多,写得越慢。这是一个根本性的可扩展性灾难。
我之前在做类似系统时也踩过这个坑——当时图省事用了一个全局 markdown 文件存"长期记忆",每次更新让 LLM 重写整个文件。前两周还行,第三周就开始 OOM 了。当时没想明白,现在看其实就是这个问题:写入路径关键路径是 O(M)。
一张表说清楚关键路径
论文 Table 1 把各家系统的写入关键路径做了对比,我把它精简了一下:
| 系统 | 写路径关键路径 | 后果 |
|---|---|---|
| Mem0 | O(M) | 检索证据上的串行 LLM 更新 |
| MemoryOS | O(M+N) | 有序提升 + 热状态重写 |
| EverMemOS | O(M) | 单元级合并到维护内存 |
| LightMem | O(M+N) | 缓冲写入 + 全局合并 |
| MemPalace | O(M) | 快速追加,但不维护时序 |
| MemForest | O(log N) 量级 | 局部 MemTree 更新 + 并行刷新 |
注:M = 累积记忆量,N = 单棵树内事实数(远小于 M)。
这就是关键。从 O(M) 降到 O(log N),差不多就是从顺序扫数组降到 B+树查找的那种量级差距。如果你做过数据库索引,看到这一行就该对它的设计思路有数了。
二、核心思路:把 Agent 记忆当成"写优化的时序数据库"
我觉得 MemForest 最值钱的洞察其实就一句话:
Agent 的记忆问题,本质上是一个"高频写入 + 时序敏感 + 多视角检索"的数据管理问题。
数据库领域早就发明过应对这种问题的工具——LSM-Tree、B+树、分层索引、并发控制。但之前的 Memory OS 只是在用语义压缩在做"摘要",用 vector store 在做"召回",并没有把数据库的写优化思想拿过来。
MemForest 把这件事给做了。它的设计哲学有三条:
- 解耦 LLM 与写入关键路径:让 LLM 在写入时只负责"局部摘要",不再做"全局合并决策"
- 局部更新替代全状态重写:用一个分层时序索引(MemTree),让每次写入只影响 O(log N) 条路径
- 并行抽取 + 并行刷新:榨取硬件并发,让独立的写入操作真正并发执行
通用工作流:先看大家在做什么

图2:所有 Agent 记忆系统都跑在这个三段式上——抽取(写入路径起点)、维护(写入路径终点)、检索(读路径)。MemForest 的所有创新都集中在"抽取+维护"这一段。
任何 Agent 记忆系统都跳不出这三个动作。MemForest 没改变这个框架,但把"抽取"和"维护"的内部实现彻底重构了。
MemForest 整体架构

图3:左边是写路径(Session Ingestion + Lifecycle Maintenance),右边是读路径(Forest-level Recall → 树内 Browse)。中间这片"森林"由三类树构成:Session Tree(会话树)、Entity Tree(实体树)、Scene Tree(场景树)。
这张图信息量挺大,我们一块块拆。
共享内存基底(Shared Memory Substrate)
整个系统的"持久层"分两类:
- 持久状态(Persistent State):真理来源——规范化事实、作用域分配、MemTree 结构、源会话引用
- 派生访问构件(Derived Access Artifacts):可重新生成的——区间摘要、节点嵌入、根索引行
这种"持久 vs 派生"的分离,跟数据库的"基础表 vs 物化视图"完全是同一种思想。当你需要重做 ranking 或者改 embedding 模型时,只重生成派生构件就行,不用动持久状态。这是工程上非常友好的设计。
三种 MemTree:从不同视角组织同一份事实
| 树类型 | 组织方式 | 适用场景 |
|---|---|---|
| Session Tree(会话树) | 按单个会话的时序 | 保留原始交互上下文,回退用 |
| Entity Tree(实体树) | 围绕循环主题(人/项目/偏好) | 跨会话查"用户对 X 的看法" |
| Scene Tree(场景树) | 跨多实体的语义连贯情境 | 查"上次出差讨论了什么" |
同一条事实可以同时挂在多棵树上——这就是"森林"的来源。读的时候从不同视角召回,写的时候每棵树独立维护。
我蛮喜欢这个三视图设计。之前看过的一些方案要么只按时间组织(Session-only),要么只按实体组织(Entity-only),结果就是某些查询模式下召回率特别差。MemForest 在消融里也证明了这点(后面会看到),entity+scene 的组合已经很能打。
三、MemTree:把"数据库索引"搬到 Agent 记忆里
这是整篇论文最核心的技术。

图4:每棵 MemTree 是一棵按时间排序的平衡树。新事实从叶子追加进去,只有从该叶子到根的路径上的节点会被标记为 dirty 需要重摘要。
一句话讲清结构
- 叶子:按时间顺序存储局部证据(具体的 canonical facts)
- 内部节点:是其子节点区间的"摘要"(由 LLM 生成,但只摘要受影响的路径)
- 根:粗粒度的全局表示,用于森林级召回
- 分支因子 k ≈ 16(消融实验显示这是甜蜜点)
- 树高 h = ⌈log_k N⌉
写入时,新叶子一插入,只有它到根这条路径(O(log N) 个节点)需要重新摘要——其他分支完全不动。
写路径算法(Algorithm 1 简化版)
输入:内存基底 M,路由记录 R_t
输出:更新后的持久状态和派生构件
1. 按目标树分组路由记录:B ← GroupByTree(R_t)
2. 对每个 (T_σ, R_σ) ∈ B:
- 按时间排序 R_σ
- 创建叶子节点 ℓ
- 附加到 T_σ 并重平衡
- 标记从叶子到根的祖先为 dirty
3. 收集所有 dirty 节点,按 level 分组
4. 自底向上、并行刷新(同 level 节点之间、不同树之间均可并发):
- 叶子(entity/scene):直接 passthrough
- 叶子(其他):摘要 unit text
- 内部节点:摘要子节点
5. 并行更新 NodeIndex 和 RootIndex
这里的关键设计有两点:
第一,延迟刷新(Lazy Refresh)。dirty 标记不是立刻处理,而是攒一批一起处理。这让多个写入可以共享 dirty 路径(比如连续两条事实落到同一棵子树上,只摘要一次就够了)。
第二,按 level 并行。同一层的 dirty 节点之间没有依赖(B+树性质),不同树之间更没依赖,全部可以并发跑 LLM 摘要。这就把"串行 LLM 调用"变成了"并行 LLM 批处理"。
并行块抽取
写入的另一半是"抽取"——从原始对话里提取 canonical facts。MemForest 的做法是:
把会话切成块(默认 b=2 轮对话),每个块独立抽取,互不依赖、并发执行。这跟 MapReduce 的 Map 阶段完全是一个思路。
这里我觉得有个值得讨论的点:默认 b=2 是不是太激进了?2 轮对话能不能形成足够的上下文让 LLM 抽取出有意义的事实?论文没在这上面做太多消融,我猜实战里这个值得再调。
四、实验:数字硬不硬?
4.1 写入吞吐量:6× 加速名副其实
Table 2,LongMemEval 上的写入路径效率:
| 方法 | 30B 时间(s) | 30B 加速 | 4B 时间(s) | 4B 加速 |
|---|---|---|---|---|
| MemForest | 178.0 | 13.7× | 136.9 | 12.4× |
| Mem0 | 353.2 | 6.9× | 314.9 | 5.4× |
| EverMemOS | 1048.8 | 2.3× | 790.9 | 2.1× |
| MemoryOS | 2439.9 | 1.0× | 1695.1 | 1.0× |
看到这个数我愣了一下——MemForest 比最慢的 MemoryOS 快 13.7 倍,比 SOTA 的 EverMemOS 快约 6 倍。
但这里有个坑:MemForest 的 token 消耗是 1.143M,而 Mem0 只有 294K。也就是说MemForest 用更多的 token 换了更短的时间——它没有省 LLM 推理量,省的是关键路径上的串行等待。这个 trade-off 我觉得是合理的,因为 token 可以并发跑、可以用便宜模型,但关键路径延迟省不下来。
4.2 查询时延:纯 embedding 模式有惊喜
Table 3 的查询时延数据:
| 方法 | 30B Total (s) | 4B Total (s) |
|---|---|---|
| MemForest (LLM browse) | 4.60 | 4.30 |
| MemForest(emb 浏览) | 2.19 秒 | 2.42 秒 |
| Mem0 | 0.22 | 0.29 |
| MemoryOS | 2.29 | 1.10 |
| EverMemOS | 8.49 | 10.97 |
Mem0 在查询时延上是最快的——但你看回 Table 4 的准确率,它只有 32.8%(4B),基本没法用。
MemForest 的纯 embedding 浏览模式(emb)2.19 秒已经相当能打,跟 MemoryOS 持平但准确率高出一截。如果开 LLM browse 那 4.6 秒就有点慢了,但准确率最高。
4.3 准确率:LongMemEval-S 上拿了"最强有状态基线"
Table 4,30B 模型的 pass@1 准确率:
| 方法 | Overall | Single-User | Pref | K-Update | Multi-Sess | Temp |
|---|---|---|---|---|---|---|
| MemForest | 79.8 | 97.1 | 76.7 | 75.6 | 73.7 | 79.7 |
| MemForest (emb) | 78.4 | 94.3 | 70.0 | 76.9 | 69.9 | 81.2 |
| EverMemOS | 66.2 | 87.9 | 50.0 | 86.7 | 62.1 | 52.5 |
| LightMem | 67.0 | 94.3 | 76.7 | 73.1 | 64.7 | 65.4 |
| MemoryOS | 50.0 | 71.4 | 43.3 | 55.1 | 34.6 | 36.8 |
| Mem0 | 40.2 | 75.7 | 50.0 | 44.9 | 41.4 | 27.8 |
整体 79.8%,比 EverMemOS 的 66.2 高了 13.6 个点。Multi-Session(多会话推理)和 Temporal(时序推理)这两个 MemForest 特别强:73.7 vs 62.1,79.7 vs 52.5。
这个结果其实是合理的——MemTree 本身就是按时间组织的,对时序问题天然有优势。但 K-Update(知识更新)这一项 EverMemOS 是 86.7,比 MemForest 的 75.6 还高。我猜是因为 EverMemOS 的"全局合并"在"覆盖式更新"场景下确实更彻底,MemForest 的局部更新可能会留一些过时的旧叶子节点没清掉。
4.4 LoCoMo:被 EverMemOS 反超
Table 5,LoCoMo 上的准确率(30B):
| 方法 | Overall | Single-Hop | Multi-Hop | Open-End | Temporal | Adversarial |
|---|---|---|---|---|---|---|
| MemForest | 68.4 | 78.0 | 67.3 | 65.6 | 83.1 | 35.9 |
| EverMemOS | 69.6 | 76.2 | 86.6 | 62.5 | 88.1 | 19.7 |
这里 MemForest 输了 1.2 个点,主要输在 Multi-Hop 上(67.3 vs 86.6)。
我得说这个数挺值得玩味的。LoCoMo 是更注重多跳推理的 benchmark,需要把分散在多处的事实串起来。EverMemOS 那种"全局合并"的策略在多跳场景下有优势,因为它把相关的事实"揉"在一起了,而 MemTree 的局部组织反而会让多跳信息分散。
但反过来,MemForest 在 Adversarial(对抗性问题)上甩了 EverMemOS 16 个点(35.9 vs 19.7),说明它在区分真假信息上更稳定。
4.5 写路径可扩展性诊断

图6 是支撑这套设计选择的诊断图。重点看 (e):分支因子 k 在 16 左右是甜蜜点,太小(k=2 二叉树)或太大(k=64 接近扁平)都会让根召回率下降。
这里 (c) 和 (e) 给了我比较强的信心——层级并行不是空话,在更大的树上加速比反而更明显(说明它是真正可扩展的)。k=16 的甜蜜点也跟数据库 B+树的工程经验一致。
4.6 消融:哪些组件是真的必要?
Table 6,树家族组合(30B pass@8):
| 变体 | pass@8 |
|---|---|
| entity+scene+session | 86.7 |
| entity+scene | 86.7 |
| entity+session | 85.0 |
| session only | 85.0 |
| scene+session | 83.3 |
| scene only | 81.7 |
| entity only | 63.3 |
这个消融有点意思——完整三棵树和 entity+scene 两棵树效果一样。也就是说在 LongMemEval 上,session tree 是冗余的。
但作者还是保留了 session tree,理由是"原始上下文回退"。我能理解,但严格来说这一项是在赌某些特殊查询会需要原始上下文。如果做产品落地,可以考虑把 session tree 做成可选项,按需开启。
Table 7,检索/浏览策略:
| 变体 | pass@8 |
|---|---|
| flat-10 | 78.3 |
| root-only | 73.3 |
| emb | 85.0 |
| emb+planner | 83.3 |
| llm | 88.3 |
| llm+planner | 90.0 |
LLM browse + planner 拉满到 90%。但注意 emb+planner 反而比单纯 emb 差(83.3 vs 85.0)——planner 对嵌入浏览没有帮助,只对 LLM 浏览有帮助。这个发现挺反直觉的,作者也没深入解释。我猜是因为 planner 输出的"查询计划"对 embedding 检索可能引入了噪声,但对 LLM 来说能更好地利用结构化信息。
五、批判性看一眼:哪些地方值得打个问号?
读完整篇,我有几个想吐槽的点:
1. Token 消耗其实涨了,论文淡化了这点。 Mem0 写一次 294K token,MemForest 1.143M token——多了快 4 倍。MemForest 用并行抢回了延迟,但总算力消耗是涨的。如果你是按 token 计费的(用云端 API),账单会更难看。这点论文里没怎么强调。
2. b=2 默认块大小没充分论证。 切得太碎可能让单块抽取出的事实质量下降。我个人会想做一组从 b=2 到 b=8 的实验看看。
3. LoCoMo 输给 EverMemOS 这件事被一笔带过。 论文用"具有竞争力(competitive)"包装了一下,但 multi-hop 上输了快 20 个点其实挺严重的。如果你的 Agent 主要做多跳推理(比如复杂客服、研究助手),MemForest 不一定是最优解。
4. 写路径里仍然有 LLM 摘要。 论文卖点是"打破 LLM-in-the-loop",但严格说它只是把 LLM 从串行关键路径上挪到了批量并行路径上——LLM 还在写路径里,只是被批处理 + 并行化了。如果后续有人做出"完全无 LLM 写路径"(比如纯 embedding 维护),MemForest 这套就有点尴尬了。
5. Lifecycle Maintenance(合并、删除、迁移)被讲得很简略。 真实生产环境里,过时记忆怎么删、矛盾事实怎么处理、用户主动要求遗忘怎么办——这些才是工程上最头疼的。论文里这一块基本是 future work。
6. 没和 MemGPT、A-MEM 直接比。 Related Work 里提了,但实验里没有。这俩在长程记忆领域也是经常被对标的,缺席让 baseline 选择看起来有点"挑软柿子"的嫌疑。
不过这些吐槽不影响我对整篇 paper 的整体好感——它是这个方向上目前我看到最系统、最像数据库工程师在认真思考问题的方案。
六、对工程的启发:你能从这篇 paper 里抄什么?
如果你也在做长程对话 Agent / 长上下文记忆系统,下面几个思路可以直接借鉴:
-
写入关键路径上能不放 LLM 就别放 LLM。LLM 是关键路径的死亡之吻——一旦放上去,延迟天花板就锁死了。哪怕是把 LLM 调用挪到异步批处理也好。
-
维护成本要随 N(新增)增长,不能随 M(累积)增长。如果你的系统在做"全局摘要重写"或者"全量索引重建",赶紧改。这是 O(M) → O(log N) 的本质区别。
-
多视角组织同一份数据。entity / scene / session 三视图在 LongMemEval 上的效果让我意识到,单一组织维度的记忆系统是在自废武功。哪怕只多一个视图,召回效果都能上一个台阶。
-
embedding 检索 + 偶尔 LLM browse 是个 sweet spot。MemForest (emb) 模式 2.19 秒、78.4% 准确率,已经是个非常实用的产品级配置。LLM browse 慢一倍换 1.4 个点不一定划算。
-
dirty 标记 + 延迟批量刷新是个万能技巧。这个思路在数据库、文件系统里用了几十年,搬到 Agent 记忆里同样好使。任何"边读边算"的场景都可以这么改造。
收尾
我蛮喜欢这篇 paper 的姿态——它没有去比谁的 prompt 更花哨、谁的"智能体认知架构"概念更宏大,而是老老实实把问题降维成了一个"写优化的时序数据管理问题",然后用数据库领域的成熟思想把它做掉了。
Agent 记忆这个方向到现在还在概念漫天飞的阶段,能看到一篇愿意把脏活做扎实的工作,还是挺珍贵的。如果你也在被长程 Agent 的"用着用着就慢死"折磨,这篇值得花一个下午认真读一下。
至于 MemForest 会不会成为下一代 Agent 记忆的事实标准——我觉得它的"森林 + 分层时序索引"框架大概率会被吸收,但具体实现细节(k=16、b=2、三视图)每家肯定会按自己场景再调一遍。这就跟 LSM-Tree 的故事一样,思想是普适的,参数是要调的。
觉得有启发的话,欢迎点赞、在看、转发。跟进最新 AI 前沿,关注我