WMX · 随记
·AI· 6 分钟阅读

别只看回答顺不顺:给检索系统做一张评估表

从 Recall@k 和 MRR 开始,将检索质量、回答依据、耗时与成本分开观察。

检索评估示意:准备独立测试集,测量 Recall@k 与 MRR,再审查回答和引用。
检索评估示意:准备独立测试集,测量 Recall@k 与 MRR,再审查回答和引用。 点击图片查看大图 ↗

一个答案写得很流畅,可能引用了错误版本的文档;一个答案措辞普通,却完整覆盖了关键步骤。评估 AI 应用时,语言风格只是其中一部分,检索、证据和业务可用性需要各自的检查。

先准备一组能复核的问题

每个问题至少记录相关资料的 ID 和判断依据。问题应该覆盖常见用法、相似概念、过期资料、无答案情况和权限边界。开发集用于调参,测试集用于最终评估,不能一边看测试失败一边无限调整后再把它当作独立结果。

两个简单指标,各自回答一个问题

Recall@k 衡量已标注的相关资料有多少出现在前 k 个结果中。MRR(Mean Reciprocal Rank)关注第一个相关结果的位置:排第一记 1,排第二记 1/2,没有找到记 0,再对查询取平均。两者都不能单独证明最终答案正确。

Python22 行 · 可横向滚动
def recall_at_k(ranked, relevant, k):
    if k <= 0 or not relevant:
        raise ValueError("positive k and non-empty relevance labels required")
    return len(set(ranked[:k]) & relevant) / len(relevant)

def reciprocal_rank_at_k(ranked, relevant, k):
    if k <= 0 or not relevant:
        raise ValueError("positive k and non-empty relevance labels required")
    for rank, document in enumerate(ranked[:k], start=1):
        if document in relevant:
            return 1.0 / rank
    return 0.0

cases = [
    (["a", "b", "c"], {"b", "c"}),
    (["x", "a", "z"], {"a"}),
]
k = 2
recall = sum(recall_at_k(r, labels, k) for r, labels in cases) / len(cases)
mrr = sum(reciprocal_rank_at_k(r, labels, k) for r, labels in cases) / len(cases)
print(f"Recall@{k}: {recall:.2f}")  # 0.75
print(f"MRR@{k}: {mrr:.2f}")       # 0.50
上面的结果来自两条人为构造的样本,只用于演示计算,不能代表任何模型或服务的实际质量。这里对每条查询的指标做等权平均。

无答案问题要单独看

样例函数要求相关集合非空。真正的知识库也应该包含“资料中没有答案”的问题,这类查询需要单独评估错误回答率、错误检索率和拒答质量,不宜用一个人为定义的 Recall 值混在有答案的问题里。

把一张大分数拆成诊断表

层次观察内容常见问题
检索Recall@k、MRR、过滤结果漏资料、排错序、权限过滤失败
上下文相关片段占比、截断位置噪声太多、关键段落未进入预算
回答正确性、引用支持度、拒答编造步骤、引用不支持结论
运行延迟分位数、错误率、成本尾延迟过高、重试放大负载

让比较条件保持一致

保存语料版本、模型配置、切分参数和评估集版本。对同一组查询比较两个方案,并回看指标发生变化的具体样本。不要只挑选改善的例子;指标下降或新出现的失败,往往最能说明系统的边界。

自动评审可以辅助大规模筛查,但评审模型本身也可能偏向文风、受上下文影响或给出不稳定判断。关键业务仍需要人工抽查和可重现的证据。

继续阅读

← 返回文章归档