Skip to main content

RAGAS五个指标全解读

RAGAS 跑通了,终端里出现了 5 个 0~1 的浮点数。faithfulness 0.85、answer_correctness 0.69——好还是不好?0.69 比上次的 0.72 低了 3 个点,是真退化还是随机波动?

要回答这些问题,得先搞清楚这些数字是怎么算出来的。

这篇把 5 个指标的算法拆透。每个指标讲清楚算法步骤,配一个比特严选的手算例子,让数字有体感。最后用三组配对读法告诉你怎么根据指标组合定位问题——单看某个指标的高低只有一半信息,组合起来看才能精准归因。

总览:5 个指标的坐标系

先建一个全局认知,后面每一节展开一行:

指标比较对象算法核心不达标第一反应
faithfulness生成response vs contexts拆 response 的 claims → judge 判能否由 contexts 推出prompt 没限定知识来源 / 模型用预训练知识补了 contexts 里没有的内容
answer_relevancy生成response vs user_input从 response 反向生成问题 → 与原问题算余弦相似度回答跑题 / 啰嗦 / 答非所问
answer_correctness生成response vs reference0.75 × claim F1 + 0.25 × embedding similarity端到端答案差,综合性信号
context_precision检索contexts + user_input vs referencejudge 逐个 chunk 判有用没用 + Average Precision 排序得分rerank 没生效 / 过滤太宽 / 噪声 chunk 靠前
context_recall检索contexts vs reference拆 reference 的 statements → judge 判能否由 contexts 覆盖chunk 切太细 / 检索策略漏 / 知识库缺内容

版本说明:以下算法描述适用于 RAGAS 0.1.x ~ 0.4.x,核心计算逻辑跨版本未变。版本间的差异主要在 API 层面:0.2+ 将字段名从 question/answer/contexts/ground_truth 改为 user_input/response/retrieved_contexts/reference;对 context_precision 和 context_recall 新增了 NonLLM、ID-based 等变体(本文描述的是默认的 LLM-based 版本)。

五个指标的算法详解

1. faithfulness:回答里的话有据可查吗

faithfulness 是 5 个指标里最核心的一个——它检测幻觉。算法分两步。

1.1 Step 1:拆 claims

RAGAS 调 judge 模型,把 response 拆成一组原子级事实声明(atomic claims)。每个 claim 是一条独立的、可验证的事实陈述。

什么叫原子级:拆到不能再拆、只包含一个可验证事实的粒度。一个好的 claim 应该可以独立判定真假,不依赖其他 claim 的上下文。

用一个例子感受粒度:

原始句子拆出的原子级 claims
AirPods Pro 2 标准保修 1 年,自购买之日起算① AirPods Pro 2 标准保修期为 1 年 ② 保修自购买之日起算
推荐购买 AppleCare+,延保至 3 年③ AppleCare+ 可将保修延长至 3 年

注意第二句中推荐购买是主观建议,不是事实声明,不会成为 claim;但句子里蕴含的客观事实(AppleCare+ 的延保时长)仍然会被拆出。只有可以判定对还是错的陈述才算 claim。

拿比特严选的完整例子。response = AirPods Pro 2 标准保修 1 年,自购买之日起算。如果购买 AppleCare+ 可延保至 3 年。

judge 拆出三个 claims:

  • claim 1:AirPods Pro 2 标准保修期为 1 年
  • claim 2:保修自购买之日起算
  • claim 3:购买 AppleCare+ 可延保至 3 年

1.2 Step 2:逐个判 supportable

对每个 claim,judge 判断它能否从 retrieved_contexts 推导出来。结果是二值的:supported 或 not supported。

假设 contexts 里只有一段话:“标准保修期:自购买之日起 1 年。保修范围包括非人为损坏的硬件故障。”

  • claim 1:supported(上下文明确写了保修 1 年)
  • claim 2:supported(上下文写了自购买之日起)
  • claim 3:not supported(上下文没提 AppleCare+ 延保——这是模型从预训练知识里补的)

计算:

faithfulness = supported / total = 2 / 3 ≈ 0.667

0.667 意味着回答里 1/3 的事实声明在上下文中找不到依据。claim 3 就是幻觉——模型编了一个 contexts 里没有的信息。

不达标怎么办:faithfulness 低 → 看 response 里哪些 claims 是 not supported → 如果是模型补了预训练知识 → 改 prompt 加强“只基于给定上下文回答”的约束、加兜底指令。如果 claim 本身应该被支持但 contexts 里漏了 → 问题出在检索阶段,转查 context_recall

2. answer_relevancy:回答切题吗

answer_relevancy 衡量的是回答有没有跑偏。算法的思路很巧——反向推导。

为什么不直接比 response 和 user_input 的相似度?

直觉上会觉得:直接把 response 和 user_input 都做 embedding,算余弦相似度不就行了?问题是,一个好的回答跟原始问题在词汇和句式上往往差异很大。

比如用户问“退货怎么寄回去”,好的回答是“请在订单页点击申请退货,选择上门取件或到付寄回,地址是 xxx”。这段回答跟问题的文本相似度并不高——因为回答是信息展开,不是重复问题。直接比两者的 embedding 会得到偏低的分数。

RAGAS 的思路是:如果这个回答是切题的,那从回答反推出的问题应该跟原始问题很像。这比直接比 response 和 user_input 更能捕捉语义切题——回答的信息指向了正确的问题方向。

2.1 Step 1:反向生成问题

judge 从 response 出发,反向生成 N 个问题(默认 N=3)。意思是:如果有人看到这个回答,他原本可能在问什么?

例如 response = “退款通常在 35 个工作日到账,信用卡支付可能需要 710 天。”

judge 反向生成:

  • q1:退款多久到账?
  • q2:信用卡退款需要多长时间?
  • q3:退款到账时间是多少?

2.2 Step 2:算余弦相似度

把 3 个反向问题和原始 user_input 分别做 embedding,算余弦相似度,取平均。

以下数值为简化示意,帮助理解分数高低的含义。实际分布取决于所用 embedding 模型,不同模型的相似度区间差异较大。

假设 user_input = 退货怎么寄回去?

反向问题与 user_input 的余弦相似度
q1:退款多久到账?0.55
q2:信用卡退款需要多长时间?0.50
q3:退款到账时间是多少?0.52
answer_relevancy = mean(0.55, 0.50, 0.52) = 0.523

0.523 偏低。用户问的是退货流程(怎么寄回去),模型回答了退款到账时间——跑题了。反向生成的问题跟原问题不匹配,所以分数低。

再看一个切题的例子对比:

假设 response = 您可以在订单页面点击申请退货,选择上门取件或自行寄回,地址是北京市 xxx。

judge 反向生成:

  • q1:退货怎么操作?
  • q2:退货的寄送地址是什么?
  • q3:退货流程是什么?
反向问题与 user_input 的余弦相似度
q1:退货怎么操作?0.88
q2:退货的寄送地址是什么?0.82
q3:退货流程是什么?0.86
answer_relevancy = mean(0.88, 0.82, 0.86) = 0.853

对比一下:跑题的回答 0.523,切题的回答 0.853。差距来自反向生成问题跟原问题的语义匹配程度。

关键陷阱:answer_relevancy 只看切题,不看正确性。一个事实完全错误的回答,只要看起来在回答用户的问题,relevancy 就可能很高。比如用户问“保修期多久”,模型回答“保修期 5 年”(实际 1 年),反向生成的问题会是“保修期多久”,跟原问题高度相似 → relevancy 接近 1.0,但答案是错的。所以 answer_relevancy 必须跟 faithfulnessanswer_correctness 配套看。

不达标怎么办:answer_relevancy 低 → 回答跑题了 → 先查意图识别(自建指标 intent_top1)是不是分错了 → 如果意图对,看 prompt 是不是没有聚焦用户问题 → 或者 query rewrite 把用户问题改偏了。

3. context_precision:召回里有多少是有用的,排得好不好

context_precision 衡量的是检索质量的精度面——召回的 chunk 里有用的多不多,排得靠不靠前。

3.1 Step 1:逐个 chunk 判有用没用

judge 对 retrieved_contexts 里的每个 chunk,结合 user_input 和 reference 做二值判断:这个 chunk 对正确回答用户问题有没有用。

注意这里的判断逻辑:judge 看的是这个 chunk 的信息是否有助于回答原始问题。具体来说,它参考 reference(标准答案)来判断——如果一个 chunk 包含了标准答案中涉及的信息,就算 useful。

3.2 Step 2:按 Average Precision 计算

context_precision 不是简单算有用 chunk 占比——那样就丢失了排序信息。一组 5 个 chunk 里有 2 个有用的,排在第 1、2 位跟排在第 4、5 位,对生成质量的影响差别很大。

Average Precision 的直觉是:每发现一个有用 chunk,就算一下截止到这个位置,有用的占比是多少,最后对所有有用位置的占比取平均。有用 chunk 排得越靠前,截止位置的占比就越高,最终分数越高。

具体公式:

对每个 useful chunk 在位置 k:precision@k = 截止位置 k 时有用数量 / k
最终:context_precision = 所有 useful chunk 的 precision@k 之和 / useful chunk 总数

用一个例子。用户问 AirPods Pro 2 保修期,检索回来 5 个 chunk:

位置chunk 内容摘要判定
1AirPods Pro 2 售后政策useful ✓
2扫地机器人使用手册not useful
3AirPods Pro 2 产品规格useful ✓
4电视遥控器配对说明not useful
5耳机清洁指南not useful

逐步计算:

  • 位置 1 是 useful:截止位置 1,有用 1 个,总共看了 1 个 → precision@1 = 1/1 = 1.0
  • 位置 2 是 not useful:跳过,不参与计算
  • 位置 3 是 useful:截止位置 3,有用 2 个,总共看了 3 个 → precision@3 = 2/3 ≈ 0.667
  • 位置 4、5 是 not useful:跳过
context_precision = (1.0 + 0.667) / 2 ≈ 0.833

对比感受排序的影响:如果两个 useful chunk 都排在前两位(位置 1 和 2),分数会变成:

  • precision@1 = 1/1 = 1.0

  • precision@2 = 2/2 = 1.0

  • context_precision = (1.0 + 1.0) / 2 = 1.0

如果两个 useful chunk 排在最后两位(位置 4 和 5):

  • precision@4 = 1/4 = 0.25
  • precision@5 = 2/5 = 0.40
  • context_precision = (0.25 + 0.40) / 2 = 0.325

同样是 5 个 chunk 里 2 个有用,排前面得 1.0,排后面只有 0.325——差了 3 倍。这就是为什么 context_precision 不只看有没有找到,还看排在哪。

不达标怎么办:context_precision 低 → 召回里噪声多或排序差 → 先看噪声是不是排在相关 chunk 前面 → 检查 rerank 是不是没生效,或 metadata 过滤是否太宽。只有在相关 chunk 已稳定排在前列、后面主要是冗余噪声时,才优先考虑缩小 topK;否则盲目缩小 topK 可能会进一步拉低 context_recall

4. context_recall:标准答案需要的信息找全没

context_recall 衡量的是检索质量的覆盖面——标准答案所需的信息,contexts 找到了多少。

4.1 Step 1:拆 reference 的 statements

解锁付费内容,👉 戳