RAG evaluation

通过 minScore 解决召回准确率低的问题

现象 部分 Query 即便经过查询改写、混合检索(KNN + 全文)、BGE RERANKER 重排序,仍会把语义相关度极低的分片喂给 LLM。不仅可能出现错误回答,还会导致召回准确率降低。 比如我们在测试的时候发现,经过重排序后…

TL;DR

现象 部分 Query 即便经过查询改写、混合检索(KNN + 全文)、BGE RERANKER 重排序,仍会把语义相关度极低的分片喂给 LLM。不仅可能出现错误回答,还会导致召回准确率降低。 比如我们在测试的时候发现,经过重排序后…

现象

部分 Query 即便经过查询改写、混合检索(KNN + 全文)、BGE-RERANKER 重排序,仍会把语义相关度极低的分片喂给 LLM。不仅可能出现错误回答,还会导致召回准确率降低。 比如我们在测试的时候发现,经过重排序后有分数小于0的上下文也会保留下来。 原因是因为我们只设置了maxResult,这使得KnowEngineReRankingContentAggregator 默认仅按 maxResults 截断,不会按分数过滤。

KnowEngineReRankingContentAggregator.builder()
        .scoringModel(scoringModel)
        .maxResults(5)
        .querySelector(queryToContents -> queryToContents.keySet().iterator().next())
        .build()

也就是说,原方案li里 Reranker 的精排能力只用了一半:知道哪些分片更相关,但不知道哪些分片"已经差到不该用"。

修复方案

在 KnowEngineReRankingContentAggregator 构建时,显式传入 minScore(0.6) —— 这里的 minScore 作用于 BGE-RERANKER 的输出分数,是真正的语义相关度:

ContentAggregator


        processCallback
)

阈值选取依据

BGE-RERANKER-v2-m3 在 RAG 场景下的分数语义大致如下(经过 sigmoid 归一化): | Rerank 分数区间 | 语义相关度 | 是否纳入上下文 | | --- | --- | --- | | 0.8 | 强相关,几乎可直接当作答案出处 | ✅ | | 0.6 ~ 0.8 | 相关,包含可用信息 | ✅ | | 0.4 ~ 0.6 | 弱相关,可能噪声 | ❌ | | < 0.4 | 几乎无关 | ❌ |

minScore = 0.6 是经验值,对应 "至少包含可用信息" 这条线,既能滤掉绝大部分噪声,又不会过度截断(实测命中率仍能维持 maxResults 上限附近)。后续可基于业务侧 BadCase 反馈做动态调整。

与 ES minScore 的协同

做了以上优化后,我们最终形成"两道阈值"的过滤管道:

原始数据
   ↓
[ES KNN minScore=0.5]   粗筛:剔除向量空间明显不相关的分片
   ↓
[ES 全文检索 + 混合]      召回:保证召回率
   ↓
[BGE-RERANKER 精排]      精排:基于 cross-encoder 语义打分
   ↓
[Aggregator minScore=0.6]  精筛:基于精排分数过滤低相关度
   ↓
[maxResults=5]           截断:控制 LLM 上下文长度
   ↓
进入 LLM 生成

这是典型的 粗筛 → 精排 → 精筛 三段式漏斗: - 粗筛(ES)追求召回率,阈值松; - 精排(Reranker)追求排序质量; - 精筛(Aggregator minScore)追求最终上下文质量,阈值严。

版本提示

模型、框架与接口会持续变化。涉及版本号、参数与生产配置时,请在实践前对照对应官方文档。

LLMentor系统化学习大模型应用工程

内容来自个人课程知识库备份,并经过结构化整理。技术版本持续演进,生产使用前请结合官方文档验证。