测试日期:2026-08-26 · 测试对象:mem0(Qdrant)+ memory-inject v4 多路召回 + 14 天半衰期时间衰减 数据源:mem0 真实记忆库
~/.mem0(100 条,2026-08-11 ~ 2026-08-26) 复现:~/dev/memory-eval/(cases.json + run_eval.py + results.json)
记忆架构 8-26 升级到 v4:召回侧改为多路召回(Lane A 当前用户消息 + Lane B 最近 recap 主题)+ 注入分层(<recalled-memory> 块紧跟 <rules> 之后)+ 14 天半衰期时间衰减(effective = score × 0.5^(days/14))。
之前(8-19)跑过 pi-search benchmark(237 cases,测的是 SQLite FTS5 全文检索工具),但从未对记忆架构本身做过 eval。v4 上线后需要基线数据,验证"多路召回 + 衰减"这套设计到底行不行。
从 mem0 真实记忆库取 27 条有明确唯一答案的事实/偏好/事件作为 target,query 用用户口吻重写:
| 类别 | 条数 | 考察点 |
|---|---|---|
| real | 12 | 真实提问场景(最贴近使用) |
| fact | 9 | 身份/事实/决策类记忆 |
| preference | 2 | 用户偏好类 |
| paraphrase | 2 | 同义描述(不出现专名) |
| negative | 2 | 无关提问(防幻觉召回) |
mem0-cli search <query> 5(模拟 before_agent_start 单路召回)| 口径 | hit@1 | hit@3 | hit@5 | 平均延迟 |
|---|---|---|---|---|
| raw(原始分) | 44.4% | 81.5% | 88.9% | 2.44s |
| eff(衰减后重排) | 33.3% | 77.8% | 85.2% | — |
| 类别 | 条数 | hit@1 | hit@3 | hit@5 |
|---|---|---|---|---|
| real | 12 | 58.3% | 91.7% | 100% |
| fact | 9 | 44.4% | 66.7% | 77.8% |
| preference | 2 | 0% | 100% | 100% |
| paraphrase | 2 | 50% | 100% | 100% |
| negative | 2 | — | 0%(无幻觉) | 0%(无幻觉) |
| 类别 | 条数 | hit@1 | hit@3 | hit@5 |
|---|---|---|---|---|
| real | 12 | 50.0% | 83.3% | 91.7% |
| fact | 9 | 33.3% | 55.6% | 55.6% |
| preference | 2 | 0% | 100% | 100% |
| paraphrase | 2 | 50% | 100% | 100% |
query:记忆框架的失败模式是不是要重点记住,target 61853aab(score 0.55)排第 5 名外
top5 里 4 条全是 PersonaMem 失败模式同主题记忆(a440df82 0.59 / 407198eb 0.56 / b40ff791 0.56 / 53dd55ca 0.56),把目标挤出去。
根因:8-26 同一天反复写入 5 条几乎一样的记忆("Mem0 失败模式要记住"被 autosediment 在不同轮次反复沉淀)。mem0 写入侧无相似度去重——同主题多轮写入本该合并,结果各占一条,召回时互相稀释。
query:我是什么学校的,target 5d4f0347(墨尔本大学,8-14 记,12 天前,raw score 0.29)
原始分本来就低(0.29),衰减后 0.16 → 排第 5 名外。
query:我现在在哪个公司实习,target f8c0f3e1(Tezign,8-25 记,1 天前,raw 0.47)—— 未进 top5,被 1 天前的 4 条面试记忆(MemOS/石墨/fAIshion)淹没
根因:14 天半衰期对"偏好/近期事件"合理,对"身份事实"是错的。学校、当前公司这类长期稳定事实不该随天数降温——它们是最该被记住的东西。衰减公式没有区分记忆类型。
query:我九月初要去哪上班,target 31f88a72(MaxInsights 入职,8-26 记,score 0.60)—— 完全没进 top5
而直接搜 MaxInsights 入职 时 31f88a72 排第 2(0.60)。"上班/入职/去哪"这些口语化表达与英文记忆文本("join maxinsights around early September")embedding 匹配弱。
根因:embedding 对中英混合 + 口语化的语义桥接不足。这正是 PersonaMem-v3 指出的"需要的信息没被检索到"失败模式在真实系统里的复现——而且 8-26 刚把这条失败模式写进记忆,同一天自己就踩了。
我九月初要去哪上班 raw 没命中但 eff 也没命中——因为 12 天前的 MaxInsights 早期探索条目(de8fb764,0.61)被衰减到 0.34 排后,而 8-26 的入职条目(31f88a72,0.60)又因口语化没召回。这是 4.3 的叠加效应,不是衰减的问题——衰减本身在 real 类只把 hit@3 从 91.7% 微降到 83.3%,代价可控。
fact / preference / event),召回时按类型套不同半衰期。改动在 memory-inject v4 的 effectiveScore 函数。| 口径 | pi-search(FTS) | mem0 v4(语义) |
|---|---|---|
| real hit@3 | 77.8% | 91.7% |
| real hit@5 | 88.9% | 100% |
| 延迟 | 51ms / 1.22s(expand) | 2.44s |
语义召回在真实提问场景全面胜出(hit@3 +14 个点),但延迟高 2 个数量级(mem0 search 每次 ~2.4s,含 embedding + LLM 重写)。对 before_agent_start 注入场景 2.4s 可接受(启动时跑一次);但对交互式即时检索不可接受——这支持了"memory 做注入、session search 做即时检索"的分工。
cd ~/dev/memory-eval
python3 run_eval.py # 27 case × search,输出 results.json + 汇总
# 产物:cases.json(27 case 定义+ground truth)、run_eval.py(runner)、results.json(结果)
# 新增 case:往 cases.json 的 cases 里加 {query, target, cat, note},target 填 mem0 记忆 id 前缀(前 8 位)
# 注意:target 必须先在 mem0 里确认存在(~/bin/mem0-cli.py search "<专名>" 验证)
报告生成:memory-eval v1 · 2026-08-26 · 由 mem0 召回质量首轮评测产出