← RAG 与知识检索 · 第 3 篇

如何评估 RAG:把检索和回答分开检查

用 Recall@k、证据支持与无答案用例定位 RAG 问题,用小数据集演示检索评估。

学完这一篇,你能做到

建立检索与回答分开的评测表,知道调参后应该回归哪些样本。

一个 RAG 答案不好,可能因为召回漏了资料、排序选错、上下文太杂,也可能是生成不忠于证据。只看最后一段文字,无法区分这些原因。

把链路分开评估,你才知道改动影响了哪一段,以及是否引入新的失败。

先测资料有没有找到

为一组查询标注可支持答案的资料 ID。Recall@k 表示前 k 个结果覆盖了多少已标注相关资料;它适合观察漏召回。

如果一个问题有多份有效资料,标注也应体现这一点。只标一个来源,可能把另一份正确证据误判成失败。还要明确按文档还是按块计算,避免混用粒度。

MRR 关注第一个相关结果的位置,适合观察排序是否让可用资料太靠后。它与 Recall@k 回答的是不同问题。

本地计算检索指标

下面使用人工构造的资料 ID。没有相关资料的问题返回空指标,随后单独评估“是否应该拒绝回答”,不把它混入召回率分母。

def retrieval_metrics(ranked, relevant, k):
    if not relevant:
        return {"recall": None, "mrr": None}
    top = ranked[:k]
    recall = len(set(top) & relevant) / len(relevant)
    first = next((i for i, doc in enumerate(top, 1) if doc in relevant), None)
    return {"recall": recall, "mrr": 1 / first if first else 0}

score = retrieval_metrics(["doc-c", "doc-b"], {"doc-a", "doc-b"}, k=2)
assert score == {"recall": 0.5, "mrr": 0.5}
assert retrieval_metrics(["doc-c"], set(), 1)["recall"] is None
print(score)

代码中的 MRR 限于前 k 个结果,真实报告应注明这个定义。多个查询的平均值,还要说明排除了哪些无标注或无答案样本。

再测回答是否使用了证据

检查答案中的陈述能否被提供的资料支持,引用是否指向对应位置,以及是否回答了用户真正的问题。有引用不代表引用正确。

可以借助模型辅助评分,但评分模型也可能出错。为评分规则保留人工样本,抽查不同问题类型,并观察评分是否与人类判断一致。

RAGAS 等工作将检索上下文、忠实性与回答质量拆成不同维度,适合作为设计评测表的参考,而不是一个不需要解释的总分。

无答案与权限用例不能少

准备资料库里没有答案的问题、资料过期的问题,以及用户无权访问的问题。期望结果可能是解释资料不足、询问澄清或停止访问,而不是生成一个完整长答案。

资料权限变动后,还应检查旧缓存和已保存的检索结果。权限正确不能只发生在首次建立索引时。

下一步

固定一小批查询,分别记录召回、排序、证据支持与最终回答。每次只改变一个关键变量,例如块大小或排序方式。

先检查失败类型,再决定改哪个组件。把真实发现的失败补进回归集,而不是只增加更多成功样本。

资料来源与延伸阅读

资料核验:2026-11-10。本文为原创工程讲解,教学示例不代表线上实测。