Memory Backend Audit — 大白话版

完整版见 audit_memory_backends.md。这份只讲做决定要知道的事。

一句话结论

Mem0 / MemOS / Graphiti 都能用。OpenRouter 都通过,没有 deal-breaker。

GAME.md 锁定的三个评估对象都跑得起来。剩下的全是工程细节,不影响选型。

三个意外发现

  1. Zep 死了。 Zep 社区版 2025 年 4 月 deprecated。我们说的”Zep”实际是 Graphiti(pip install graphiti-core),是 Zep 团队留下来的 OSS 引擎。GAME.md 引用 [34, 36] 已经覆盖到,但写文章时要把 Graphiti 放前面。

  2. MemOS 居然有个 pref_mem 类型,叫 PreferenceTextMemory,自带 explicit_preference / implicit_preference 两类。听起来跟我们 IPaS 完美匹配——其实没用。它的分类轴是”明说 vs 没明说”,跟我们的 4-context(work/personal × internal/external)正交。要适配反而要打。

  3. MemOS 的 search() 签名压根不接受 metadata filter。 这是 C5 gap 最干净的源码证据。GAME.md 的 H1 假设(“三个框架 CS 都低”)直接被这一行签名背书——它根本没这个能力。

三个 backend,一句话定位

  • Mem0:vector + 可选 graph。pip install mem0ai,Qdrant 默认本地。最轻、API 最齐。Reset 有坑(graph 模式下 reset() 不清图谱 #3040),所以 v1 别开 graph 模式。
  • MemOS:tree + memcube。Server 模式要 Neo4j+Qdrant+Redis,太重;用 in-process MOS 就行。Snapshot 最强——MemCube.dump(dir) / load(dir) / init_from_dir(dir) 是真原语。
  • Graphiti:temporal KG。pip install graphiti-coregroup_id 是 first-class 参数,context 隔离最干净(把 group_id 设成 {user}_{context} 就完了)。但没有 delete_group / reset——重置只能 drop 整个数据库。用 Kuzu 后端(文件式,rm -rf 即重置)能解决。

五个约束逐项谁赢

谁最强备注
C1 OpenRouter三个都源码层确认 base_url 可改
C2 用户隔离Graphiti group_id 概念最干净;MemOS 物理分目录最强
C3 Reset/SnapshotMemOS唯一有 dump/load 原语
C4 Trace 可观测Graphiti唯一内置 tracer slot(OTel 风)
C5 Context 检索Graphiti(但都不行)group_ids filter 是 native;但仍是硬分区,不是软条件——这正是 benchmark 要暴露的 gap

共同的坑(都得处理)

  1. Embeddings 也走 OpenRouter,不用改代码。 OpenRouter 现在有 POST /api/v1/embeddings(OpenAI 兼容)。Mem0 / MemOS / Graphiti 三个 backend 的 embedder 源码都接受 base_url 参数。只要把 embedder 的 base_url 指到 https://openrouter.ai/api/v1,model id 用 openai/text-embedding-3-small 这种 provider/model 形式即可。本地 HF embedder 当备选。
  2. Trace observability 都要自己 wrap(除 Graphiti 之外)。AMemGym 的 write/read/utilization 三段诊断对接,需要在 add / search 路径上自己挂 logger。
  3. Reproducibility:三个都在写入路径调 LLM,温度调低 + OpenRouter 上 pin 模型版本。或者预抽事实自己喂 infer=False(Mem0 直接支持)。

实施建议(v1)

  • Mem0:版本要 ≥ #3928 修复后的 release;关 graph 模式;Qdrant 本地;snapshot 用目录拷贝。
  • MemOS:用 in-process MOS;MemCube.dump/load 做 checkpoint;先不上 server 模式。
  • Graphiti用 Kuzu 后端(不要 Neo4j);reset 直接 rm -rf db_dir;async API 注意 harness 适配。

已知失败模式(写论文时直接引用)

  • OP-Bench(arxiv 2601.13722)测过 Mem0 和 MemOS:所有 memory 方法 OP 分数比 BASE(无 memory)下降 26–61%,MemOS 比 RAG 还差。原因是 “memory hijacking”——检索出来的记忆在 attention 上压过了用户当前 query。
  • AMemGym(arxiv 2603.01966)测过 Mem0-G:write failure 是主要瓶颈——信息在写入抽取阶段就丢了,不是检索阶段丢的。所以我们的 trace 重点应该挂在 extractor 的输入输出。

这两条直接进 H1 / H2 的讨论,不用自己再证。