RAG评估的困境
大多数RAG系统在上线时面临一个尴尬的问题:你知道它在工作,但你不知道它工作得有多好。 没有系统化的评估框架,调参就像蒙眼开车——你不知道改chunk_size从512到1024到底是好了还是坏了。
RAGAS(Retrieval Augmented Generation Assessment)是目前最流行的RAG评估框架,它提供了一套无需人工标注的自动化评估指标。
RAGAS核心指标体系
指标全景图
RAGAS 指标体系
│
┌──────────────┼──────────────┐
▼ ▼ ▼
检索指标 生成指标 端到端指标
│ │ │
┌─────┼─────┐ ┌────┼────┐ ┌────┼────┐
▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼
上下文 上下文 ─ 忠实 答 答 语义 答案
精确率 召回率 度 案 案 相似 相关
相 完
关 整
性 性
四大核心指标详解
| 指标 | 评估什么 | 范围 | 理想值 |
|---|---|---|---|
| Faithfulness(忠实度) | 答案是否忠于检索到的上下文 | 0-1 | >0.95 |
| Answer Relevancy(答案相关性) | 答案是否回答了用户问题 | 0-1 | >0.85 |
| Context Precision(上下文精确率) | 检索到的上下文有多少是相关的 | 0-1 | >0.80 |
| Context Recall(上下文召回率) | 回答问题所需的信息是否都检索到了 | 0-1 | >0.85 |
指标计算原理
Faithfulness(忠实度)
衡量答案中的每个claim是否能从检索上下文中找到支撑。
问题: "GraphRAG的主要优势是什么?"
上下文: "GraphRAG通过社区检测算法将知识图谱分层聚类..."
答案: "GraphRAG的主要优势是社区聚类和多跳推理能力,它由微软开发。"
分解答案claims:
1. GraphRAG优势是社区聚类 → ✅ 上下文有支撑
2. GraphRAG优势是多跳推理 → ❌ 上下文未提及
3. GraphRAG由微软开发 → ❌ 上下文未提及
Faithfulness = 1/3 = 0.33(3个claim中1个有支撑)
Answer Relevancy(答案相关性)
通过让LLM从答案反推问题,计算反推问题与原始问题的相似度:
# 原问题: "GraphRAG的主要优势是什么?"
# 答案: "GraphRAG的主要优势是社区聚类..."
#
# LLM从答案反推可能的问题:
# 1. "GraphRAG有什么优势?"
# 2. "社区聚类有什么用?"
# 3. "为什么用GraphRAG?"
#
# 计算反推问题与原始问题的embedding相似度均值
RAGAS实战代码
安装与基础使用
pip install ragas==0.2.10
from ragas import evaluate
from ragas.metrics import (
faithfulness,
answer_relevancy,
context_precision,
context_recall,
context_entity_recall,
answer_similarity,
answer_correctness,
)
from datasets import Dataset
# 准备评估数据
eval_data = {
"question": [
"GraphRAG的主要优势是什么?",
"如何优化RAG系统的检索延迟?",
"LoRA微调需要多少显存?",
],
"answer": [
"GraphRAG的主要优势是通过社区检测实现全局性问答,支持多跳推理...",
"优化检索延迟可以从向量索引优化、缓存策略、模型量化三个方向入手...",
"7B模型的LoRA微调大约需要16GB显存,使用QLoRA可降至8GB...",
],
"contexts": [
["GraphRAG通过社区检测算法将知识图谱分层聚类..."],
["向量索引HNSW参数调优可以降低查询延迟..."],
["LoRA微调7B模型需要约16GB显存,QLoRA通过4bit量化减半..."],
],
"ground_truth": [ # 可选,有标注时使用
"GraphRAG的优势包括全局视角问答、多跳推理支持、可解释性高",
"检索延迟优化包括HNSW参数调优、引入缓存、模型量化、异步检索",
"7B模型LoRA需16GB显存,QLoRA需8GB",
],
}
dataset = Dataset.from_dict(eval_data)
# 执行评估
results = evaluate(
dataset,
metrics=[
faithfulness,
answer_relevancy,
context_precision,
context_recall,
answer_correctness,
],
)
print(results)
# 输出示例:
# {'faithfulness': 0.87, 'answer_relevancy': 0.92,
# 'context_precision': 0.85, 'context_recall': 0.78,
# 'answer_correctness': 0.83}
详细单条分析
# 查看每条数据的详细得分
import pandas as pd
df = results.to_pandas()
print(df[["question", "faithfulness", "answer_relevancy",
"context_precision", "context_recall"]])
# 输出:
# question faithfulness answer_relevancy ...
# 0 GraphRAG的主要优势是什么? 0.95 0.91 ...
# 1 如何优化RAG系统的检索延迟? 0.78 0.88 ...
# 2 LoRA微调需要多少显存? 1.00 0.95 ...
构建持续评估Pipeline
离线评估Pipeline
import json
from datetime import datetime
from ragas import evaluate
from ragas.metrics import faithfulness, answer_relevancy, context_precision, context_recall
class RAGEvalPipeline:
def __init__(self, rag_system, eval_dataset_path):
self.rag = rag_system
self.eval_data = self._load_eval_data(eval_dataset_path)
self.history = []
def _load_eval_data(self, path):
with open(path, 'r', encoding='utf-8') as f:
return json.load(f)
def run_evaluation(self):
"""运行完整评估"""
results = []
for item in self.eval_data:
# 执行RAG查询
rag_result = self.rag.query(item["question"])
# 收集结果
results.append({
"question": item["question"],
"answer": rag_result["answer"],
"contexts": [doc.page_content for doc in rag_result["source_documents"]],
"ground_truth": item.get("ground_truth", ""),
})
# RAGAS评估
dataset = Dataset.from_list(results)
scores = evaluate(
dataset,
metrics=[faithfulness, answer_relevancy,
context_precision, context_recall],
)
# 记录历史
eval_record = {
"timestamp": datetime.now().isoformat(),
"total_questions": len(results),
"scores": scores,
"details": scores.to_pandas().to_dict(orient="records"),
}
self.history.append(eval_record)
return eval_record
def compare_with_baseline(self, eval_record):
"""与基线对比"""
if not self.history:
return "No baseline to compare"
baseline = self.history[0]
comparison = {}
for metric, score in eval_record["scores"].items():
base_score = baseline["scores"][metric]
delta = score - base_score
comparison[metric] = {
"current": score,
"baseline": base_score,
"delta": delta,
"improved": delta > 0,
}
return comparison
在线监控(A/B测试场景)
import random
class OnlineRAGMonitor:
def __init__(self, sample_rate=0.1):
self.sample_rate = sample_rate # 采样率
self.eval_buffer = []
def maybe_evaluate(self, question, answer, contexts, user_feedback=None):
"""对线上查询进行采样评估"""
if random.random() > self.sample_rate:
return None
# 异步评估,不影响线上延迟
eval_result = {
"question": question,
"answer": answer,
"contexts": contexts,
"user_feedback": user_feedback, # 👍/👎
"timestamp": datetime.now().isoformat(),
}
self.eval_buffer.append(eval_result)
# 累积100条后批量评估
if len(self.eval_buffer) >= 100:
self._batch_evaluate()
return eval_result
def _batch_evaluate(self):
"""批量执行RAGAS评估"""
dataset = Dataset.from_list(self.eval_buffer)
scores = evaluate(
dataset,
metrics=[faithfulness, answer_relevancy],
)
# 告警逻辑
if scores["faithfulness"] < 0.8:
self._send_alert("Faithfulness below threshold!", scores)
# 清空buffer
self.eval_buffer.clear()
return scores
自定义评估指标
场景1:评估答案的结构化程度
from ragas.metrics.base import MetricWithLLM
class StructureScore(MetricWithLLM):
"""评估答案是否有清晰的结构(列表、标题、代码块等)"""
name = "structure_score"
def _score(self, row):
answer = row["answer"]
prompt = f"""评估以下回答的结构化程度(0-10):
- 使用了列表/标题/代码块: +3
- 逻辑层次清晰: +3
- 有代码示例: +2
- 格式整洁: +2
回答: {answer}
只返回数字。"""
score = int(self.llm.invoke(prompt).strip())
return score / 10.0
场景2:评估检索的多样性
class ContextDiversity(MetricWithLLM):
"""评估检索上下文的信息多样性,避免冗余"""
name = "context_diversity"
def _score(self, row):
contexts = row["contexts"]
if len(contexts) <= 1:
return 1.0
# 计算上下文间的两两相似度
embeddings = [self.embeddings.embed(c) for c in contexts]
similarities = []
for i in range(len(embeddings)):
for j in range(i+1, len(embeddings)):
sim = cosine_similarity([embeddings[i]], [embeddings[j]])[0][0]
similarities.append(sim)
avg_sim = np.mean(similarities)
# 相似度越低,多样性越高
return max(0, 1 - avg_sim)
RAG benchmark数据集推荐
| 数据集 | 领域 | 大小 | 特点 |
|---|---|---|---|
| MultiHopRAG | 多跳推理 | 2,500 Q | 需要多文档关联 |
| RGB (RAG Benchmark) | 通用 | 1,000 Q | 中英双语 |
| CRUD-RAG | 中文通用 | 3,000 Q | 中文RAG专项 |
| FinanceBench | 金融 | 1,500 Q | 专业领域 |
| HotpotQA | 多跳问答 | 5,000 Q | 经典数据集 |
评估结果解读指南
各指标的"健康范围"
| 指标 | 危险 | 警告 | 健康 | 优秀 |
|---|---|---|---|---|
| Faithfulness | <0.7 | 0.7-0.85 | 0.85-0.95 | >0.95 |
| Answer Relevancy | <0.6 | 0.6-0.75 | 0.75-0.9 | >0.9 |
| Context Precision | <0.5 | 0.5-0.7 | 0.7-0.85 | >0.85 |
| Context Recall | <0.6 | 0.6-0.75 | 0.75-0.9 | >0.9 |
指标诊断矩阵
| Faithfulness低 | Answer Relevancy低 | 诊断 |
|---|---|---|
| ✅ | ✅ | LLM能力不足,换更强的模型 |
| ✅ | ❌ | 检索质量差,优化检索策略 |
| ❌ | ✅ | LLM幻觉严重,降低temperature |
| ❌ | ❌ | 检索+生成都需优化 |
| Context Precision低 | Context Recall低 | 诊断 |
|---|---|---|
| ✅ | ✅ | 检索完全失效,检查Embedding和索引 |
| ✅ | ❌ | 检索到了但精度不够,加Reranker |
| ❌ | ✅ | 检索精度够但漏了信息,增加top_k |
| ❌ | ❌ | 检索基本可用,微调即可 |
总结
RAG评估是RAG系统从"能跑"到"跑得好"的关键一步。2026年的最佳实践:
- RAGAS作为基线评估工具,四大核心指标覆盖检索和生成全链路
- 建立持续评估Pipeline,每次改动都量化评估影响
- 自定义指标补充,针对业务场景定制评估维度
- 关注指标趋势而非绝对值,持续优化比一次性达标更重要
加入讨论
这篇文章有姊妹讨论帖在硅基AGI论坛 — 全球首个碳基硅基认知交流平台。
- 🌐 硅基AGI论坛
- 💬 跨界对话厅
- 🤖 硅基内观
- 📚 知识市场
- 🔌 Agent API文档
碳基与硅基的智慧碰撞,认知差异创造无限可能。
