RAG 评估指南:解析评估指标与代码示例
RAG 系统评估涉及检索评估和响应评估。检索评估关注上下文相关性,常用指标包括精确度、召回率、MRR 和 MAP。响应评估关注忠实度和答案相关性。通过 LangSmith 平台可以方便地创建测试数据集并运行自动化评估器(如 cot_qa),从而迭代改进 RAG 系统的性能与可靠性。本文详细介绍了 RAG 优化策略、评估指标计算方法以及 LangSmith 的具体实施代码。

RAG 系统评估涉及检索评估和响应评估。检索评估关注上下文相关性,常用指标包括精确度、召回率、MRR 和 MAP。响应评估关注忠实度和答案相关性。通过 LangSmith 平台可以方便地创建测试数据集并运行自动化评估器(如 cot_qa),从而迭代改进 RAG 系统的性能与可靠性。本文详细介绍了 RAG 优化策略、评估指标计算方法以及 LangSmith 的具体实施代码。

在构建检索增强生成(Retrieval-Augmented Generation, RAG)系统时,我们常面临数据质量差、检索不准、生成幻觉等问题。为了优化 RAG 效果,必须建立科学的评估体系。
针对常见的 RAG 痛点,以下是最佳实践总结及关键优化点:
在使用数据之前,确保数据是干净和结构化的。这包括去除噪音、处理缺失值、标准化格式等。
分段和标注: 将长文档分成较小的段落(chunks),并为每个段落添加相关标签或元数据,以便更好地进行检索和生成。
import pandas as pd
# 读取数据
data = pd.read_csv('data.csv')
# 数据清洗
data.dropna(inplace=True) # 去除缺失值
data['text'] = data['text'].str.lower() # 转换为小写
data['text'] = data['text'].str.replace(r'\d+', '', regex=True) # 去除数字
# 数据分段和标注
def chunk_text(text, chunk_size=200):
words = text.split()
chunks = [' '.join(words[i:i + chunk_size]) for i in range(0, len(words), chunk_size)]
return chunks
data['chunks'] = data['text'].apply(chunk_text)
Chunk-size 的设置需要平衡信息量和检索效率。一般来说,较短的 chunk 可以提高检索的准确性,但可能会丢失上下文信息;较长的 chunk 可以保留更多的上下文,但可能会增加冗余信息。常见的 chunk 大小在 100 到 300 个词之间,根据具体应用场景进行调整。
# 设置 chunk 大小
chunk_size = 150 # 例如设置为 150 个词
# 分段函数
def chunk_text(text, chunk_size):
words = text.split()
chunks = [' '.join(words[i:i + chunk_size]) for i in range(0, len(words), chunk_size)]
return chunks
data['chunks'] = data['text'].apply(lambda x: chunk_text(x, chunk_size))
选择合适的模型:常用的 embedding 模型包括 BERT、RoBERTa、Sentence-BERT 等。选择时需要考虑模型的性能、训练数据和计算资源。
from sentence_transformers import SentenceTransformer
# 使用 Sentence-BERT 模型
model = SentenceTransformer('paraphrase-MiniLM-L6-v2')
# 对数据进行 embedding
embeddings = model.encode(data['chunks'].sum())
对于特定领域的应用,可以考虑对预训练模型进行微调,以提高嵌入的相关性和准确性。
设计有效的 prompt 以引导生成模型产生所需的回答。Prompt 应尽量清晰、具体,避免模糊或开放性太强。
# 示例 prompt 设计
prompt_template = "请根据以下内容回答问题:\n\n内容:{}\n\n问题:{}"
def create_prompt(content, question):
return prompt_template.format(content, question)
# 使用示例
content = "这是一个示例内容。"
question = "这段内容的主要观点是什么?"
prompt = create_prompt(content, question)
TopN 设置决定了在生成过程中使用多少个最相关的文档段落。常见的 topN 值在 3 到 10 之间,根据检索效果和生成质量进行调整。
from sklearn.metrics.pairwise import cosine_similarity
import numpy as np
# 假设我们有一个查询的 embedding
query_embedding = model.encode("示例查询")
# 计算相似度
similarities = cosine_similarity([query_embedding], embeddings)[0]
# 设置 topN 值
topN = 5
# 获取最相似的 topN 个结果
topN_indices = np.argsort(similarities)[-topN:][::-1]
topN_chunks = [data['chunks'].sum()[i] for i in topN_indices]
选择合适的生成模型:常用的大语言模型(LLM)包括 GPT-3.5、GPT-4、4o 等。选择时需要考虑模型的生成能力、推理速度和计算资源。
混合使用模型:在一些场景下,可以同时使用多个模型来提高生成效果,例如结合检索模型和生成模型的优势。
通过不断地实验和优化,可以找到最适合特定应用场景的 RAG 配置,从而实现更好的检索和生成效果。
评估是 AI 开发流程中的一个非常关键步骤,它被用于检查当前策略相对于其他策略的有效性,或在当你对流程进行更改时进行评估。因此在进行 LLM 项目的开发和改进时,必须要有衡量其表现的方法。
为了评估 RAG 系统,我们通常使用两种类型的评估:
与传统的机器学习技术不同,传统技术有明确定量的度量指标(如 Gini 系数、R 平方、AIC、BIC、混淆矩阵等),评估 RAG 系统更加复杂。这种复杂性的原因在于 RAG 系统生成的响应是非结构化文本,需要结合定性和定量指标来准确评估其性能。
为了有效评估 RAG 系统,我们通常遵循 TRIAD 框架。该框架由三个主要组成部分组成:
检索评估适用于 RAG 系统的检索器组件,该组件通常使用向量数据库。这些评估衡量检索器在响应用户查询时识别和排名相关文档的效果。检索评估的主要目标是评估上下文相关性,即检索到的文档与用户查询的匹配程度。它确保提供给生成组件的上下文是相关和准确的。
精确度衡量了检索到的文档的准确性。它是检索到的相关文档数量与检索到的文档总数之比。
这意味着精确度评估了系统检索到的文档中有多少实际与用户查询相关。例如,如果检索器检索到了 10 个文档,其中 7 个是相关的,那么精确度将是 0.7 或 70%。
def calculate_precision(retrieved_docs, relevant_docs):
"""
计算精确度
参数:
retrieved_docs (list): 检索到的文档列表
relevant_docs (list): 相关文档列表
返回:
float: 精确度
"""
# 计算检索到的相关文档数量
relevant_retrieved_docs = [doc for doc in retrieved_docs if doc in relevant_docs]
# 计算精确度
precision = len(relevant_retrieved_docs) / len(retrieved_docs) if retrieved_docs else 0
return precision
# 示例数据
retrieved_docs = ['doc1', 'doc2', 'doc3', 'doc4', 'doc5']
relevant_docs = ['doc2', 'doc4', 'doc6']
# 计算精确度
precision = calculate_precision(retrieved_docs, relevant_docs)
print(f"精确度:{precision:.2f}")
精确度评估的是'系统检索到的所有文档中,有多少实际上是相关的?'
在可能导致负面后果的情况下,精确度尤为重要。例如,在医学信息检索系统中,高精确度至关重要,因为提供不相关的医学文档可能导致错误信息和潜在的有害结果。
召回率衡量了检索到的文档的全面性。它是检索到的相关文档数量与数据库中相关文档的总数之比。
这意味着召回率评估了数据库中存在的相关文档有多少被系统成功检索到。
def calculate_recall(retrieved_docs, relevant_docs):
"""
计算召回率
参数:
retrieved_docs (list): 检索到的文档列表
relevant_docs (list): 相关文档列表
返回:
float: 召回率
"""
# 计算检索到的相关文档数量
relevant_retrieved_docs = [doc for doc in retrieved_docs if doc in relevant_docs]
# 计算召回率
recall = len(relevant_retrieved_docs) / len(relevant_docs) if relevant_docs else 0
return recall
# 示例数据
retrieved_docs = ['doc1', 'doc2', 'doc3', 'doc4', 'doc5']
relevant_docs = ['doc2', 'doc4', 'doc6', 'doc7']
# 计算召回率
recall = calculate_recall(retrieved_docs, relevant_docs)
print(f"召回率:{recall:.2f}")
召回率评估的是'数据库中存在的所有相关文档中,系统成功检索到了多少个?'
在可能错过相关信息会产生成本的情况下,召回率至关重要。例如,在法律信息检索系统中,高召回率至关重要,因为未能检索到相关的法律文件可能导致不完整的案例研究,并可能影响法律诉讼的结果。
通常需要平衡精确度和召回率,因为改善其中一个指标有时会降低另一个指标。目标是找到适合特定应用需求的最佳平衡。这种平衡有时可以用 F1 分数来量化,F1 分数是精确度和召回率的调和平均值。
平均倒数排名(MRR)是一种评估检索系统效果的度量指标,它考虑了第一个相关文档的排名位置。当只有第一个相关文档是主要关注的情况下,MRR 特别有用。倒数排名是第一个相关文档被找到的排名的倒数。MRR 是多个查询的这些倒数排名的平均值。
MRR 评估的是'平均来说,系统多快能够在响应用户查询时检索到第一个相关文档?'
例如,在基于 RAG 的问答系统中,MRR 至关重要,因为它反映了系统能够多快地向用户呈现正确答案。如果正确答案更频繁地出现在列表的顶部,MRR 值将更高,表示检索系统更有效。
平均准确率(MAP)是一种评估多个查询的检索精确度的度量指标。它同时考虑了检索的精确度和检索文档的顺序。MAP 定义为一组查询的平均准确率得分的平均值。
MAP 评估的是'平均来说,系统在多个查询中排名靠前的文档的精确度如何?'
例如,在基于 RAG 的搜索引擎中,MAP 至关重要,因为它考虑了检索的精确度和不同排名的检索结果,确保相关文档在搜索结果中更高地显示,从而通过首先呈现最相关的信息来提高用户体验。
响应评估适用于系统的生成组件。这些评估衡量系统根据检索到的文档提供的上下文有效地生成响应的能力。我们将响应评估分为两种类型:忠实度(基于检索)和答案相关性。
忠实度评估生成的响应是否准确,并且基于检索到的文档。它确保响应不包含幻觉或错误信息。这个度量指标至关重要,因为它将生成的响应追溯到其来源,确保信息基于可验证的真实情况。忠实度有助于防止幻觉,即系统生成听起来合理但事实上不正确的响应。
为了衡量忠实度,通常使用以下方法:
答案相关性衡量生成的响应对用户的查询有多好,并提供有用的信息。
了解了这些评估指标,该如何进行评估,可以先通过使用 LangSmith 进行评估。LangSmith 是一个开发者平台,允许您调试、测试、评估和监控大语言模型 (LLM) 应用程序,并且能够与 LangChain 无缝集成,助您从开发原型顺利过渡到实际生产应用。
在 LLM 任务中,测量准确性的一个挑战来自非结构化文本的影响。问答系统可能生成冗长的响应,使得传统的指标如 BLEU 或 ROUGE 变得不可靠。在这种情况下,使用标注良好的数据集和大语言模型 (LLM) 辅助评估器可以帮助您评估系统的响应质量。
针对一个 RAG 系统进行评估,主要步骤如下:
第一步:获取一个 LangChain 的 API Key,登录 LangSmith 创建 API key。
第二步:设置以下参数后,LangSmith 会自动进行跟踪管理。
import os
os.environ['LANGCHAIN_TRACING_V2'] = 'true'
os.environ['LANGCHAIN_ENDPOINT'] = 'https://api.smith.langchain.com'
os.environ['LANGCHAIN_API_KEY'] = '<your-api-key>'
os.environ['LANGCHAIN_PROJECT'] = "my project name"
这里整理了三种准备测试数据的方式:数据导入,代码创建和使用 LangSmith 辅助创建。
第一种方法:CSV 文件导入 可以通过后台界面直接上传 CSV 文件作为测试集。
第二种方法:代码创建 下面的代码执行后,也可以在 LangSmith 中新建一个 Retrieval QA Questions 的测试集。
# 问题与答案
examples = [
(
"What is LangChain?",
"LangChain is an open-source framework for building applications using large language models. It is also the name of the company building LangSmith.",
),
(
"Can I trace my Llama V2 llm?",
"So long as you are using one of LangChain's LLM implementations, all your calls can be traced",
),
]
# 数据库创建部分
from langsmith import Client
client = Client()
import uuid
dataset_name = f"Retrieval QA Questions {str(uuid.uuid4())}"
dataset = client.create_dataset(dataset_name=dataset_name)
for q, a in examples:
client.create_example(
inputs={"question": q}, outputs={"answer": a}, dataset_id=dataset.id
)
第三种方法:使用 LangSmith 辅助创建 创建的步骤如下:
rag_chain.invoke("Ollama 支持哪些模型?")。测试数据准备好之后,就可以开始对系统进行评估了。LangSmith 的后台可以生成评估的代码。
RAG QA 问答的正确性评估器(Evaluator)包含三个版本:'qa'、'context_qa'、'cot_qa'。
import langsmith
from langchain import chat_models, prompts, smith
from langchain.schema import output_parser
from langchain_community.llms import Ollama
from langchain_community.embeddings import OllamaEmbeddings
import bs4
from langchain import hub
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.document_loaders import WebBaseLoader
from langchain_community.vectorstores import Chroma
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
from langchain_community.document_loaders import UnstructuredHTMLLoader
loader = UnstructuredHTMLLoader("./240327-ollama-20question.html")
docs = loader.load()
text_splitter = RecursiveCharacterTextSplitter(chunk_size=300, chunk_overlap=50)
splits = text_splitter.split_documents(docs)
vectorstore = Chroma.from_documents(documents=splits, embedding=OllamaEmbeddings(model="mofanke/acge_text_embedding"))
retriever = vectorstore.as_retriever()
from langchain.prompts import ChatPromptTemplate
template = """你是一个回答问题的助手。请使用以下检索到的背景信息来回答问题。如果你不知道答案,直接说你不知道。请用最多三句话来保持回答的简洁性。
问题:{question}
背景:{context}
答案:"""
prompt = ChatPromptTemplate.from_template(template)
#llm = chat_models.ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
llm = Ollama(model="qwen:72b", temperature=0)
# Post-processing
def format_docs(docs):
.join(doc.page_content doc docs)
rag_chain = (
{: retriever | format_docs, : RunnablePassthrough()}
| prompt
| llm
| StrOutputParser()
)
rag_chain.invoke()
eval_config = smith.RunEvalConfig(
evaluators=[
],
custom_evaluators=[],
eval_llm=Ollama(model=, temperature=)
)
client = langsmith.Client()
chain_results = client.run_on_dataset(
dataset_name=,
llm_or_chain_factory=rag_chain,
evaluation=eval_config,
project_name=,
concurrency_level=,
verbose=,
)
开发 RAG 系统本身并不困难,但评估 RAG 系统对于性能、实现持续改进、与业务目标保持一致、平衡成本、确保可靠性和适应新方法至关重要。这个全面的评估过程有助于构建强大、高效和以用户为中心的 RAG 系统。建议在实际项目中建立自动化评估流水线,定期监控关键指标的变化,从而确保持续交付高质量的 AI 服务。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online