RAGAS 实战:一套能跑起来的 RAG 自动评测框架

个人主页: > for_ever_love__ <(欢迎各位大佬莅临😊)
其他栏目: > 大模型开发从0到1 <
其他栏目: > iOS项目总结大全 <
其他栏目: > 我想学python了 <
其他栏目: > iOS UI <

文章目录

  • [RAGAS 实战:一套能跑起来的 RAG 自动评测框架](#RAGAS 实战:一套能跑起来的 RAG 自动评测框架)
    • [一、RAGAS 是什么](#一、RAGAS 是什么)
      • [1.1 定位](#1.1 定位)
      • [1.2 输入输出](#1.2 输入输出)
      • [1.3 指标全景](#1.3 指标全景)
    • 二、安装与第一个例子
      • [2.1 安装](#2.1 安装)
      • [2.2 完整示例](#2.2 完整示例)
      • [2.3 转成 DataFrame 细看](#2.3 转成 DataFrame 细看)
    • 三、每个指标在算什么
      • [3.1 Faithfulness(忠实度)](#3.1 Faithfulness(忠实度))
      • [3.2 Answer Relevancy(答案相关性)](#3.2 Answer Relevancy(答案相关性))
      • [3.3 Context Precision(上下文精确率)](#3.3 Context Precision(上下文精确率))
      • [3.4 Context Recall(上下文召回率)](#3.4 Context Recall(上下文召回率))
    • 四、用自定义模型跑
      • [4.1 用 LangChain 的 LLM 包装](#4.1 用 LangChain 的 LLM 包装)
      • [4.2 传入 evaluate](#4.2 传入 evaluate)
      • [4.3 embedding 也要换(Answer Relevancy 需要)](#4.3 embedding 也要换(Answer Relevancy 需要))
      • [4.4 一个重要的注意事项](#4.4 一个重要的注意事项)
    • 五、结果怎么读
      • [5.1 建立基线表](#5.1 建立基线表)
      • [5.2 不要只看平均分](#5.2 不要只看平均分)
      • [5.3 关注相对变化](#5.3 关注相对变化)
    • 六、常见坑
      • [6.1 ground_truth 写法影响巨大](#6.1 ground_truth 写法影响巨大)
      • [6.2 contexts 传错格式](#6.2 contexts 传错格式)
      • [6.3 版本兼容问题](#6.3 版本兼容问题)
      • [6.4 成本](#6.4 成本)
      • [6.5 中文场景表现下降](#6.5 中文场景表现下降)
    • 七、和其他评测方案怎么选
    • 八、一个可复制的工作流
    • 小结

RAGAS 实战:一套能跑起来的 RAG 自动评测框架

RAG 做出来之后,最现实的问题是:怎么知道它好不好? 靠人工看几条答案,很容易被"看起来挺流畅"骗过去。

RAGAS(Retrieval-Augmented Generation Assessment)是目前最常用的开源 RAG 评测框架。它的价值在于:不需要人工给每篇文档标注相关性,只靠"问题 + 答案 + 上下文 + 标准答案"就能算出一组有解释力的指标。

这一篇从实战角度讲:它有哪些指标、怎么跑起来、结果怎么读、以及它有哪些坑。


一、RAGAS 是什么

1.1 定位

RAGAS 不是一个端到端的测试平台,它是一套指标计算库。你给它数据,它返回分数。

它的核心设计思路是:用 LLM 当评判员(LLM-as-a-judge),把原本需要人工标注的环节自动化。

1.2 输入输出

最小输入(四元组):

python 复制代码
{
    "question":      "用户问题",
    "answer":        "系统生成的答案",
    "contexts":      ["召回的文档1", "召回的文档2", ...],
    "ground_truth":  "标准答案"      # 部分指标需要
}

输出:一组 0~1 的分数。

1.3 指标全景

指标 需要 ground_truth 评估对象 回答什么问题
Faithfulness 否 生成 答案有没有编造?
Answer Relevancy 否 生成 答案切题吗?
Context Precision 是 检索 召回的有用吗、排序好吗?
Context Recall 是 检索 需要的信息召回了吗?
Context Entities Recall 是 检索 关键实体覆盖了吗?
Answer Similarity 是 生成 和标准答案语义像吗?
Answer Correctness 是 生成 答案对吗?(语义+事实加权)

前四个是核心,绝大多数场景够用。

关键区分:

  • 不需要 ground_truth 的指标(Faithfulness、Answer Relevancy)→ 可以在线监控真实流量
  • 需要 ground_truth 的 → 只能离线评测

这个区分很重要。很多线上系统只能跑前两个,所以离线评测集的建设不能省。


二、安装与第一个例子

2.1 安装

bash 复制代码
pip install ragas datasets

RAGAS 需要配置一个评判用的 LLM。默认用 OpenAI:

python 复制代码
import os
os.environ["OPENAI_API_KEY"] = "sk-xxx"

用其他模型(比如国内模型、本地模型)需要自定义,后面讲。

2.2 完整示例

python 复制代码
from ragas import evaluate
from ragas.metrics import (
    faithfulness,
    answer_relevancy,
    context_precision,
    context_recall,
)
from datasets import Dataset

data = {
    "question": [
        "公司差旅一线城市住宿标准是多少?",
        "超标部分怎么申请特批?",
    ],
    "answer": [
        "一线城市住宿上限为 500 元/晚。",
        "超标需提前提交特批申请,由部门负责人审批。",
    ],
    "contexts": [
        [
            "差旅标准(2023版):一线城市住宿上限 500 元/晚,二线城市 350 元/晚。",
            "差旅报销流程:提交发票 → 部门审批 → 财务复核。",
        ],
        [
            "超标部分需提前提交特批申请,由部门负责人审批后方可报销。",
            "特殊情况可事后补充说明。",
        ],
    ],
    "ground_truth": [
        "一线城市住宿上限 500 元/晚。",
        "超标需提前提交特批申请,由部门负责人审批。",
    ],
}

ds = Dataset.from_dict(data)
result = evaluate(ds, metrics=[
    faithfulness, answer_relevancy,
    context_precision, context_recall,
])

print(result)

输出大致是:

复制代码
{'faithfulness': 0.9500, 'answer_relevancy': 0.8731,
 'context_precision': 0.8333, 'context_recall': 1.0000}

2.3 转成 DataFrame 细看

python 复制代码
df = result.to_pandas()
print(df[["question", "faithfulness", "context_recall"]])

能看到每条样本的分数,找出具体哪些题拖了后腿。这比只看平均分有用得多------平均分会被大量简单题掩盖问题。


三、每个指标在算什么

3.1 Faithfulness(忠实度)

算法:把答案拆成原子陈述 → 逐条判断能否从 contexts 推出 → 被支撑数 / 总数。

python 复制代码
# 答案:"一线城市 500 元,超标需部门负责人审批。"
# 陈述1: 一线城市住宿上限 500 元     → 上下文支撑 ✓
# 陈述2: 超标需部门负责人审批        → 上下文支撑 ✓
# Faithfulness = 2/2 = 1.0

注意:它只管"照没照材料说",不管材料本身对错。详细讨论见我写的忠实度专篇。

3.2 Answer Relevancy(答案相关性)

算法(这个比较巧妙):

  1. 用答案反向生成若干个问题(假设答案是对某个问题的回答)
  2. 计算这些生成问题与原始问题的相似度
  3. 取平均

原理:如果答案切题,那么从答案反推出来的问题,应该和原问题很接近。如果答案跑题了,反推的问题也会跑偏。

python 复制代码
# 原问题:"一线城市住宿标准是多少?"
# 答案:"公司成立于 2010 年,总部在北京。"
# → 反推问题:"公司什么时候成立的?" / "公司总部在哪?"
# → 与原问题相似度很低
# → Answer Relevancy 低

优点 :不需要 ground_truth,可以在线跑。

缺点:答案很短或很长时,反推会不稳定。

3.3 Context Precision(上下文精确率)

算法:判断每篇上下文是否对得出 ground_truth 有贡献 → 按排名加权平均。

它惩罚"有用的排在后面"。详见我写的上下文精确率与召回率专篇。

3.4 Context Recall(上下文召回率)

算法:把 ground_truth 拆成陈述 → 判断每条能否从 contexts 推出 → 能推出数 / 总数。


四、用自定义模型跑

用 OpenAI 之外的模型(国内模型、本地模型),需要自己接。

4.1 用 LangChain 的 LLM 包装

python 复制代码
from ragas.llms import LangchainLLMWrapper
from langchain_openai import ChatOpenAI

# 例如接一个兼容 OpenAI 接口的中转/本地服务
judge_llm = ChatOpenAI(
    model="qwen-plus",
    openai_api_key="xxx",
    openai_api_base="https://your-endpoint/v1",
    temperature=0,
)

ragas_llm = LangchainLLMWrapper(judge_llm)

4.2 传入 evaluate

python 复制代码
from ragas import evaluate

result = evaluate(
    ds,
    metrics=[faithfulness, context_recall],
    llm=ragas_llm,
)

4.3 embedding 也要换(Answer Relevancy 需要)

python 复制代码
from ragas.embeddings import LangchainEmbeddingsWrapper
from langchain_community.embeddings import HuggingFaceEmbeddings

emb = HuggingFaceEmbeddings(model_name="BAAI/bge-small-zh-v1.5")
ragas_emb = LangchainEmbeddingsWrapper(emb)

result = evaluate(ds, metrics=[answer_relevancy],
                  llm=ragas_llm, embeddings=ragas_emb)

4.4 一个重要的注意事项

评判模型不能太弱。 用 7B 模型去评判 GPT-4 生成的答案,判定本身就不可靠。经验法则:评判模型的能力应不低于被测系统的生成模型。

如果预算有限,折中方案是:用便宜模型做相对比较(A 方案 vs B 方案),而不是看绝对分数。


五、结果怎么读

5.1 建立基线表

改动前后各跑一次,填表对比:

配置 Faithfulness Answer Relev. Ctx Precision Ctx Recall 平均延迟
基线(top_k=5,无重排) 0.72 0.81 0.48 0.66 0.9s
+ 重排 0.79 0.83 0.71 0.66 1.6s
+ 混合检索 0.80 0.84 0.68 0.83 1.7s
+ 提示词硬约束 0.91 0.85 0.68 0.83 1.7s

这样一眼能看出每个改动的收益:

  • 重排提精确率(0.48→0.71)
  • 混合检索提召回率(0.66→0.83)
  • 提示词约束提忠实度(0.72→0.91)

定位很清晰,不会瞎调。

5.2 不要只看平均分

按分数分布看:

python 复制代码
df = result.to_pandas()
print(df["faithfulness"].describe())
print("\n最差的 5 条:")
print(df.nsmallest(5, "faithfulness")[["question", "faithfulness"]])

低分的那些样本才是金矿。把它们挑出来人工看,往往能发现系统性的失败模式(比如某一类问题全都答不好)。

5.3 关注相对变化

LLM 判定有噪声,单次跑分波动 ±0.05 正常。判断改动是否有效,看变化幅度是否超过 0.05~0.1,别为 0.02 的差异纠结。


六、常见坑

6.1 ground_truth 写法影响巨大

Context Recall 会把 ground_truth 拆成陈述。如果 ground_truth 写得太啰嗦:

python 复制代码
# ❌ 糟糕
"根据《差旅管理制度》第三章第二节的规定,结合公司实际情况,一线城市的住宿标准被设定为每晚 500 元人民币。"

# ✅ 好
"一线城市住宿上限 500 元/晚。"

啰嗦的版本会拆出很多无关陈述("根据制度第三章"这种),拉低召回率,而且不稳定。

原则:ground_truth 只写事实点,不写套话。

6.2 contexts 传错格式

contexts 必须是列表的列表------每个问题对应一个文档列表:

python 复制代码
# ✅ 正确
"contexts": [["doc1", "doc2"], ["doc3", "doc4"]]

# ❌ 错误(少一层)
"contexts": ["doc1", "doc2"]

这个错误很常见,会报奇怪的错。

6.3 版本兼容问题

RAGAS 更新比较快,API 在不同版本间有变化。常见问题:

  • EvaluationDataset vs 直接传 Dataset
  • 指标导入路径变化(ragas.metrics vs ragas.metrics.critique)
  • llm= 参数的类型要求(有的版本要 wrapper,有的不要)

建议:固定版本号,写进 requirements:

复制代码
ragas==0.1.x

6.4 成本

每个样本的四个指标,大约需要 5~15 次 LLM 调用。跑 200 条样本、用 GPT-4 级别模型,成本可能在几十到上百元。

控制成本的办法:

  • 用小一点的评测集(50~100 条足够发现趋势)
  • 分层抽样:简单题少抽,难例多抽
  • 日常回归用便宜模型,关键决策时才用贵模型

6.5 中文场景表现下降

RAGAS 的提示词是英文的,中文文本的陈述拆分质量会下降------中文标点、无空格分词,都让 LLM 拆句子更困难。

缓解:

  1. 自定义提示词(RAGAS 支持传入自定义 prompt)
  2. 用中文能力强的评判模型
  3. 对中文场景,考虑自己实现简版指标(参考我写的忠实度篇)

七、和其他评测方案怎么选

方案 优点 缺点 适用
RAGAS 开箱即用、指标成体系、社区活跃 需 LLM 成本高、有噪声、中文打折 通用首选
传统 IR 指标(P@K/MRR) 便宜、可复现、无噪声 需要文档级相关性标注 有标注时
自建 LLM 评判 完全可控、可定制标准 要自己写、要自己验证可靠性 有特殊判定标准
人工评测 最可靠 贵、慢、不可规模化 关键决策、抽检复核
业务指标(点击率/解决率) 真正反映价值 滞后、干扰因素多 线上长期监控

我的建议组合:

  1. 离线:RAGAS 四指标跑评测集,用于迭代决策
  2. 在线:只跑不需要 ground_truth 的指标(Faithfulness、Answer Relevancy),抽样监控
  3. 定期:人工抽检 50 条,校验自动指标是否可信
  4. 长期:看业务指标(用户是否点了"有用"、是否转人工)

自动指标不能替代人工抽检。 它们是指向器,不是终审。


八、一个可复制的工作流

python 复制代码
# evaluate_rag.py
import json
from ragas import evaluate
from ragas.metrics import (
    faithfulness, answer_relevancy,
    context_precision, context_recall,
)
from datasets import Dataset

def load_eval_set(path):
    return json.load(open(path, encoding="utf-8"))

def collect_predictions(eval_set, pipeline):
    rows = {"question": [], "answer": [], "contexts": [], "ground_truth": []}
    for item in eval_set:
        ans, ctxs = pipeline.query(item["question"])
        rows["question"].append(item["question"])
        rows["answer"].append(ans)
        rows["contexts"].append(ctxs)
        rows["ground_truth"].append(item["ground_truth"])
    return Dataset.from_dict(rows)

def main():
    eval_set = load_eval_set("eval_set.json")
    ds = collect_predictions(eval_set, my_pipeline)

    result = evaluate(ds, metrics=[
        faithfulness, answer_relevancy,
        context_precision, context_recall,
    ])

    # 1. 打印总分
    print(result)

    # 2. 保存明细
    df = result.to_pandas()
    df.to_csv("eval_result.csv", index=False, encoding="utf-8-sig")

    # 3. 挑出最差样本
    df["min_score"] = df[[
        "faithfulness", "answer_relevancy",
        "context_precision", "context_recall"
    ]].min(axis=1)
    worst = df.nsmallest(10, "min_score")
    worst.to_csv("worst_cases.csv", index=False, encoding="utf-8-sig")
    print("\n最差 10 条已保存到 worst_cases.csv")

if __name__ == "__main__":
    main()

每次改动 pipeline 就跑一次,对比 eval_result.csv,看 worst_cases.csv 找失败模式。这个循环跑几轮,系统质量会有明显提升。


小结

  • RAGAS 是一套基于 LLM-as-judge 的 RAG 评测指标库,核心四个指标:Faithfulness、Answer Relevancy、Context Precision、Context Recall。
  • 前两个不需要 ground_truth,可以在线监控;后两个需要,只能离线评测。
  • 用法很直接:准备四元组数据 → evaluate() → 读分数。但要注意 contexts 是"列表的列表"、ground_truth 要简洁。
  • 看明细比看平均分重要。挑出最差的样本人工分析,才能发现系统性失败模式。
  • 主要坑:LLM 判定有噪声(±0.05)、成本高、中文场景陈述拆分质量下降、版本 API 不稳定(固定版本号)。
  • 它不能替代人工抽检。自动指标 + 定期人工复核才是可靠组合。

一句话:没有评测就没有优化。RAGAS 的意义不在于分数本身,而在于它让你能回答"这次改动到底有没有用"。

相关推荐
俊哥AI全栈工程师1 小时前
用 AI 重构老项目,我踩过的 5 个坑(真实项目复盘)
人工智能
七七安1 小时前
部分卷积(Partial Convolution)
人工智能
Xuantong_901 小时前
在AI时代,重新寻找「师傅」
人工智能
长弓三石1 小时前
用 JEV 决策模型接管 Agent 路由判断(一):为什么把「判断」从推理里拿出来
人工智能
晨间晓1 小时前
图片对比度够不够?用华为云码道开发 OpenCV 对比度分析工具
人工智能·opencv·华为云
ADAI_Bowen1 小时前
当AI读懂图纸:ADAI,用垂直大模型重构建筑方案的迭代逻辑
人工智能·重构
霸道流氓气质1 小时前
AI 简历制作平台:结构化输出解析、多模板渲染与 PDF 导出的 Vue3 + Spring AI 全栈实战
人工智能·spring·pdf
方方洛1 小时前
ai-agent教程-09-MCP模型上下文协议
人工智能·llm·agent
QinHsiu1 小时前
4.4%到61.1%,提升14倍:LongHarness证明证据管理比扩大窗口更有效
人工智能