为什么需要系统化评估
RAG 系统的质量很难凭直觉判断——你看到 LLM 给出了一段流畅的回答,但它可能是编造的,也可能是基于错误的文档片段。没有量化指标,优化就是在黑暗中摸索。
RAG 评估需要覆盖两个维度:
- 检索质量:找到的文档是否真的相关?
- 生成质量:基于文档的答案是否准确、完整、不幻觉?
RAGAS 评估框架
RAGAS
RAG Assessment(检索增强生成评估)框架。用 LLM 自动评估 RAG 管道的各个维度,无需大量人工标注。核心四指标:忠实性、答案相关性、上下文精确率、上下文召回率。
忠实性(Faithfulness)
答案中每个陈述是否可以从检索到的上下文中推断出来。检测幻觉的核心指标。值域 [0, 1],越高越好,< 0.8 通常说明存在严重幻觉问题。
答案相关性(Answer Relevancy)
生成的答案与原始问题的相关程度。通过让 LLM 从答案反推多个可能的问题,计算这些问题与原始问题的语义相似度。
上下文精确率(Context Precision)
检索到的上下文中,有多少比例对生成正确答案是有用的。精确率低说明检索噪声多。
上下文召回率(Context Recall)
参考答案中的每个陈述,有多少比例可以在检索到的上下文中找到依据。召回率低说明重要信息没有被检索到。
RAGAS 快速上手
# pip install ragas langchain-openai
from ragas import evaluate
from ragas.metrics import (
faithfulness,
answer_relevancy,
context_precision,
context_recall,
answer_correctness,
)
from datasets import Dataset
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
# 准备评估数据集
# 格式:问题 + 检索到的上下文 + 生成答案 + 参考答案
eval_data = {
"question": [
"RAG 是什么?",
"Qdrant 使用什么索引算法?",
"文档分块的最佳实践是什么?",
],
"contexts": [
["RAG(检索增强生成)由 Meta AI 于 2020 年提出,解决 LLM 的知识截止和幻觉问题..."],
["Qdrant 使用 HNSW(分层可导航小世界图)作为默认向量索引..."],
["推荐使用递归字符分块,chunk_size=1000,overlap=150..."],
],
"answer": [
"RAG 是检索增强生成,通过在生成前检索相关文档来减少幻觉。",
"Qdrant 默认使用 HNSW 索引。",
"最佳实践是使用递归分块,块大小 1000 字符,重叠 150 字符。",
],
"ground_truth": [
"RAG(检索增强生成)是 Meta AI 于 2020 年提出的技术,结合检索和生成来解决 LLM 幻觉问题。",
"Qdrant 使用 HNSW(分层可导航小世界图)索引算法。",
"推荐使用递归字符分块策略,通用起始参数是 chunk_size=1000, chunk_overlap=150。",
],
}
dataset = Dataset.from_dict(eval_data)
# 配置评估使用的模型
from ragas.llms import LangchainLLMWrapper
from ragas.embeddings import LangchainEmbeddingsWrapper
ragas_llm = LangchainLLMWrapper(ChatOpenAI(model="gpt-4o"))
ragas_emb = LangchainEmbeddingsWrapper(OpenAIEmbeddings())
# 运行评估
result = evaluate(
dataset=dataset,
metrics=[
faithfulness,
answer_relevancy,
context_precision,
context_recall,
answer_correctness,
],
llm=ragas_llm,
embeddings=ragas_emb,
)
print(result)
# 输出示例:
# {'faithfulness': 0.923,
# 'answer_relevancy': 0.951,
# 'context_precision': 0.875,
# 'context_recall': 0.912,
# 'answer_correctness': 0.887}
# 转 DataFrame 查看明细
df = result.to_pandas()
print(df[["question", "faithfulness", "answer_relevancy"]])
自动构建评估数据集
手工标注问答对成本高昂。RAGAS 提供了 Testset Generator,可以从文档自动生成高质量的评估集。
from ragas.testset import TestsetGenerator
from ragas.testset.evolutions import simple, reasoning, multi_context
generator = TestsetGenerator.with_openai(
generator_llm="gpt-4o",
critic_llm="gpt-4o",
embeddings="text-embedding-3-small",
)
# 从文档生成测试集
testset = generator.generate_with_langchain_docs(
documents=docs,
test_size=50, # 生成 50 个问答对
distributions={
simple: 0.5, # 50% 简单问题
reasoning: 0.25, # 25% 推理型问题
multi_context: 0.25 # 25% 需要多文档的问题
}
)
testset_df = testset.to_pandas()
print(testset_df.head())
testset_df.to_csv("rag_testset.csv", index=False)
常见失败模式与诊断
| 失败模式 | 症状(指标) | 根本原因 | 解决方案 |
|---|---|---|---|
| 低忠实性 | Faithfulness < 0.7 | LLM 未遵循上下文,自行编造 | 强化 Prompt 指令;降低 temperature;减少上下文噪声 |
| 低上下文精确率 | Context Precision < 0.7 | 检索噪声多,无关文档被纳入上下文 | 提高相似度阈值;加入 Reranker;改进分块策略 |
| 低上下文召回率 | Context Recall < 0.7 | 相关文档未被检索到 | 增大 top_k;启用混合检索;查询改写扩展覆盖 |
| 低答案相关性 | Answer Relevancy < 0.8 | 答案偏离问题,答非所问 | 改进 Prompt 模板;检查问题理解逻辑 |
| 空检索 | No context found | 查询与文档语义距离远;文档未正确索引 | 降低相似度阈值;检查文档加载;启用查询改写 |
端到端评估流水线
import pandas as pd
from tqdm import tqdm
def run_rag_pipeline(question: str) -> dict:
"""运行 RAG 系统并收集中间结果"""
# 检索
retrieved_docs = retriever.invoke(question)
contexts = [doc.page_content for doc in retrieved_docs]
# 生成
answer = rag_chain.invoke(question)
return {
"question": question,
"contexts": contexts,
"answer": answer,
}
# 批量运行评估集
testset_df = pd.read_csv("rag_testset.csv")
results = []
for _, row in tqdm(testset_df.iterrows(), total=len(testset_df)):
result = run_rag_pipeline(row["question"])
result["ground_truth"] = row["ground_truth"]
results.append(result)
# 用 RAGAS 评估
eval_dataset = Dataset.from_list(results)
scores = evaluate(
eval_dataset,
metrics=[faithfulness, answer_relevancy, context_precision, context_recall]
)
# 保存报告
report_df = scores.to_pandas()
report_df.to_csv("rag_evaluation_report.csv", index=False)
# 打印摘要
print("\n=== RAG 评估报告 ===")
print(f"忠实性: {scores['faithfulness']:.3f}")
print(f"答案相关性: {scores['answer_relevancy']:.3f}")
print(f"上下文精确率:{scores['context_precision']:.3f}")
print(f"上下文召回率:{scores['context_recall']:.3f}")
RAG 调优策略矩阵
| 调优目标 | 优先尝试 | 进阶方案 |
|---|---|---|
| 提升召回率 | 增大 top_k、降低相似度阈值 | 混合检索(BM25+向量)、查询改写、多查询融合 |
| 提升精确率 | 提高相似度阈值、加 Reranker | 父子分块、改进 Embedding 模型、元数据过滤 |
| 减少幻觉 | 强化 Prompt("只基于上下文")、降低 temperature | 引用追踪验证、使用更强 LLM、减少上下文噪声 |
| 提升速度 | 向量量化、减小 top_k | 异步并发检索、缓存高频查询结果 |
| 降低成本 | 换小 LLM(GPT-4o-mini)、减少 top_k | 本地 Embedding 模型、语义缓存(Semantic Cache) |
语义缓存(Semantic Cache)
对相似的查询缓存结果,避免重复调用 LLM,大幅降低成本和延迟。
from langchain.globals import set_llm_cache
from langchain_community.cache import RedisSemanticCache
# 语义缓存:相似问题命中缓存(不需要完全一致)
set_llm_cache(RedisSemanticCache(
redis_url="redis://localhost:6379",
embedding=OpenAIEmbeddings(),
score_threshold=0.95, # 相似度超过 0.95 才命中缓存
))
# 第一次查询:调用 LLM,存入缓存
r1 = rag_chain.invoke("HNSW 索引是什么?")
# 第二次相似查询:直接命中缓存,不调用 LLM
r2 = rag_chain.invoke("HNSW 是什么索引?") # 命中缓存!
print("缓存命中,节省一次 LLM 调用")
持续改进飞轮
建立 RAG 系统的数据飞轮:用户反馈(踩/赞) → 识别失败案例 → RAGAS 专项评估 → 定位问题组件 → 针对性优化 → A/B 测试验证 → 上线新版本 → 继续收集反馈。每一轮迭代都应该有量化指标支撑,避免凭感觉改。
本章总结
- RAGAS 四大指标:忠实性(幻觉)、答案相关性、上下文精确率(噪声)、上下文召回率(覆盖)
- Testset Generator 可以自动从文档生成评估集,降低标注成本
- 常见失败模式都有对应的指标信号,根据指标确定优化方向
- 语义缓存是高性价比的成本优化手段,适合查询模式有规律的场景