Skip to content

召回可信与可调:修复基准 seed bug + 可配置融合配方(RRF/blend/min-max)+ 信号透明 #106

Closed

Description

@heptaspirit

问题

记忆检索(召回)目前在三个点上"不可信、不可调",直接影响结果质量:

1. 自带基准无法验证召回是否正确

scripts/benchmark-recall.js 的 seed 在存种子记忆时漏传 id(store.save 于是生成 UUID),而测试用例的 expected 是按 mem_* id 精确匹配的。结果无论怎么改配置,Recall 恒为 0%。这意味着连"现状召回是什么水平"都测不出来,任何召回改动都无从验证。

2. 融合方式量纲不同、直接相加

searchMemories 在 mode=vector/hybrid 时把三路分数加权求和:原始 cos(vector)+ keyword 分数 + 归一化 IDF(BM25)。三路量纲不同、缺乏归一化基准。用户想靠切换搜索模式获得更精准排序时,这个"混合"实际是"把不同尺度的分数硬加",排序可信度存疑。

3. 结果不说来源,无法诊断

默认 mode=auto 时 keyword 优先、vector/bm25 只填剩余空位。结果对象虽带 source/score,但没有各路的原始信号。想判断"这条结果为什么排前面"(是关键字命中、语义相近、还是 BM25 命中)没有数据支撑。

提议的改善

  • recallFusion: enum [blend|rrf|minmax],默认 blend(沿用现状逻辑,零行为变更)
    • blend:现加权加和(保持)
    • rrf:Reciprocal Rank Fusion(k=60),对各路排名做加权汇聚,天然兼容不同量纲
    • minmax:各源归一化到 [0,1] 后再加权,修量纲问题
  • signalTransparency: 默认 false;开启后每条结果带 signals{keyword,vector,bm25,final},便于诊断来源
  • 两者入 feature-flag 白名单,设置面板可启停
  • benchmark 修复 seed + 扩种子库 + runFusionBenchmark() 做 blend/rrf/minmax A/B

验证

  • 基准修复:legacy Recall@5 0%(bug)→ 83.3%,fused 100%
  • 三方 A/B:blend=rrf=minmax 在玩具集(12 条记忆、topK=5)均 Recall@5 100%、MRR 0.917——toy 数据量纲接近、区分度不足;配方级差异需在更真的语义数据集上验证
  • 测试全绿,npm run sync 后 src/lib 一致

几个想请你定的点

  1. RRF 的 k=60 是否合适?min-max 是否要每路独立归一化窗口?
  2. signalTransparency 默认关(作为调试观测)是否合适,还是要随版本默认开?
  3. signals 字段命名(keyword/vector/bm25)是否符合预期观察维度?

Activity

  1. changed the title [-]召回可测量可裁决:fix benchmark seed bug + 可配置融合配方(RRF/blend/min-max) + 信号透明[/-] [+]召回可信与可调:修复基准 seed bug + 可配置融合配方(RRF/blend/min-max)+ 信号透明[/+] on Sep 9, 2026
  2. Anans-Amarre commented on Sep 9, 2026

    @Anans-Amarre
    Collaborator

    已合并(4b5583c,PR #107),对应你提出的三个待定点逐条回复:

    1. RRF 的 k=60 与 min-max 归一化窗口

    k=60 是 RRF 的标准参数(Cornack et al. 原文即 60),在 rank 尺度下对 top 命中的加权合理,保留。min-max 采用每路独立归一化窗口(keyword / vector / BM25 各自 min-max 到 [0,1] 再加权),这也是当前实现——三路量纲本来不同(raw cos vs keyword score vs IDF),独立窗口正是修量纲错配的用意,不做全局窗口。若后续真实数据暴露某一路分数分布异常(如 vector 全在 0.9+ 导致区分度被压平),可再加每路分数段 clip 或分位数归一化,届时开 issue 跟进。

    2. signalTransparency 默认关

    同意默认关。它是调试观测面,默认开会给每条返回行带 signals 对象增加 payload,且当前无消费方;面板可启停已足够。等有前端可视化来源的消费方(或用户报告召回问题时)再考虑随版本默认开。

    3. signals 字段命名

    keyword/vector/bm25 与召回三路的既有 source 命名一致(source: "keyword" | "vector" | "bm25"),观察维度对齐,保留。final 为融合后总分,命名也直观。

    结论:三处设计均维持 PR 实现。配方级 A/B(rrf/minmax vs blend)在 toy 集无法区分,欢迎后续用真实语义数据集带数据来验证——若有区分度更好的评测集,直接开 issue 或 PR 到 scripts/benchmark-recall.js 扩充即可。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions