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

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

Mindket 编辑部 · 发布于 2026-11-04 · 更新于 2026-11-05 · https://mindket.com/cn/learn/rag/evaluate-rag

## 要点

- 分清检索失败和生成失败。
- 用 Ragas 需要的四个字段建一个小型评估集。
- 算出上下文召回率、上下文精确率、忠实度和答案相关性，并读懂每个指标在数什么。
- 知道 LLM 评委在哪里需要检查，并能从你的文档生成更多测试问题。

## 开始之前

你需要 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](https://pypi.org/project/ragas/) 显示，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 的指标就是沿着这条线划分的，所以一个分数能告诉你该修哪一半。上下文召回率和上下文精确率评的是检索到的块，忠实度和答案相关性评的是回答，噪声敏感度则两边都看。

| 指标 | 回答什么问题 | 需要的字段 | 越高越好吗 |
| --- | --- | --- | --- |
| 上下文召回率 | 检索到的块是否支持参考答案里的每一条陈述？ | 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` 是标准答案。[它的入门指南](https://docs.ragas.io/en/stable/getstarted/rag_eval/)的做法是让每个查询跑一遍流水线，再把各行载入 `EvaluationDataset`。指南说参考答案是可选的，但上面有三个指标要用到它。

[Anthropic 的指南](https://platform.claude.com/docs/en/test-and-evaluate/develop-tests)在建评估时的建议同样适用：贴近任务的真实分布，加入边界情况，比如无关或不存在的输入、特别长的输入，以及连人都很难达成一致的模糊情况，并且宁可要更多可自动评分的问题，也不要少量人工评分的问题。

````python
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 页面](https://docs.ragas.io/en/stable/concepts/metrics/available_metrics/context_precision/)展示了影响有多大：一个相关的块加一个不相关的块，不相关的块排第一时，它的 Context Utilization 得分会减半。

**同样两个块，顺序不同**

- **1.0** 相关的块排第一时的 Context Utilization，由 0.9999999999 四舍五入 (来源：[Ragas: Context Precision](https://docs.ragas.io/en/stable/concepts/metrics/available_metrics/context_precision/), 2026-11-04 查阅)
- **0.5** 不相关的块排第一时的 Context Utilization，由 0.49999999995 四舍五入 (来源：[Ragas: Context Precision](https://docs.ragas.io/en/stable/concepts/metrics/available_metrics/context_precision/), 2026-11-04 查阅)

````python
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 的例子](https://docs.ragas.io/en/stable/concepts/metrics/available_metrics/faithfulness/)里，上下文说爱因斯坦出生于 1879 年 3 月 14 日，回答是“Einstein was born in Germany on 20th March 1879”，被拆成两条陈述：第一条有依据，第二条没有，得分就是 2 条里的 1 条，也就是一半。

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

````python
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 把改提示词列为应对幻觉或输出格式不佳时最先尝试的做法之一。

> **我们对读分数的看法**
>
> 我们会一次只改一样东西，用同一组问题重新跑一遍，只有分数确实有变化才保留这个改动。问题只有十几个时，翻转一个答案就会拉动所有平均值，所以先看逐题的结果，再相信平均数。

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

## 评委什么时候需要检查

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

- 写一份详细、清晰的评分细则，比如规定回答的第一句必须提到某个具体产品，否则算不正确。
- 让输出具体。告诉评委只回答“correct”或“incorrect”，或者按 1 到 5 打分。
- 让评委先推理。Anthropic 说，开启思考的评分模型表现更好，在复杂判断上尤其如此。

**三种评分方式**

| | 基于代码 (我们的选择) | 人工 | 基于 LLM |
| --- | --- | --- | --- |
| 又快又能扩展 | ✓ 是 | ✗ 否 | ✓ 是 |
| 能处理细微的判断 | ✗ 否 | ✓ 是 | ✓ 是 |
| 开箱即可靠 | ✓ 是 | ✓ 是 | ◐ 部分 |

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

来源：[Claude Docs: Define success criteria and build evaluations](https://platform.claude.com/docs/en/test-and-evaluate/develop-tests) (2026-11-04 查阅)

## 生成更多测试问题

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

[概念页面](https://docs.ragas.io/en/stable/concepts/test_data_generation/rag/)把 RAG 的查询分成四类。默认的分布是：一半是单跳具体问题，多跳抽象和多跳具体问题各占四分之一。

````python
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 上](https://x.com/sh_reya/status/1782425960366940333)说，评估大概是 LLMOps 里最难的部分：模型会出错，所以我们用别的模型去检查，那谁来检验这些检验者？

[她团队的论文](https://arxiv.org/abs/2404.12272)把其中一个难点叫作“标准漂移”：人要有标准才能给输出打分，而给输出打分，又帮人把标准想清楚。

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

Hamel Husain 的 X 简介写着他在 OpenAI 做评估。2024 年 6 月，他[在 X 上](https://x.com/HamelHusain/status/1798024532995052010)提醒，简洁度、毒性、事实正确性这类通用评估，跑完却没人看数据，就没什么用。

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

> 很多人在自己的数据上跑这些评估，却从不看数据。如果盲目地跑，它就是一条几乎毫无价值的安慰毯。
>
> Hamel Husain, 按他的 X 简介，在 OpenAI 做评估，引文为译文, [X](https://x.com/HamelHusain/status/1798024532995052010) (2026-11-05 查阅)

[![Shreya Shankar（@sh_reya）2024 年 4 月 22 日在 X 上说：评估大概是 LLMOps 里最难的部分。模型会出错，所以我们用别的模型检查它们，但这让人不太舒服。谁来检验这些检验者？我们做了一个界面，让基于模型的评估和用户的偏好对齐，也弄明白了这件事为什么难](https://mindket.com/blog/shots/x-shreya-who-validates-validators.webp?v=5ceeb9e4aab0)](https://x.com/sh_reya/status/1782425960366940333)

Shreya Shankar 在 X 上，2024 年 4 月 22 日

[![Hamel Husain（@HamelHusain）2024 年 6 月 4 日在 X 上说：通用评估就是简洁度、毒性、事实正确性这一类。很多人在自己的数据上跑这些评估，却从不看数据。盲目地跑，它就是一条几乎毫无价值的安慰毯，过度依赖还会让产品变差](https://mindket.com/blog/shots/x-hamelhusain-generic-evals.webp?v=954bb084d692)](https://x.com/HamelHusain/status/1798024532995052010)

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 工程路径的第一门。[它的第一课](https://mindket.com/cn/learn/prompt-engineering-advanced/few-shot-prompting)讲怎样用示例教模型，这也是调整 RAG 流水线回答方式的一种办法。想用自己的问题去检验别人做的东西，可以看看 Mindket 上的[智能体](https://mindket.com/cn/agents)。

## 自测一下

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

   A. 要求模型引用来源的提示词
   B. 检索，因为正确的段落根本没到达模型
   C. 评委模型
   D. 答案相关性背后的嵌入

   答案：B。 上下文召回率是检索到的上下文所支持的参考答案陈述所占的比例，所以 0 表示这些块里一条也没有。

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

   A. 上下文精确率
   B. 答案相关性
   C. 噪声敏感度
   D. 忠实度

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

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

   A. 上下文精确率
   B. 上下文召回率
   C. 忠实度
   D. 答案相关性

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

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

   A. 直接信任，因为它能扩展
   B. 用它取代所有基于代码的检查
   C. 先测试评分模型是否可靠，再扩大规模
   D. 不写评分细则，让评分模型自由推理

   答案：C。 Anthropic 说基于 LLM 的评分又快、又灵活、又能扩展，并且要先测试它的可靠性，还要求写详细的评分细则。

## 常见问题

### 评估 RAG 该用哪些指标？

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

### RAG 的评估集要多大？

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

### 没有参考答案，怎么评估 RAG？

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

### LLM 评委可信吗？

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

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

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

### 多少分算好？

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

### 能自动生成测试问题吗？

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

## 资料来源

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

[浏览智能体](https://mindket.com/cn/agents)
