微信扫码
添加专属顾问
我要投稿
RAG应用落地难在评估?这份指南帮你建立科学的评估体系,确保应用稳定可控。 核心内容: 1. RAG应用评估的必要性与四大挑战 2. 评估依据与关键指标解析 3. 评估流程设计与实施方法
一、为什么RAG应用需要评估
随着大模型技术的发展,我们已经具备了开发完整 RAG(Retrieval-Augmented Generation,检索增强生成)应用的技术能力。借助 LlamaIndex、LangChain 等成熟框架,可以在较短时间内实现从原型到应用的快速构建。然而,真正将 RAG 应用推向生产环境,远不只是“搭建起来”那么简单,仍有许多问题值得提前思考与应对。
1. 大模型输出的不确定性
大模型的回答往往带有不确定性,这种特性会造成结果的不可预知性。如果缺乏充分测试,上线后可能引发严重的应用风险。因此,在部署之前,必须通过科学的方法对系统进行全面评估,尽可能量化和控制这种不确定性。
2. 持续评估与改进机制
应用上线只是起点。在后续的迭代中,需要建立科学、快速且可复用的评估机制,用于衡量改进是否真正带来价值。例如,某次优化后,回答的置信度是上升了 10%,还是下降了 5%?只有通过系统化的度量,才能避免“盲目调优”。
3. 知识库的动态变化
RAG 应用依赖的知识库并非一成不变。在持续更新与维护过程中,可能会引入新的噪声甚至错误信息。为了确保应用长期稳定运行,定期检测与重新评估知识库的质量就显得尤为重要。
4. 底层模型的选择与升级
RAG 应用高度依赖底层大模型。面对市面上众多商业与开源模型,企业需要明确如何选择最适合自身需求的版本。同时,模型升级是否会带来性能提升,还是引入新的不确定性,也是必须提前纳入评估体系的关键问题。
RAG 应用的快速开发并非难事,真正的挑战在于如何在生产环境中保持其稳定性、可控性和持续改进的能力。唯有建立起科学的评估与运维体系,才能让 RAG 应用真正发挥价值。
二、RAG应用的评估依据与指标
RAG 应用的评估依据,即评估模块的输入一般包括以下要素。
输入问题(question):用户在使用 RAG 应用时的输入问题。
生成的答案(answer):需要评估的 RAG 应用的输出,即问题的答案。
上下文(context):用于增强 RAG 应用输出的参考上下文,通常在检索阶段生成。
参考答案(reference_answer):输入问题的真实的正确答案,通常需要人类标注。
基于这些评估依据,对 RAG 应用进行评估的常见指标见表1 。
三、RAG应用的评估流程与方法
确定评估的目的、维度与指标。
准备评估数据集,可以自行准备与标注,也可以使用大模型生成。根
据 评 估 指 标 , 你 可 能 需 要 准 备 不 同 的 输 入 问 题 ( question ) 与 参 考 答 案(reference_answer)。
将评估数据集输入 RAG 应用,获得检索结果(即上下文,context)与生成的答案(answer)。
将评估依据输入评估器,计算各类评估指标,分析 RAG 应用的整体性能。
对 RAG 应用的组件级评估通常侧重于检索与生成两个最关键的阶段。通过对这两个阶段单独评估,可以更细致地观察与分析问题,从而有针对性地优化与增强 RAG 应用。
四、评估检索质量
利用检索评估组件 RetrieverEvaluator 可以对任何检索模块进行质量评估。
该评估的主要指标如下。
命中率(hit_rate):表示检索出的上下文对期望的上下文的命中率。
平均倒数排名(mrr):衡量检索出的上下文的排名质量。
cohere 重排相关性(cohere-rerank-relevancy):用 Cohere Rerank 模型的排名结果衡量检索的排名质量。
评估检索质量的主要依据为输入问题与期望的上下文(检索出的 Node)。
1、生成检索评估数据集
# 读取文档,构造 Node,用于生成检索评估数据集
from pathlib import Path
from llama_index.core import SimpleDirectoryReader, VectorStoreIndex
from llama_index.core.node_parser import SentenceSplitter
from llama_index.core.evaluation import (
generate_question_context_pairs,
EmbeddingQAFinetuneDataset,
)
# 加载大模型的代码,请勿删除 start
from common.llm_model_helper import llm_settings
# 加载大模型的代码,请勿删除 end
documents = SimpleDirectoryReader(
input_files=[r"D:\muxue\common_docs\jianlai.txt"]).load_data()
node_parser = SentenceSplitter(chunk_size=1024)
nodes = node_parser.get_nodes_from_documents(documents)
for idx, node in enumerate(nodes):
node.id_ = f"node_{idx}"
# 准备一个检索器,后面使用
# vector_index = VectorStoreIndex(nodes)
# retriever = vector_index.as_retriever(similarity_top_k=2)
QA_GENERATE_PROMPT_TMPL = """
以下是上下文:
---------------------
{context_str}
---------------------
你是一位专业教授。你的任务是基于以上的上下文,为即将到来的考试设置{num_questions_per_chunk} 个问题。
这些问题必须基于提供的上下文生成,并确保上下文能够回答这些问题。确保每一行都只有一个独立的问题。不要有多余解释。不要给问题编号。
"""
print("Generating question-context pairs...")
qa_dataset = generate_question_context_pairs(
nodes,
# llm=llm_Ollama,
num_questions_per_chunk=1,
qa_generate_prompt_tmpl=QA_GENERATE_PROMPT_TMPL
)
print("Saving dataset...")
qa_dataset.save_json("retriever_eval_dataset.json")
在这段代码中,手工设置了中文的 Prompt,一方面有助于了解生成原理与调试生成结果,另一方面用于生成中文问题。最后,把生成的检索评估数据集保存到本地的 JSON 文档中,以减少不必要的重复生成,后面只需要从本地文档中加载即可。
2、运行评估检索过程的程序
我们已经构造了一个检索器,并且借助大模型生成了检索评估数据集。下面构造与运行检索评估器。基本的流程如下。
加载检索评估数据集。
构造检索评估器( RetrieverEvaluator 对象),设置评估指标。
调用 evaluate 方法,查看评估结果。
# 读取文档,构造 Node,用于生成检索评估数据集
# 读取文档,构造 Node,用于生成检索评估数据集
from pathlib import Path
from llama_index.core import SimpleDirectoryReader, VectorStoreIndex
from llama_index.core.node_parser import SentenceSplitter
from llama_index.core.evaluation import (
generate_question_context_pairs,
EmbeddingQAFinetuneDataset,
)
from llama_index.core.evaluation import RetrieverEvaluator
from evaluation_comm import get_retriever
print("Loading dataset...")
# 从保存的 JSON 文档中加载检索评估数据集
qa_dataset = EmbeddingQAFinetuneDataset.from_json("retriever_eval_dataset.json")
eval_querys = list(qa_dataset.queries.items())
# 构造一个检索评估器,设定两个评估指标
metrics = ["mrr", "hit_rate"]
retriever_evaluator = RetrieverEvaluator.from_metric_names(metrics, retriever=get_retriever())
# 简单评估前 10 个评估用例
for eval_id, eval_query in eval_querys[:10]:
expect_docs = qa_dataset.relevant_docs[eval_id]
print(f"Query: {eval_query}, Expected docs: {expect_docs}")
# 评估,输入评估问题与预期检索出的 Node
eval_result = retriever_evaluator.evaluate(query=eval_query, expected_ids=expect_docs)
print(eval_result)
# 对整个评估数据集进行评估
# eval_results = retriever_evaluator.evaluate_dataset(qa_dataset)
从打印的结果中可以看到评估指标,你可以对这些评估指标进行汇总计算,得出检索评估器的质量评估结果。如果需要对整个检索评估数据集直接进行评估,那么可以使用更简单的方式:
eval_results = retriever_evaluator.evaluate_dataset(qa_dataset)
直接在检索评估数据集上调用 evaluate_dataset 方法,其效果与逐个循环调用 evaluate 方法的效果是一致的。
五、评估响应质量
1、 生成响应评估数据集
from pathlib import Path
from llama_index.core import SimpleDirectoryReader, VectorStoreIndex
from llama_index.core.llama_dataset.generator import RagDatasetGenerator
from llama_index.core.llama_dataset import LabelledRagDataset
# 加载大模型的代码
from common.llm_model_helper import llm_settings
# build documents
docs = SimpleDirectoryReader(input_files=[r'D:\muxue\common_docs\jianlai.txt']).load_data()
# define generator, generate questions
dataset_generator = RagDatasetGenerator.from_documents(
documents=docs,
#llm=llm_ollama,
num_questions_per_chunk=1, # 设置每个 Node 都生成的问题数量
show_progress=True,
question_gen_query="您是一位老师。您的任务是为即将到来的考试设置{num_questions_per_chunk}个问题。这些问题必须基于提供的上下文生成,并确保上下文能够回答这些问题。确保每一行都只有一个独立的问题。不要有多余解释。不要给问题编号。")
# 以下代码只需要运行一次
save_json_name='rag_eval_dataset_jianlai.json'
print('Generating questions from nodes...\n')
rag_dataset = dataset_generator.generate_dataset_from_nodes()
rag_dataset.save_json(save_json_name)
# 从本地文档中加载并查看
print('Loading dataset...\n')
rag_dataset = LabelledRagDataset.from_json(save_json_name)
for example in rag_dataset.examples:
print(f'query: {example.query}')
print(f'answer: {example.reference_answer}')
在运行代码后,你可以在当前目录中看到一个 rag_eval_dataset_jianlai.json 数据集文档,打开该文档,可以看到生成的每个评估用例的数据格式。其中:
query:生成的问题。
reference_contexts:检索出的参考上下文。
reference_answers:参考答案。
这些内容都可能被输入到后面的响应评估器中,作为评估响应质量的输入依据,如下所示。
2、单次响应评估
要想对 RAG 应用的某一次查询的响应过程进行不同维度的评估,那么只需要构造对应的评估器组件(Evaluator),然后输入必需的数据,即可获得评估结果。单次响应评估的输入参数有以下几个。
query:输入问题。
response:RAG 应用的响应结果。如果使用 evaluate_response 方法评估,那么可以直接输入 response;如果使用 evaluate 方法评估,那么需要从response 中提取上下文与文本内容,将其分别作为参数输入。
reference:参考答案。它在正确性与相似度评估中会用到,对应响应评估数据集中的 reference_answer 字段。
from llama_index.core import (
VectorStoreIndex,
SimpleDirectoryReader,
Response,
)
from llama_index.core.node_parser import SentenceSplitter
from llama_index.core.evaluation import (FaithfulnessEvaluator,RelevancyEvaluator,ContextRelevancyEvaluator
,AnswerRelevancyEvaluator,CorrectnessEvaluator,SemanticSimilarityEvaluator)
# 加载大模型的代码,请勿删除 start
from common.llm_model_helper import llm_settings
# 加载大模型的代码,请勿删除 end
# ......这里省略构造查询引擎的过程......
documents = SimpleDirectoryReader(input_files=[r"D:\muxue\common_docs\jianlai.txt"]).load_data()
# create vector index
splitter = SentenceSplitter(chunk_size=512)
vector_index = VectorStoreIndex.from_documents(
documents, transformations=[splitter]
)
query_engine = vector_index.as_query_engine()
# 两个重要的输入参数
query = "陈平安对中年光棍的尖酸刻薄言语有何反应?"
response = query_engine.query(query)
# 评估忠实度的评估器
evaluator = FaithfulnessEvaluator()
eval_result = evaluator.evaluate_response(query=query,
response=response)
print(f'faithfulness score: {eval_result.score}\n')
# 评估相关性的评估器(综合了上下文相关性与答案相关性)
evaluator = RelevancyEvaluator()
eval_result =evaluator.evaluate_response(query=query, response=response)
print(f'relevancy score: {eval_result.score}\n')
# 评估上下文相关性的评估器
evaluator = ContextRelevancyEvaluator()
eval_result =evaluator.evaluate_response(query=query, response=response)
print(f'context relevancy score: {eval_result.score}\n')
# 评估答案相关性的评估器
evaluator = AnswerRelevancyEvaluator()
eval_result =evaluator.evaluate_response(query=query, response=response)
print(f'answer relevancy score: {eval_result.score}\n')
# 评估正确性的评估器,注意输入了 reference
evaluator = CorrectnessEvaluator()
eval_result =evaluator.evaluate_response(query=query, response=response,
reference='根据提供的上下文信息,陈平安对中年光棍的尖酸刻薄言语反应如下:他翻了个白眼,但并不以为意。原因有二:一是他生活在这座乡野地方,早已习惯此类言语,认为若因此恼火反而显得可笑;二是这中年光棍本身也是小镇百姓经常取笑的对象,陈平安对此人并无太多计较。')
print(f'correctness score: {eval_result.score}\n')
# 评估答案与标准答案的语义相似度(基于 embedding)的评估器,注意输入了 reference
evaluator = SemanticSimilarityEvaluator()
eval_result =evaluator.evaluate_response(query=query, response=response,
reference='陈平安翻了个白眼,但并不以为意,对此人并无太多计较。')
print(f'semantic similarity score: {eval_result.score}\n')
评估过程非常简单,各个评估指标可参考表 1中的说明。必须再次强调,有的评估器需要输入参考答案(正确性与语义相似度),否则会出现异常。在正常运行评估代码后,可以看到输出的评估结果,如下图所示。
3、批量响应评估
你可以借助批量评估器,在评估数据集的基础上并行运行多个响应评估器,并通过计算与统计获得综合的性能评估结果。以 (五-1)节生成的响应评估数据集为基础,对构造的查询引擎进行综合评估:
from llama_index.core import (
VectorStoreIndex,
SimpleDirectoryReader,
Response,
)
from llama_index.core.node_parser import SentenceSplitter
from llama_index.core.llama_dataset import LabelledRagDataset
from llama_index.core.evaluation import (FaithfulnessEvaluator, RelevancyEvaluator, ContextRelevancyEvaluator
, AnswerRelevancyEvaluator, CorrectnessEvaluator, SemanticSimilarityEvaluator)
from llama_index.core.evaluation import BatchEvalRunner
import asyncio
# 打印评估结果
import pandas as pd
# 加载大模型的代码,请勿删除 start
from common.llm_model_helper import llm_settings
# 加载大模型的代码,请勿删除 end
# ......这里造查询引擎......
documents = SimpleDirectoryReader(input_files=[r"D:\muxue\common_docs\jianlai.txt"]).load_data()
# create vector index
splitter = SentenceSplitter(chunk_size=512)
vector_index = VectorStoreIndex.from_documents(
documents, transformations=[splitter]
)
query_engine = vector_index.as_query_engine()
# 构造多个响应评估器
faithfulness_evaluator = FaithfulnessEvaluator()
relevancy_evaluator = RelevancyEvaluator()
correctness_evaluator = CorrectnessEvaluator()
similartiy_evaluator = SemanticSimilarityEvaluator()
# 加载数据集
rag_dataset = LabelledRagDataset.from_json('rag_eval_dataset_jianlai.json')
# 构造一个批量评估器
runner = BatchEvalRunner(
{"faithfulness": faithfulness_evaluator,
"relevancy": relevancy_evaluator,
"correctness": correctness_evaluator,
"similarity": similartiy_evaluator},
workers=4
)
async def evaluate_queries():
"""
为了提高性能,采用异步并行的评估方法,调用批量评估器
输入:查询引擎、批量的 query,批量的 reference
这里对响应评估数据集中的前十个评估用例进行评估
"""
eval_results = await runner.aevaluate_queries(
query_engine,
queries=[example.query for example in rag_dataset.examples][:10],
reference=[example.reference_answer for example in rag_dataset.examples][:10],
)
return eval_results
eval_results = asyncio.run(evaluate_queries())
def display_results(eval_results):
data = {}
for key, results in eval_results.items():
scores = [result.score for result in results]
scores.append(sum(scores) / len(scores))
data[key] = scores
data["query"] = [result.query for result in eval_results["faithfulness"]]
data["query"].append("【Average】")
df = pd.DataFrame(data)
print(df)
display_results(eval_results)
借助 BatchEvalRunner 组件,在调用 aevaluate_queries 方法进行批量评估时可以设置 workers 参数并行运行,从而缩短评估的时间。最后,我们把评估结果用表格的形式展示,以便更直观地观察(也可以输出 Excel 文档),输出结果如图所示。
53AI,企业落地大模型首选服务商
产品:场景落地咨询+大模型应用平台+行业解决方案
承诺:免费POC验证,效果达标后再合作。零风险落地应用大模型,已交付160+中大型企业
2025-09-10
企业级RAG系统实战心得:来自10多个项目的深度总结
2025-09-10
您应该为您的 RAG 系统使用哪种分块技术?
2025-09-10
关于多模态应用的几个疑问,以及多模态应该怎么应用于RAG?
2025-09-10
MiniMax RAG 技术:从推理、记忆到多模态的演进与优化
2025-09-09
告别新手级RAG!一文掌握专业级后检索优化流水线
2025-09-09
切块、清洗、烹饪:RAG知识库构建的三步曲
2025-09-09
终结 “闭卷考试”:RAG 如何从根源上构建可信的AI应用
2025-09-09
你的RAG应用为什么总“胡说八道”?这份21项优化自查清单,帮你根治AI幻觉
2025-06-20
2025-06-20
2025-07-15
2025-06-24
2025-06-24
2025-07-16
2025-06-23
2025-07-09
2025-06-15
2025-06-20
2025-09-10
2025-09-10
2025-09-03
2025-08-28
2025-08-25
2025-08-20
2025-08-11
2025-08-05