☰
RAG 排序验收:NDCG 的理想分母,不能只用已经召回的文档
2026/10/25 16:12:04 网站建设 项目流程

两个检索器返回相同的文档,顺序不同,用户的阅读负担就可能不同。MRR关心第一条相关结果出现在哪里,NDCG允许用分级相关性衡量排序;但一个实现细节会让结果看起来过于漂亮:只把已召回的文档排序,充当理想结果。

先固定标注全集和增益定义

scikit-learn对NDCG的定义是将按预测顺序排列的真实相关分数折扣求和,再除以最佳可能排序的得分。使用哪个增益函数、截断到几位、如何处理并列分数,都需要固定。指标定义

本文明确采用指数增益(2^rel-1)与log2(rank+1)折扣,和直接线性相关分数的实现不能混报。教学标注把d1、d2、d3分成3、2、1级;d4为0级。理想分母来自这份标注,而不是某个检索器碰巧返回的子集。

图中A把3级相关放第一位,B把无关文档放第一位。若把rel>=2定义为“相关”,两者首个相关位置分别为1和2。这个阈值只属于本例;不能把它宣称为所有业务的行业标准。

一个故意漏掉最佳文档的反例

下面只用标准库。它去除重复ID,并对缺失的相关文档保留理想分母。最后一条断言说明:返回一篇低相关文档,不应该因为它是候选里最好的就得到满分。

from math import log2 qrels = {"d1": 3, "d2": 2, "d3": 1, "d4": 0} def dcg(grades): return sum((2 ** r - 1) / log2(i + 2) for i, r in enumerate(grades)) def ndcg(ids, k): unique = list(dict.fromkeys(ids))[:k] actual = dcg([qrels.get(d, 0) for d in unique]) ideal = dcg(sorted(qrels.values(), reverse=True)[:k]) return actual / ideal if ideal else 0.0 def rr(ids): return next((1 / i for i, d in enumerate(dict.fromkeys(ids), 1) if qrels.get(d, 0) >= 2), 0.0) a, b = ["d1", "d4", "d2", "d3"], ["d4", "d1", "d2", "d3"] assert rr(a) == 1 and rr(b) == 0.5 assert rr(["d4", "d4", "d1"]) == 0.5 assert ndcg(a, 4) > ndcg(b, 4) assert 0 < ndcg(["d3"], 3) < 1 assert ndcg(["d1", "d1"], 2) == ndcg(["d1"], 2) print("ranking invariants passed", round(ndcg(a, 4), 4), round(ndcg(b, 4), 4))

遇到未标注文档时,示例把它的增益暂记为0;正式评估应区分“标为不相关”与“尚未判断”,并补充判断池或披露标注覆盖。否则检索到新好文档的系统可能被不公平惩罚。

报告要允许定位失败

切片为什么单独报
精确制度问答排名第一条的权威性重要
多文档比较单一相关文档不足以支撑答案
最新政策必须核对生效与废止关系
无答案问题应检查拒答,不能强求高召回
不同租户/岗位权限范围本来不同

GitHub在10月21日的测试质量工作流介绍中提醒,覆盖率高不意味着测试能发现错误。检索评估也一样:一个总分必须配失败样本,才知道测试有没有触及风险。工作流说明

本例验证指标算式,不运行嵌入、重排模型或在线延迟测试。上线门槛应在双方认可的数据和错误代价上确定,同时观察答案是否引用正确证据;排序分数不能替代整条RAG链路的验收。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询