Mindket

如何评估 RAG:检索指标、忠实度与小型测试集

黑色横幅,标题是“RAG 实战”,下面是“向量、分块、检索与评估”。

评估 RAG 要分成两半来做。用上下文召回率和上下文精确率衡量检索,用忠实度和答案相关性衡量答案。准备一小组带参考答案的问题,让流水线逐个回答,保存检索到的块和回答,再交给 Ragas 计算指标。每次只改一个设置,再比较分数。

本节内容

  • 分清检索失败和生成失败。
  • 用 Ragas 需要的四个字段建一个小型评估集。
  • 算出上下文召回率、上下文精确率、忠实度和答案相关性,并读懂每个指标在数什么。
  • 知道 LLM 评委在哪里需要检查,并能从你的文档生成更多测试问题。
全部课程
本页目录
  1. 开始之前
  2. 把检索和答案分开测
  3. 建一个小型评估集
  4. 给检索打分:召回率和精确率
  5. 给答案打分:忠实度和相关性
  6. 读懂分数,选一个杠杆
  7. 评委什么时候需要检查
  8. 生成更多测试问题
  9. Shreya Shankar 谈怎样检查评委,Hamel Husain 谈通用指标
  10. 常见错误
  11. 自己试一试
  12. 下一课
  13. 自测一下
  14. 常见问题
  15. 资料来源

开始之前

你需要 Python 3,一条能返回检索到的块和所给答案的流水线(比如第 1 课里的那条),以及评委模型的 API 密钥。用 pip install ragas 安装 Ragas。Ragas 页面里的示例调用的是 OpenAI,测试集指南还展示了怎样用 LangchainLLMWrapper 接入 AWS、Google Cloud、Azure 或其他任何 LangChain 支持的服务商。

有一点要说明版本。本课依据的 Ragas 页面日期是 2025 年 12 月 9 日,上面仍写着旧的 ragas.metrics 类(比如 LLMContextRecall)属于旧版 API,“将在 0.4 版弃用”,并在 1.0 版移除。

可是 PyPI 显示,0.4.0 早在 2025 年 12 月 3 日就发布了。到 2026 年 11 月 5 日,最新版是 2026 年 1 月 13 日发布的 0.4.3。下面的指标代码用的是文档推荐新项目使用的 ragas.metrics.collections API。测试时请固定版本,比如 pip install ragas==0.4.3,免得一次升级让前后两次运行的分数没法比。

把检索和答案分开测

答错有两种可能的原因:检索器没找到那段内容,或者模型忽略了它,或者把它改歪了。Ragas 的指标就是沿着这条线划分的,所以一个分数能告诉你该修哪一半。上下文召回率和上下文精确率评的是检索到的块,忠实度和答案相关性评的是回答,噪声敏感度则两边都看。

名称和定义出自 Ragas 的各个指标页面,例如上下文召回率和噪声敏感度。分数通常在 0 到 1 之间。
指标回答什么问题需要的字段越高越好吗
上下文召回率检索到的块是否支持参考答案里的每一条陈述?user_input, retrieved_contexts, reference越高越好
上下文精确率相关的块是否排在不相关的块前面?user_input, retrieved_contexts, reference越高越好
忠实度检索到的上下文是否支持回答里的每一条陈述?user_input, retrieved_contexts, response越高越好
答案相关性回答是否切中了问题?user_input, response越高越好
噪声敏感度回答多常出现参考答案不支持的陈述?user_input, retrieved_contexts, response, reference越低越好

建一个小型评估集

Ragas 对每个问题要四个字段:user_input 是问题,retrieved_contexts 是检索器返回的块,response 是模型给出的答案,reference 是标准答案。它的入门指南的做法是让每个查询跑一遍流水线,再把各行载入 EvaluationDataset。指南说参考答案是可选的,但上面有三个指标要用到它。

Anthropic 的指南在建评估时的建议同样适用:贴近任务的真实分布,加入边界情况,比如无关或不存在的输入、特别长的输入,以及连人都很难达成一致的模糊情况,并且宁可要更多可自动评分的问题,也不要少量人工评分的问题。

from ragas import EvaluationDataset

# sample_queries and expected_responses: your own questions and reference answers
dataset = []

for question, reference in zip(sample_queries, expected_responses):
    chunks = retrieve(question)          # your retrieval step: a list of chunk texts
    response = answer(question, chunks)  # your generation step
    dataset.append(
        {
            "user_input": question,
            "retrieved_contexts": chunks,
            "response": response,
            "reference": reference,
        }
    )

evaluation_dataset = EvaluationDataset.from_list(dataset)
  1. 写下用户真正会问的问题,其中包括几个你的文档回答不了的。
  2. 给每个问题写一条参考答案,取自你的文档,一两句话即可。
  3. 让每个问题跑一遍你的流水线,保存它检索到的块和给出的回答。
  4. 把各行载入 EvaluationDataset,或者直接保留成字典列表。
  5. 冻结这个集合。遇到新的失败就加一行,绝不为了让分数好看而删掉某一行。

给检索打分:召回率和精确率

上下文召回率问的是检索器有没有漏掉东西。Ragas 把参考答案拆成若干陈述,逐条对照检索到的上下文检查,所以得分是上下文支持的陈述数,除以参考答案里的陈述总数。因为它要拿来对比,所以总是需要参考答案。

上下文精确率问的是有用的块是不是排在前面。它是检索到的各个块的 precision@k 的平均值,其中 precision@k 统计前 k 个块里的真正例。顺序很重要,Ragas 页面展示了影响有多大:一个相关的块加一个不相关的块,不相关的块排第一时,它的 Context Utilization 得分会减半。

同样两个块,顺序不同

1.0

相关的块排第一时的 Context Utilization,由 0.9999999999 四舍五入

来源:Ragas: Context Precision (2026年11月4日 查阅)

0.5

不相关的块排第一时的 Context Utilization,由 0.49999999995 四舍五入

来源:Ragas: Context Precision (2026年11月4日 查阅)

from openai import AsyncOpenAI
from ragas.llms import llm_factory
from ragas.metrics.collections import ContextPrecision, ContextRecall

client = AsyncOpenAI()  # reads OPENAI_API_KEY
llm = llm_factory("gpt-4o-mini", client=client)  # the judge model

recall = ContextRecall(llm=llm)
precision = ContextPrecision(llm=llm)

recalls, precisions = [], []
for row in dataset:
    recalls.append(
        recall.score(
            user_input=row["user_input"],
            retrieved_contexts=row["retrieved_contexts"],
            reference=row["reference"],
        ).value
    )
    precisions.append(
        precision.score(
            user_input=row["user_input"],
            reference=row["reference"],
            retrieved_contexts=row["retrieved_contexts"],
        ).value
    )

print("context recall", sum(recalls) / len(recalls))
print("context precision", sum(precisions) / len(precisions))
  • 没有参考答案:ContextUtilization 改为拿每个块和生成的回答做比较。
  • 不调用 LLM:NonLLMContextRecall 和 NonLLMContextPrecisionWithReference 用字符串相似度(比如 Levenshtein 距离)把检索到的块和 reference_contexts 做比较。精确率那个需要 rapidfuzz 包。
  • 按 ID:IDBasedContextRecall 和 IDBasedContextPrecision 比较 retrieved_context_ids 和 reference_context_ids。文档里的例子是,4 个参考 ID 检索到 1 个,召回率是 0.25;检索到的 4 个 ID 里有 2 个在参考里,精确率是 0.5。

给答案打分:忠实度和相关性

忠实度先把回答拆成若干陈述,再逐条对照检索到的上下文检查。Ragas 的例子里,上下文说爱因斯坦出生于 1879 年 3 月 14 日,回答是“Einstein was born in Germany on 20th March 1879”,被拆成两条陈述:第一条有依据,第二条没有,得分就是 2 条里的 1 条,也就是一半。

答案相关性只看问题和回答。模型根据回答生成若干人造问题,默认三个,得分是这些问题的嵌入与真实问题的嵌入之间的平均余弦相似度。按它的设计,它不管事实是否准确,而是对不完整或带有多余细节的回答扣分。得分通常在 0 到 1 之间,但余弦相似度最低可到 -1,所以 Ragas 并不保证这个范围。

from ragas.embeddings.base import embedding_factory
from ragas.metrics.collections import AnswerRelevancy, Faithfulness

embeddings = embedding_factory("openai", model="text-embedding-3-small", client=client)

faithfulness = Faithfulness(llm=llm)
relevancy = AnswerRelevancy(llm=llm, embeddings=embeddings)

faithful, relevant = [], []
for row in dataset:
    faithful.append(
        faithfulness.score(
            user_input=row["user_input"],
            response=row["response"],
            retrieved_contexts=row["retrieved_contexts"],
        ).value
    )
    relevant.append(
        relevancy.score(user_input=row["user_input"], response=row["response"]).value
    )

print("faithfulness", sum(faithful) / len(faithful))
print("answer relevancy", sum(relevant) / len(relevant))
  • NoiseSensitivity 是回答里参考答案不支持的陈述所占的比例,所以越低越好。Ragas 默认针对相关的块计算,设置 mode="irrelevant" 就针对不相关的块计算。
  • Ragas 的例子里,一个加入了参考答案从未提过的陈述的回答,得分是 0.333,也就是三条陈述里有一条错误。
  • 忠实度有一个变体 FaithfulnesswithHHEM,它用 Vectara 的 HHEM-2.1-Open 分类器代替逐条检查,Ragas 称这个模型小巧、免费且开源。

读懂分数,选一个杠杆

低分指向流水线的某一半。上下文召回率低,说明那段内容根本没到达模型。上下文精确率低而召回率不错,说明找到了,却排在噪声后面。忠实度低而检索不错,问题出在生成上,LlamaIndex 把改提示词列为应对幻觉或输出格式不佳时最先尝试的做法之一。

杠杆出自第 3 课、第 1 课和 LlamaIndex 的基础策略。提示词方面见系统提示词一课。
低分的指标说明什么可以试的杠杆
上下文召回率检索到的块漏掉了参考答案里的内容块大小和重叠、上下文检索、混合搜索、换一个嵌入模型
上下文精确率相关的块排在不相关的块后面给候选重排序,或者少传几个块
忠实度回答说的比块支持的更多改提示词、加引用
答案相关性回答不完整,或带有多余细节改提示词

评委什么时候需要检查

上面的大多数指标都用模型当评委。Anthropic 按速度、可靠性和规模对评分方法做了排序,并且说,要在可行的方法里选最快、最可靠、最能扩展的那一个。基于代码的评分最快也最可靠,但缺少灵活性。人工评分最灵活,却又慢又贵。基于 LLM 的评分又快又灵活,Anthropic 说要先测试它的可靠性,再扩大规模。

  • 写一份详细、清晰的评分细则,比如规定回答的第一句必须提到某个具体产品,否则算不正确。
  • 让输出具体。告诉评委只回答“correct”或“incorrect”,或者按 1 到 5 打分。
  • 让评委先推理。Anthropic 说,开启思考的评分模型表现更好,在复杂判断上尤其如此。
三种评分方式
基于代码 我们的选择人工基于 LLM
又快又能扩展是否是
能处理细微的判断否是是
开箱即可靠是是部分

我们的选择:基于代码。 凡是字符串匹配或 ID 检查能判断的地方都用它,比如基于 ID 的检索指标,把 LLM 评委留给代码解决不了的部分。

来源:Claude Docs: Define success criteria and build evaluations (2026年11月4日 查阅)

生成更多测试问题

手写问题没法扩展,所以 Ragas 可以从你的文档生成问题。它的指南讲了两步:先用你的文档建一个知识图谱,并用实体、关键词等提取器丰富它,再把图谱转成场景,场景就变成带参考答案的问题。用 to_pandas() 导出结果,保留你认为合适的问题。我们会先读一遍每个生成的问题和它的参考答案再信任它,因为两者都是模型写的。

概念页面把 RAG 的查询分成四类。默认的分布是:一半是单跳具体问题,多跳抽象和多跳具体问题各占四分之一。

import openai
from langchain_community.document_loaders import DirectoryLoader
from langchain_openai import ChatOpenAI
from ragas.embeddings import OpenAIEmbeddings
from ragas.llms import LangchainLLMWrapper
from ragas.testset import TestsetGenerator

docs = DirectoryLoader("docs/", glob="**/*.md").load()

generator_llm = LangchainLLMWrapper(ChatOpenAI(model="gpt-4o"))
generator_embeddings = OpenAIEmbeddings(client=openai.OpenAI())

generator = TestsetGenerator(llm=generator_llm, embedding_model=generator_embeddings)
dataset = generator.generate_with_langchain_docs(docs, testset_size=10)
dataset.to_pandas()
  • 单跳具体:一个来源就能回答一个事实,比如爱因斯坦在哪一年发表了相对论。
  • 单跳抽象:只有一个来源,但答案偏解释性,比如这个理论怎样改变了我们对时间和空间的看法。
  • 多跳具体:需要两个或更多来源,比如哪位科学家影响了爱因斯坦的工作,他们提出了什么理论。
  • 多跳抽象:把多个来源合成一个宽泛的答案,比如相对论自最初发表以来是怎样演变的。

Shreya Shankar 谈怎样检查评委,Hamel Husain 谈通用指标

Shreya Shankar 的 X 简介写着,她即将出任卡内基梅隆大学计算机系的助理教授。2024 年 4 月,她在 X 上说,评估大概是 LLMOps 里最难的部分:模型会出错,所以我们用别的模型去检查,那谁来检验这些检验者?

她团队的论文把其中一个难点叫作“标准漂移”:人要有标准才能给输出打分,而给输出打分,又帮人把标准想清楚。

所以,在相信忠实度或你自己的评委给其余行打的分之前,先亲手给一部分行打分。你和评委意见不同的每一行,都指出评分标准里缺了一条。论文研究里的参与者就是边看边改标准的,你的评分标准也会跟着变。

Hamel Husain 的 X 简介写着他在 OpenAI 做评估。2024 年 6 月,他在 X 上提醒,简洁度、毒性、事实正确性这类通用评估,跑完却没人看数据,就没什么用。

2026 年 7 月,他又在 X 上介绍了他和一位合作者的测试:用真实的生产数据,检验那些用 AI 翻看运行记录、找出问题的工具。它们常能发现人漏掉的问题,却会漏掉需要领域知识和品味的问题,所以他建议用这些工具时,让你自己留在环里。改设置之前,先读忠实度和上下文召回率最低的那几行。

很多人在自己的数据上跑这些评估,却从不看数据。如果盲目地跑,它就是一条几乎毫无价值的安慰毯。

Hamel Husain, 按他的 X 简介,在 OpenAI 做评估,引文为译文 · X (2026年11月5日 查阅)
Shreya Shankar(@sh_reya)2024 年 4 月 22 日在 X 上说:评估大概是 LLMOps 里最难的部分。模型会出错,所以我们用别的模型检查它们,但这让人不太舒服。谁来检验这些检验者?我们做了一个界面,让基于模型的评估和用户的偏好对齐,也弄明白了这件事为什么难
Shreya Shankar 在 X 上,2024 年 4 月 22 日
Hamel Husain(@HamelHusain)2024 年 6 月 4 日在 X 上说:通用评估就是简洁度、毒性、事实正确性这一类。很多人在自己的数据上跑这些评估,却从不看数据。盲目地跑,它就是一条几乎毫无价值的安慰毯,过度依赖还会让产品变差
Hamel Husain 在 X 上,2024 年 6 月 4 日

X 官方嵌入卡片的截图,拍摄于 2026-11-05,时间为协调世界时(UTC)。Shreya Shankar 那条帖子末尾的论文链接,X 的嵌入卡片没有显示。点击截图可到 X 上打开原帖。

常见错误

  • 只给最终答案打分。没有检索到的块,你就分不清是检索没找到,还是生成出了错。
  • 没有参考答案却想算上下文召回率。它总是需要参考答案。
  • 把答案相关性当成准确性。它按设计就不管事实是否准确,所以要和忠实度放在一起看。
  • 把几道题的一次运行当成趋势,而翻转一个答案就会拉动所有平均值。
  • 在两次要比较的运行之间换了评委模型。让评委保持不变,变化的才只有你的流水线。
  • 照搬旧教程,从 ragas.metrics 导入类并调用 single_turn_ascore。文档把这称为旧版 API。

自己试一试

  • 针对一组你熟悉的文档写十个问题,其中两个是回答不了的,再补上参考答案。
  • 挑三个问题,手动标出哪些块的 ID 里有答案,并按找到的 ID 数除以参考 ID 数,算出基于 ID 的召回率。
  • 把第 3 课里的块大小改一下,用同一组问题重跑。先比较平均值,再看逐题的结果。
  • 在某一行里,把一个不相关的块挪到 retrieved_contexts 的最前面,看上下文精确率怎样下降。

下一课

这是 RAG 课程的最后一课。下一门课是高级提示词工程课,也是 AI 工程路径的第一门。它的第一课讲怎样用示例教模型,这也是调整 RAG 流水线回答方式的一种办法。想用自己的问题去检验别人做的东西,可以看看 Mindket 上的智能体。

自测一下

  1. 你的流水线给出了错误答案,这个问题的上下文召回率是 0.0,你先看哪里?

    查看答案

    B. 检索,因为正确的段落根本没到达模型 上下文召回率是检索到的上下文所支持的参考答案陈述所占的比例,所以 0 表示这些块里一条也没有。

  2. 哪个 Ragas 指标统计的是回答中被检索到的上下文所支持的陈述?

    查看答案

    D. 忠实度 忠实度用回答里被检索到的上下文所支持的陈述数,除以回答里的陈述总数。

  3. 相关的块从第一名掉到了第二名,排在一个不相关的块后面,哪个分数会下降?

    查看答案

    A. 上下文精确率 上下文精确率奖励排在不相关块前面的相关块。召回率只问信息有没有被检索到。

  4. Anthropic 对基于 LLM 的评分有什么建议?

    查看答案

    C. 先测试评分模型是否可靠,再扩大规模 Anthropic 说基于 LLM 的评分又快、又灵活、又能扩展,并且要先测试它的可靠性,还要求写详细的评分细则。

常见问题

评估 RAG 该用哪些指标?

先用上表里的四个,如果总有错误的陈述混进来,再加上噪声敏感度。每个检索指标都配一个答案指标,这样才看得出是流水线的哪一半出了问题。

RAG 的评估集要多大?

没有哪份资料规定了下限。Ragas 的指南用的是五个手写问题和一组十个的生成问题,Anthropic 的建议是数量重于质量。先从小处开始,每遇到一个失败就加成新的一行。

没有参考答案,怎么评估 RAG?

先给现在能打的分,参考答案边做边补。四个主要指标里有两个从不读参考答案,ContextUtilization 则用生成的回答代替它。能用的参考答案很短:从包含答案的文档里摘一两句就够了。

LLM 评委可信吗?

先检查。Anthropic 说,扩大规模之前要先测试基于 LLM 的评分是否可靠,并给评委清晰的评分细则、受约束的输出,以及推理的空间。字符串匹配或 ID 检查能判断的地方,就用它们。

忠实度和答案相关性有什么区别?

忠实度问的是回答是否紧扣检索到的上下文。答案相关性问的是它有没有回答问题,并且不管准确性。一个把某个块复述得毫无出入、却答非所问的回答,前一项得分高,后一项得分低。

多少分算好?

Ragas 的页面没有给出及格线。分数通常在 0 到 1 之间,噪声敏感度则是越低越好,所以用它们来比较你流水线的两个版本在同一批问题上的表现。

能自动生成测试问题吗?

可以。Ragas 的 TestsetGenerator 根据你的文档生成问题和参考答案,默认的组合偏重单跳具体问题。用之前先逐个审一遍。

资料来源

  1. Ragas Docs: Installation (2026年11月4日 查阅)https://docs.ragas.io/en/stable/getstarted/install/
  2. Ragas Docs: Evaluate a simple RAG system (2026年11月4日 查阅)https://docs.ragas.io/en/stable/getstarted/rag_eval/
  3. Ragas Docs: Context Recall (2026年11月5日 查阅)https://docs.ragas.io/en/stable/concepts/metrics/available_metrics/context_recall/
  4. Ragas Docs: Context Precision (2026年11月4日 查阅)https://docs.ragas.io/en/stable/concepts/metrics/available_metrics/context_precision/
  5. Ragas Docs: Faithfulness (2026年11月4日 查阅)https://docs.ragas.io/en/stable/concepts/metrics/available_metrics/faithfulness/
  6. Ragas Docs: Response Relevancy (2026年11月4日 查阅)https://docs.ragas.io/en/stable/concepts/metrics/available_metrics/answer_relevance/
  7. Ragas Docs: Noise Sensitivity (2026年11月4日 查阅)https://docs.ragas.io/en/stable/concepts/metrics/available_metrics/noise_sensitivity/
  8. Ragas Docs: Testset Generation for RAG (guide) (2026年11月4日 查阅)https://docs.ragas.io/en/stable/getstarted/rag_testset_generation/
  9. Ragas Docs: Testset Generation for RAG (concepts) (2026年11月4日 查阅)https://docs.ragas.io/en/stable/concepts/test_data_generation/rag/
  10. Claude Docs: Define success criteria and build evaluations (2026年11月4日 查阅)https://platform.claude.com/docs/en/test-and-evaluate/develop-tests
  11. LlamaIndex Docs: Basic strategies (2026年11月5日 查阅)https://developers.llamaindex.ai/python/framework/optimizing/basic_strategies/basic_strategies/
  12. PyPI: ragas release history (2026年11月5日 查阅)https://pypi.org/project/ragas/
  13. Shreya Shankar on X: Who validates the validators? (2026年11月5日 查阅)https://x.com/sh_reya/status/1782425960366940333
  14. arXiv: Who Validates the Validators? Aligning LLM-Assisted Evaluation of LLM Outputs with Human Preferences (2026年11月5日 查阅)https://arxiv.org/abs/2404.12272
  15. Hamel Husain on X: Generic evals (2026年11月5日 查阅)https://x.com/HamelHusain/status/1798024532995052010
  16. Hamel Husain on X: Do Automated Evals Work? (14 July 2026) (2026年11月5日 查阅)https://x.com/HamelHusain/status/2077042379392213377

分享本节课

用你的问题试试现成的智能体

浏览 Mindket 上的智能体,挑一个喜欢的,拿你自己的问题去问它,再像本课这样给它的回答打分。

浏览智能体

本节课的 Markdown 版本 · RAG 实战课:检索增强生成 · 全部课程