Files
memind/docs/architecture/memfuse-bench-baseline.md
T
john 908db04b67 Document Experience schema and JKRiver read-only references.
Map Mi-Memory Structure/Expansion into h5_experience V1 fields and record JKRiver Sleep design lessons under AGPL constraints, plus post-fix MemFuseBench numbers.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-02 10:04:44 +08:00

147 lines
9.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# MemFuseBench 检索基线(Memory V2
日期: 2026-09-02
状态: 已落地测量工具 + 首份基线。**不改动任何生产运行时路径**,纯离线评测。
## 0. 结论
在 MemFuseBench 的 357 个证据锚定问题、7823 条来源标注事件上跑现网 pgvector 检索排序链路,得到:
| 指标 | k=5 | k=20 | k=50 |
|---|---|---|---|
| 候选召回 candidateRecall | 36.6% | 36.6% | 36.6% |
| 最终召回 recall@k | 6.8% | 13.5% | 22.5% |
| **排序丢失 rankingLoss** | **29.8%** | **23.1%** | **14.2%** |
| 至少命中一条 hitAny@k | 21.8% | 41.7% | 64.4% |
| 清单覆盖 checklistCoverage | 7.8% | 16.8% | 28.3% |
| MRR | 0.135 | 0.153 | 0.160 |
| 干扰项占比 distractorRate | 8.5% | 10.8% | 12.6% |
两个可操作结论:
1. **天花板在候选生成,不在 k。** candidateRecall 恒为 36.6%,与 k 无关——超过 63% 的证据从未进入候选池,再怎么调排序或放大 k 都拿不回来。
2. **进了候选池的证据,排序又丢掉了一大半。** k=20 时候选池已包含 36.6% 的证据,最终只留下 13.5%rankingLoss 23.1 个百分点。即使 k=50(在约 200 条候选里返回 50 条),仍丢 14.2 个百分点。MRR 从 k=5 到 k=50 只从 0.135 涨到 0.160,说明列表头部的质量与 k 无关地差。
按维度看,`multi_source_conflict_arbitration` 明显最好(候选 71.5% / 召回 39.4%),`cross_device_information_fusion` 最差(26.5% / 6.1%)。
### keyword 路径修复后(commit `2c0d903e`k=20
只改 `fetchKeywordCandidates`:去掉 `ORDER BY updated_at DESC`,扩大 fetch cap 后按 `lexicalQueryCoverage` 排序;keyword 行携带 lexical 分。`rankHybridCandidates` 未改。
| 指标 | 修复前 | 修复后 | Δ |
|---|---|---|---|
| candidateRecall | 36.6% | **72.8%** | +36.2pp |
| recall@k | 13.5% | 13.3% | ≈0 |
| hitAny@k | 41.7% | **43.1%** | +1.4pp |
| checklistCoverage | 16.8% | 16.4% | ≈0 |
候选池扩大后 rankingLoss 相对值上升(59.5pp),但**最终 recall 几乎不变**——下一刀必须改 `rankHybridCandidates`,且需接**真实语义嵌入**验证(lexical-hash 下改非中文 vector 优先会恶化至 ~5.7% recall)。
## 1. 两个已定位的机制
### 机制一:`lexicalQueryCoverage` 是主排序键,但判别力接近随机
`memory-v2-pgvector.mjs``rankHybridCandidates``lexicalScore` 作为**第一排序键**,向量分只在 lexical 分相同时才起作用。而 `lexicalQueryCoverage` 是字符 2-gram 覆盖率。全量 357 题实测:
- gold 事件平均 coverage`0.5366`
- 非 gold 平均 coverage`0.4853`
- gold 高于语料中位数的比例:`64.5%`(随机为 50%
也就是一个只比随机好 14.5 个百分点的弱信号,被用作压倒性的主排序键。在英文语料上排名最高的往往是最长、bigram 最密的无关句子。
这个启发式对中文是合理的——CJK 2-gram 近似于词,判别力强;对英文退化严重,因为 `th`/`he`/`in` 这类 bigram 在任何长句里都存在。
### 机制二:keyword 回退路径按时间排序截断,不按相关性
`fetchKeywordCandidates` 的 SQL 是 `... WHERE content ILIKE ANY(...) ORDER BY updated_at DESC LIMIT n`。全量实测:
- ILIKE 能匹配到的 gold`60.4%`
-`updated_at DESC` 截断 100 条后存活的 gold`14.2%`
- 至少存活一条 gold 的问题占比:`32.5%`
一次纯粹由"按时间截断"造成的 46 个百分点损失。语料里匹配关键词的事件一旦多于 limit,这条路召回的就是"最新的匹配"而不是"最相关的匹配"。
## 2. 必须一起读的三条限制
不要把上面的绝对数字当成生产召回率。
1. **默认嵌入是 `lexical-hash`,不是语义嵌入。** 它是哈希词袋 + L2 归一化的确定性离线替身,cosine 近似词面重叠。报告里 `embeddingMode` 会标出来。机制一和机制二与嵌入无关(都在 lexical / keyword 路径上),但 36.6% 这个候选天花板里有一部分要归因于替身嵌入弱。用 `--embedding-module` 接真实嵌入后才能给向量路径定论。
2. **语料是英文,而 lexical 层是按中文调的。** 见机制一。这既是限制也是发现:一旦 Memind 要处理非中文内容,这条排序键就失效。
3. **语料粒度比现网粗。** MemFuseBench 的语料是事件级(单场景 936–1886 条原始事件),而现网 `memory_embeddings` 存的是已经筛过的用户记忆,条数少得多。所以这份基线衡量的是"如果把原始事件流直接灌进现有检索层会怎样"——正好是 Event Kernel 方向会产生的形态。
## 3. 数据集与授权
**数据集不入库。** 它在仓库外,通过 `MEMFUSE_BENCH_DATASET``--dataset` 指定;缺失时所有入口返回 `{ available: false, reason }`CLI 打印 skip 并 exit 0`--strict` 才 exit 1)。CI 无需数据集即可全绿。
```bash
git clone https://github.com/Darwin-Agent/Mi-Memory ~/Project/mi-memory
```
默认路径 `~/Project/mi-memory/MemFuse/MemFuseBench/memfusebench_dataset.json`6.2MB)。
| 项目 | 授权 | 本仓库可以做什么 |
|---|---|---|
| Mi-Memory / MemFuseBench | MITDarwin Agent Team, Xiaomi | 可自由使用数据集与论文思想 |
| JKRiver / Riverse | **AGPL-3.0 或商业双授权** | **只做架构级参考,禁止移植代码** |
JKRiver 的 `LICENSE` 明确把"集成进专有产品"和"作为商业 SaaS 提供而不开源修改"列为需要单独商业授权的场景。Memind 是带计费的商业 SaaSAGPL 的网络 copyleft 正好命中。因此:
- 允许:借鉴设计决策(如整条流水线单事务 + 末步落 processed 水位的 at-least-once 幂等)、参考反面经验(`migrations/008_drop_hypotheses.sql` 记录了 hypotheses 表建后即废,被 `layer='suspected'/'confirmed'` + supersedes 取代)。
- 禁止:把 `agent/sleep/*.py`(含 `_maturity.py` 的分层衰减表、`disputes.py` 的争议解决)逐行翻译进 `memory-v2-lifecycle.mjs`。取得商业授权前不做。
Mi-Memory 仓库本身**没有代码**,只有论文 PDF、项目页和图;MemStack / MemSense / D²ACCI / E²MEND / LiteMem 均无参考实现。唯一可直接使用的产物就是 MemFuseBench 数据集。
## 4. 用法
```bash
# 全量 357 题,约 3.5s
npm run bench:memory-v2-memfuse
# 单场景 / 单维度 / 冒烟
node scripts/run-memory-v2-memfuse-bench.mjs --scenario sc1 --limit 20
node scripts/run-memory-v2-memfuse-bench.mjs --dimension multi_source_conflict_arbitration
node scripts/run-memory-v2-memfuse-bench.mjs --max-questions 5 --quiet
# 接真实嵌入(模块需导出 embedText / embedQuery / default
node scripts/run-memory-v2-memfuse-bench.mjs --embedding-module ./scripts/my-embedder.mjs
# 事件文本前置 "[device · location]" 来源标签
node scripts/run-memory-v2-memfuse-bench.mjs --source-tags
# 落 JSON 报告
node scripts/run-memory-v2-memfuse-bench.mjs --out .release-gate/memfuse.json
```
`--source-tags` 实测把候选召回从 36.6% 抬到 38.2%,但最终召回不变(13.5%),说明当前排序器吃不到 provenance 前缀带来的信息。
单测(不依赖外部数据集):
```bash
npm run verify:memory-v2-memfuse-bench
```
## 5. 指标定义
- `candidateRecall` — 证据事件进入候选池(向量 top-N ∪ 最近 N ∪ keyword 匹配)的比例。**这是排序无关的天花板。**
- `recall@k` — 证据事件出现在最终 top-k 的比例。
- `rankingLoss` = `candidateRecall - recall@k`。大于 0 表示证据已被检索到但被排序丢弃。**这是决定"该修检索还是该修排序"的关键拆分**,对应 Mi-Memory 讲的 diagnostic trace。
- `hitAny@k` — 至少召回一条证据的问题占比。
- `checklistCoverage``answer_checklist` 中每个 point 至少召回一条其 `source_events` 的比例。这是最接近 MemFuse 论文自身评分(answer-checklist coverage)的检索侧代理,无需 LLM 评审。
- `distractorRate` — top-k 中 `source``noise` / `adversarial` 的占比。这些事件按数据集构造永远不属于任何答案的证据集。
## 6. 这份基线解锁了什么
`memory-v2-lifecycle.mjs``promote` / `compact` / `reflect` / decay 目前 flag 全关、`reflect()` 恒返回 `updated: 0`。在没有基线之前,往里面填任何算法都无法验证对错。现在有了一个 3.5 秒可重跑、357 题、能把候选损失和排序损失分开的度量,这个前置条件解除。
按 rankingLoss 的量级,优先级排序是:先修排序(`rankHybridCandidates` 的主键选择、`fetchKeywordCandidates` 的排序方式),再谈候选生成和 consolidation 算法。这两处都是几十行的局部改动,而且每一步都能用本文的表格直接对比。
## 7. 相关文件
- `memory-v2-memfuse-bench.mjs` — 数据集加载、语料/案例构建、评测与聚合
- `memory-v2-memfuse-bench.test.mjs` — 内联 fixture,19 个用例,不依赖外部数据集
- `scripts/run-memory-v2-memfuse-bench.mjs` — CLI
- `memory-v2-pgvector.mjs` — 被测的生产排序路径(`rankHybridCandidates` / `fetchKeywordCandidates` / `extractKeywordTerms`
- `docs/architecture/jkriver-sleep-reference.md` — JKRiver 只读参考(AGPL 边界)
- `docs/architecture/experience-schema-v1.md` — Mi-Memory Structure/Expansion 映射