开始之前
你需要 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 的指标就是沿着这条线划分的,所以一个分数能告诉你该修哪一半。上下文召回率和上下文精确率评的是检索到的块,忠实度和答案相关性评的是回答,噪声敏感度则两边都看。
| 指标 | 回答什么问题 | 需要的字段 | 越高越好吗 |
|---|---|---|---|
| 上下文召回率 | 检索到的块是否支持参考答案里的每一条陈述? | 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)- 写下用户真正会问的问题,其中包括几个你的文档回答不了的。
- 给每个问题写一条参考答案,取自你的文档,一两句话即可。
- 让每个问题跑一遍你的流水线,保存它检索到的块和给出的回答。
- 把各行载入
EvaluationDataset,或者直接保留成字典列表。 - 冻结这个集合。遇到新的失败就加一行,绝不为了让分数好看而删掉某一行。
给检索打分:召回率和精确率
上下文召回率问的是检索器有没有漏掉东西。Ragas 把参考答案拆成若干陈述,逐条对照检索到的上下文检查,所以得分是上下文支持的陈述数,除以参考答案里的陈述总数。因为它要拿来对比,所以总是需要参考答案。
上下文精确率问的是有用的块是不是排在前面。它是检索到的各个块的 precision@k 的平均值,其中 precision@k 统计前 k 个块里的真正例。顺序很重要,Ragas 页面展示了影响有多大:一个相关的块加一个不相关的块,不相关的块排第一时,它的 Context Utilization 得分会减半。
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 把改提示词列为应对幻觉或输出格式不佳时最先尝试的做法之一。
| 低分的指标 | 说明什么 | 可以试的杠杆 |
|---|---|---|
| 上下文召回率 | 检索到的块漏掉了参考答案里的内容 | 块大小和重叠、上下文检索、混合搜索、换一个嵌入模型 |
| 上下文精确率 | 相关的块排在不相关的块后面 | 给候选重排序,或者少传几个块 |
| 忠实度 | 回答说的比块支持的更多 | 改提示词、加引用 |
| 答案相关性 | 回答不完整,或带有多余细节 | 改提示词 |
评委什么时候需要检查
上面的大多数指标都用模型当评委。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 翻看运行记录、找出问题的工具。它们常能发现人漏掉的问题,却会漏掉需要领域知识和品味的问题,所以他建议用这些工具时,让你自己留在环里。改设置之前,先读忠实度和上下文召回率最低的那几行。
很多人在自己的数据上跑这些评估,却从不看数据。如果盲目地跑,它就是一条几乎毫无价值的安慰毯。
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 上的智能体。
自测一下
你的流水线给出了错误答案,这个问题的上下文召回率是 0.0,你先看哪里?
查看答案
B. 检索,因为正确的段落根本没到达模型 上下文召回率是检索到的上下文所支持的参考答案陈述所占的比例,所以 0 表示这些块里一条也没有。
哪个 Ragas 指标统计的是回答中被检索到的上下文所支持的陈述?
查看答案
D. 忠实度 忠实度用回答里被检索到的上下文所支持的陈述数,除以回答里的陈述总数。
相关的块从第一名掉到了第二名,排在一个不相关的块后面,哪个分数会下降?
查看答案
A. 上下文精确率 上下文精确率奖励排在不相关块前面的相关块。召回率只问信息有没有被检索到。
Anthropic 对基于 LLM 的评分有什么建议?
查看答案
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/
- Ragas Docs: Evaluate a simple RAG system https://docs.ragas.io/en/stable/getstarted/rag_eval/
- Ragas Docs: Context Recall https://docs.ragas.io/en/stable/concepts/metrics/available_metrics/context_recall/
- Ragas Docs: Context Precision https://docs.ragas.io/en/stable/concepts/metrics/available_metrics/context_precision/
- Ragas Docs: Faithfulness https://docs.ragas.io/en/stable/concepts/metrics/available_metrics/faithfulness/
- Ragas Docs: Response Relevancy https://docs.ragas.io/en/stable/concepts/metrics/available_metrics/answer_relevance/
- Ragas Docs: Noise Sensitivity https://docs.ragas.io/en/stable/concepts/metrics/available_metrics/noise_sensitivity/
- Ragas Docs: Testset Generation for RAG (guide) https://docs.ragas.io/en/stable/getstarted/rag_testset_generation/
- Ragas Docs: Testset Generation for RAG (concepts) https://docs.ragas.io/en/stable/concepts/test_data_generation/rag/
- Claude Docs: Define success criteria and build evaluations https://platform.claude.com/docs/en/test-and-evaluate/develop-tests
- LlamaIndex Docs: Basic strategies https://developers.llamaindex.ai/python/framework/optimizing/basic_strategies/basic_strategies/
- PyPI: ragas release history https://pypi.org/project/ragas/
- Shreya Shankar on X: Who validates the validators? https://x.com/sh_reya/status/1782425960366940333
- arXiv: Who Validates the Validators? Aligning LLM-Assisted Evaluation of LLM Outputs with Human Preferences https://arxiv.org/abs/2404.12272
- Hamel Husain on X: Generic evals https://x.com/HamelHusain/status/1798024532995052010
- Hamel Husain on X: Do Automated Evals Work? (14 July 2026) https://x.com/HamelHusain/status/2077042379392213377


