RAG 评估不再玄学:RAGAS / TruLens 量化你的 RAG 系统
你是否也经历过------RAG 系统上线后,用户反馈"搜出来的东西不对",但你却说不清到底哪里不对、差了多少?本文用 RAGAS + TruLens 两套开源工具,带你从"感觉不准"走向"数据说话"。
一、为什么 RAG 评估这么难?
RAG(Retrieval-Augmented Generation)系统的评估比传统 NLP 任务复杂得多,因为它涉及 三个环节的联动:
| 环节 | 核心问题 | 评估难点 |
|---|---|---|
| 检索(Retrieval) | 召回的文档对不对、全不全? | 需要标注"相关文档"作为 ground truth |
| 增强(Augmentation) | 给 LLM 的上下文是否精炼? | 上下文太长会稀释关键信息,太短会遗漏 |
| 生成(Generation) | 最终回答是否忠实于上下文? | LLM 可能会"编造"(幻觉),或忽略检索到的信息 |
传统做法是人工打分,但效率低、主观性强、不可复现。本文将介绍两套开源方案,用 定量指标 替代人工直觉:
- RAGAS:专为 RAG 设计的评估框架,8 大指标覆盖检索+生成全链路
- TruLens:基于"RAG 三角"的评估范式,支持自定义反馈函数
二、RAGAS:RAG 专用评估框架
RAGAS(R etrieval A ugmented G eneration Assessment)是目前最成熟的 RAG 评估开源工具,由 Exploding Gradients 团队维护,截至 2026 年 6 月 GitHub Star 已超过 18k。
2.1 RAGAS 的 8 大核心指标
┌─────────────────────────────────────────────────────┐
│ RAGAS 指标体系 │
├─────────────────┬───────────────────────────────────┤
│ 检索端 (4个) │ 生成端 (4个) │
├─────────────────┼───────────────────────────────────┤
│ Context Precision│ Faithfulness (忠实度) │
│ Context Recall │ Answer Relevancy (答案相关性) │
│ Context Relevancy│ Answer Correctness (答案正确性) │
│ Context Entities │ Answer Similarity (答案相似度) │
│ Recall (实体召回) │ │
└─────────────────┴───────────────────────────────────┘
检索端指标详解
① Context Precision(上下文精确率)
衡量检索到的上下文中,有多少是真正相关的。核心逻辑:相关文档在上下文中排得越靠前,得分越高。
Context Precision = (相关文档在结果中的加权排名) / 理想排名
② Context Recall(上下文召回率)
衡量 ground truth 答案所需的信息,是否都被检索到了。需要将 ground truth 拆成若干"原子陈述句"(atomic claims),逐一检查是否能在上下文中找到依据。
Context Recall = |能在上下文中找到依据的原子句| / |ground truth 所有原子句|
③ Context Relevancy(上下文相关性)
衡量检索到的文档中,有多少句子与回答问题直接相关。无关句子越多,分数越低。
④ Context Entities Recall(上下文实体召回率)
衡量 ground truth 中出现的关键实体,有多少在检索到的上下文中出现了。对知识密集型场景(如医疗、法律)尤为重要。
生成端指标详解
⑤ Faithfulness(忠实度/保真度)
衡量 LLM 生成的答案是否完全基于提供的上下文,有没有"编造"内容。
Faithfulness = (答案中可以追溯到上下文的主张数) / (答案中的所有主张数)
这是对抗幻觉的核心指标,也是最难评的指标之一------它需要把答案拆成主张(claims),再逐一验证。
⑥ Answer Relevancy(答案相关性)
衡量生成的答案是否切题、是否直接回答了用户问题。不相关但正确的内容也会被扣分。
⑦ Answer Correctness(答案正确性)
将生成的答案与 ground truth 做语义匹配,计算事实层面的准确度。需要标注 ground truth 答案。
⑧ Answer Similarity(答案相似度)
基于语义向量计算生成答案与 ground truth 的余弦相似度,是最基础的评估方式。
2.2 快速上手:评测你的 RAG 系统
安装
bash
pip install ragas langchain-openai langchain-community
准备评测数据
RAGAS 的标准输入格式是一个包含以下字段的 Dataset:
python
from datasets import Dataset
eval_data = {
"question": [
"什么是 Transformer 架构中的自注意力机制?",
"RAG 系统中的 chunk size 如何选择?",
"向量数据库和传统数据库有什么区别?"
],
"answer": [
"自注意力机制是 Transformer 的核心组件,它允许模型在处理每个词时关注输入序列中的所有其他词...",
"chunk size 的选择需要在语义完整性和检索精度之间做权衡,通常推荐 256-512 tokens...",
"向量数据库专门用于存储和检索高维向量,支持近似最近邻搜索,而传统数据库基于精确匹配..."
],
"contexts": [
[
"Transformer 架构由 Vaswani 等人在 2017 年提出,核心创新是自注意力机制...",
"自注意力计算每个词与所有词之间的注意力权重,从而实现全局依赖建模..."
],
[
"chunk size 是 RAG 系统中最关键的参数之一。过小的 chunk 会丢失上下文,过大会降低检索精度...",
"根据实验,256-512 tokens 的 chunk size 在大多数场景下效果最优..."
],
[
"向量数据库如 Faiss、Milvus、Qdrant 专为高维向量检索设计...",
"传统关系型数据库如 MySQL、PostgreSQL 基于精确匹配..."
]
],
"ground_truth": [
"自注意力机制允许输入序列中的每个位置都与其他所有位置建立直接的关联...",
"chunk size 一般推荐 256-512 tokens,需根据文档类型和任务调整...",
"向量数据库使用 ANN 算法支持语义搜索,传统数据库基于关键词精确匹配..."
]
}
dataset = Dataset.from_dict(eval_data)
运行评测
python
from ragas import evaluate
from ragas.metrics import (
faithfulness,
answer_relevancy,
context_precision,
context_recall,
context_relevancy,
)
from langchain_openai import ChatOpenAI
# 使用 LLM 作为评判器(Judge)
llm = ChatOpenAI(model="gpt-4o", temperature=0)
# 选择要评估的指标
metrics = [
faithfulness,
answer_relevancy,
context_precision,
context_recall,
context_relevancy,
]
# 执行评估
result = evaluate(
dataset=dataset,
metrics=metrics,
llm=llm,
)
# 查看结果
print(result)
# 输出示例:
# {
# 'faithfulness': 0.8921,
# 'answer_relevancy': 0.7845,
# 'context_precision': 0.7562,
# 'context_recall': 0.8123,
# 'context_relevancy': 0.7234,
# }
结果解读
| 指标 | 分数 | 评级 | 说明 |
|---|---|---|---|
| faithfulness | 0.89 | 良好 | 答案基本忠实于上下文,幻觉较少 |
| answer_relevancy | 0.78 | 一般 | 答案有时偏离问题核心,需要优化 prompt |
| context_precision | 0.76 | 一般 | 检索结果中有 24% 不相关文档混入 |
| context_recall | 0.81 | 良好 | 大部分关键信息已召回,但还有遗漏 |
| context_relevancy | 0.72 | 需改进 | 检索文档中约 28% 内容与问题无关 |
2.3 RAGAS 的 LLM-as-Judge 原理
RAGAS 的很多指标依赖 LLM 作为评判器,核心流程如下:
1. 指标定义 → 构造 Prompt
├─ Faithfulness: "以下答案中的每个主张是否可以在上下文中找到依据?"
├─ Answer Relevancy: "以下答案是否直接回答了用户的问题?"
└─ ...
2. LLM 评判 → 提取结构化输出
├─ Faithfulness: 返回每个 claim 的判定 (Yes/No)
└─ Answer Relevancy: 返回相关性分数 (0-1)
3. 聚合计算 → 最终分数
├─ Faithfulness = (Yes 数量) / (总 claim 数量)
└─ ...
关键注意事项:
- 评判 LLM 的选择直接影响评估质量(推荐 GPT-4o 或同等级别模型)
- 设置
temperature=0确保结果一致性 - 可以用开源模型替代,但评估准确度会下降
2.4 构建自动化评估流水线
python
import json
from datetime import datetime
from ragas import evaluate
from ragas.metrics import faithfulness, answer_relevancy, context_precision, context_recall
class RAGEvaluator:
"""RAG 系统自动化评估器"""
def __init__(self, llm, metrics=None):
self.llm = llm
self.metrics = metrics or [
faithfulness, answer_relevancy,
context_precision, context_recall
]
self.history = []
def evaluate_single(self, question, answer, contexts, ground_truth=None):
"""单条评测"""
data = {
"question": [question],
"answer": [answer],
"contexts": [contexts],
}
if ground_truth:
data["ground_truth"] = [ground_truth]
dataset = Dataset.from_dict(data)
result = evaluate(dataset, metrics=self.metrics, llm=self.llm)
return result
def evaluate_batch(self, test_cases, save_path=None):
"""批量评测并保存"""
dataset = Dataset.from_dict({
"question": [tc["question"] for tc in test_cases],
"answer": [tc["answer"] for tc in test_cases],
"contexts": [tc["contexts"] for tc in test_cases],
"ground_truth": [tc.get("ground_truth", "") for tc in test_cases],
})
result = evaluate(dataset, metrics=self.metrics, llm=self.llm)
# 保存评测历史
record = {
"timestamp": datetime.now().isoformat(),
"num_cases": len(test_cases),
"metrics": result,
}
self.history.append(record)
if save_path:
with open(save_path, "w", encoding="utf-8") as f:
json.dump(self.history, f, ensure_ascii=False, indent=2)
return result
def compare_versions(self, v1_result, v2_result):
"""对比两个版本的评估结果"""
print("│ 指标 │ v1 │ v2 │ 变化 │")
print("├───────────────────┼────────┼────────┼────────┤")
for metric in v1_result:
v1_val = v1_result[metric]
v2_val = v2_result.get(metric, "N/A")
if isinstance(v1_val, (int, float)) and isinstance(v2_val, (int, float)):
delta = v2_val - v1_val
arrow = "↑" if delta > 0 else "↓" if delta < 0 else "→"
print(f"│ {metric:<18}│ {v1_val:.4f} │ {v2_val:.4f} │ {arrow}{abs(delta):.4f} │")
三、TruLens:RAG 三角评估法
TruLens 是 TruEra 开源的 LLM 应用评估与可观测性工具,截止 2026 年 6 月 GitHub Star 超过 6k。它对 RAG 系统提出了独特的"RAG 三角"评估范式。
3.1 RAG 三角:Answer / Context / Groundedness
Answer Relevancy
(答案是否切题?)
▲
/ \
/ \
/ \
/ RAG \
/ 三角 \
/ \
/ \
▼ ▼
Context Relevancy Groundedness
(检索内容是否相关?) (答案是否有据可查?)
TruLens 将 RAG 质量拆解为三个正交维度:
| 维度 | 评估函 | 核心问题 | 低分意味着 |
|---|---|---|---|
| Answer Relevancy | feedback_answer_relevance |
答案是否回答了用户问题? | 答非所问 |
| Context Relevancy | feedback_context_relevance |
检索到的文档与问题相关吗? | 检索质量差 |
| Groundedness | feedback_groundedness |
答案中的每句话都能在上下文中找到支撑吗? | 出现幻觉 |
这三个指标共同形成一个平衡三角------任何一个角度的短板都会拖累整体 RAG 体验。
3.2 快速上手
安装
bash
pip install trulens-eval langchain-openai
定义反馈函数
python
from trulens_eval import Feedback, Tru
from trulens_eval.feedback.provider.openai import OpenAI
# 初始化 TruLens
tru = Tru()
# 使用 OpenAI 作为反馈提供者
provider = OpenAI(model_engine="gpt-4o")
# 定义三个反馈函数(RAG 三角)
f_answer_relevance = Feedback(
provider.relevance_with_cot_reasons,
name="Answer Relevancy"
).on_input_output()
f_context_relevance = Feedback(
provider.context_relevance_with_cot_reasons,
name="Context Relevancy"
).on_input().on(TruRag.select_context())
f_groundedness = Feedback(
provider.groundedness_measure_with_cot_reasons,
name="Groundedness"
).on(TruRag.select_context()).on_output()
包装你的 RAG 应用
python
from trulens_eval import TruRag
class SimpleRAG:
"""一个简单的 RAG 示例应用"""
def __init__(self, retriever, llm):
self.retriever = retriever
self.llm = llm
@TruRag.method # 标记为需要追踪的方法
def retrieve(self, query: str):
"""检索相关文档"""
docs = self.retriever.get_relevant_documents(query)
return [doc.page_content for doc in docs]
def generate(self, query: str, contexts: list[str]):
"""基于上下文生成答案"""
prompt = f"""基于以下上下文回答问题。如果上下文不包含答案,请说明。
上下文:
{'---'.join(contexts)}
问题:{query}
答案:"""
return self.llm.invoke(prompt).content
def query(self, query: str):
"""完整的 RAG 流水线"""
contexts = self.retrieve(query)
answer = self.generate(query, contexts)
return answer, contexts
# 包装应用(TruRag 会自动追踪 retrieve + generate)
rag_app = SimpleRAG(retriever=my_retriever, llm=my_llm)
tru_rag = TruRag(
rag_app,
app_name="MyRAGApp",
app_version="v1.0",
feedbacks=[f_answer_relevance, f_context_relevance, f_groundedness]
)
运行评测
python
# 准备测试问题
test_questions = [
"Transformer 的自注意力机制是如何工作的?",
"RAG 系统中 chunk size 的最佳实践是什么?",
"向量数据库相比传统数据库有什么优势?",
]
# 逐条评测
with tru_rag as recorder:
for question in test_questions:
answer, contexts = rag_app.query(question)
# 启动 Dashboard 查看结果
tru.run_dashboard()
# 浏览器打开 http://localhost:8501
3.3 TruLens Dashboard 实战解读
运行 tru.run_dashboard() 后,你会看到:
① 概览页面
- 每个问题的 Answer Relevancy / Context Relevancy / Groundedness 分数
- 颜色标识:绿色(高) → 黄色(中) → 红色(低)
- 平均分趋势图(适合对比不同版本)
② 逐条分析
- 点击任意问题,查看详细的 Chain-of-Thought 评判理由
- 例如 Groundedness 低时,会显示具体哪句话在上下文中找不到依据
③ 版本对比
- 修改 RAG 参数(chunk size / embedding 模型 / top-k)后重新评测
- Dashboard 自动展示版本间分数变化
3.4 TruLens 的高级功能
自定义反馈函数
python
from trulens_eval import Feedback
# 基于规则的反馈:检查答案长度是否合理
def answer_length_check(output: str) -> float:
"""答案长度应在 50-500 字之间"""
length = len(output)
if 50 <= length <= 500:
return 1.0
elif length < 20:
return 0.2 # 太短
else:
return 0.7 # 稍长但可接受
f_length = Feedback(answer_length_check, name="Answer Length").on_output()
# 基于关键词的反馈:检查是否包含引用
def has_citation(output: str) -> float:
"""检查答案是否包含引用标记"""
import re
if re.search(r'\[[\d,\s]+\]|参考|来源', output):
return 1.0
return 0.0
f_citation = Feedback(has_citation, name="Has Citation").on_output()
# 组合多个反馈函数
feedbacks = [
f_answer_relevance,
f_context_relevance,
f_groundedness,
f_length,
f_citation,
]
与 LangChain / LlamaIndex 集成
python
# LangChain 集成
from trulens_eval import TruChain
tru_chain = TruChain(
your_langchain_rag_chain,
app_name="LangChainRAG",
feedbacks=feedbacks,
)
# LlamaIndex 集成
from trulens_eval import TruLlama
tru_llama = TruLlama(
your_llamaindex_query_engine,
app_name="LlamaIndexRAG",
feedbacks=feedbacks,
)
四、RAGAS vs TruLens:如何选择?
| 对比维度 | RAGAS | TruLens |
|---|---|---|
| 指标丰富度 | ⭐⭐⭐⭐⭐ 8+ 指标,覆盖全面 | ⭐⭐⭐⭐ RAG 三角 + 自定义 |
| 上手难度 | ⭐⭐⭐ 中等,需要构造 Dataset | ⭐⭐⭐⭐ 简单,函数包装即可 |
| 可视化 | ⭐⭐ 基础(依赖 Matplotlib) | ⭐⭐⭐⭐⭐ 内置 Dashboard |
| 版本对比 | ⭐⭐ 需自行实现 | ⭐⭐⭐⭐ Dashboard 自动对比 |
| LLM 依赖 | ⭐⭐⭐ 部分指标需 LLM-as-Judge | ⭐⭐⭐ 反馈函数大多需 LLM |
| 框架集成 | ⭐⭐⭐⭐ LangChain、LlamaIndex | ⭐⭐⭐⭐⭐ LangChain、LlamaIndex、NeMo |
| 自定义扩展 | ⭐⭐⭐ 支持自定义指标 | ⭐⭐⭐⭐⭐ 反馈函数非常灵活 |
| 生产监控 | ⭐⭐ 偏离线评测 | ⭐⭐⭐⭐ 支持在线追踪 |
| 社区活跃度 | ⭐⭐⭐⭐⭐ 18k+ Star | ⭐⭐⭐⭐ 6k+ Star |
选型建议
| 场景 | 推荐方案 | 理由 |
|---|---|---|
| 快速原型验证 | TruLens | 包装代码即可评测,Dashboard 直观 |
| 深度评估 & 论文报告 | RAGAS | 指标体系严谨,学术认可度高 |
| 日常开发迭代 | TruLens | Dashboard 版本对比,效果一目了然 |
| CI/CD 自动化测试 | RAGAS | 命令行友好,可集成到测试流水线 |
| 生产环境监控 | TruLens | 支持在线追踪,可配置告警 |
| 两者结合 | RAGAS + TruLens | RAGAS 做离线深度评测,TruLens 做在线监控 |
五、实战:构建完整的评估流水线
下面是一个完整的 RAG 评估流水线,结合 RAGAS + TruLens 的优势:
python
import json
from dataclasses import dataclass, field
from typing import List, Dict
from datetime import datetime
from pathlib import Path
@dataclass
class EvalResult:
"""单次评测结果"""
timestamp: str
version: str
ragas_scores: Dict[str, float]
trulens_scores: Dict[str, float]
num_cases: int
notes: str = ""
class RAGPipelineEvaluator:
"""
完整的 RAG 评估流水线:
1. 离线评测(RAGAS):在版本发布前深度评估
2. 在线监控(TruLens):追踪生产环境的持续表现
3. 报告生成:自动汇总评测报告
"""
def __init__(self, output_dir="./eval_results/"):
self.output_dir = Path(output_dir)
self.output_dir.mkdir(parents=True, exist_ok=True)
self.results: List[EvalResult] = []
self.ragas_evaluator = None # 在实际项目中初始化
self.tru_rag = None # 在实际项目中初始化
def run_offline_eval(self, test_dataset, version="v1.0"):
"""离线评测:使用 RAGAS 做深度分析"""
print(f"[RAGAS] 开始离线评测,版本: {version}")
# result = evaluate(test_dataset, metrics=all_metrics, llm=judge_llm)
# 模拟结果
ragas_result = {
"faithfulness": 0.89,
"answer_relevancy": 0.78,
"context_precision": 0.76,
"context_recall": 0.81,
"context_relevancy": 0.72,
"answer_correctness": 0.83,
"answer_similarity": 0.85,
"context_entities_recall": 0.79,
}
return ragas_result
def run_online_monitoring(self, num_samples=100):
"""在线监控:使用 TruLens 追踪实时请求"""
print(f"[TruLens] 开始在线监控,采样数: {num_samples}")
# 从 TruLens 数据库中拉取最近 num_samples 条记录
# 模拟结果
trulens_result = {
"answer_relevancy": 0.82,
"context_relevancy": 0.74,
"groundedness": 0.88,
}
return trulens_result
def generate_report(self):
"""生成评测报告"""
ragas = self.run_offline_eval(None, "v2.0")
trulens = self.run_online_monitoring()
report = f"""
╔══════════════════════════════════════════════════════╗
║ RAG 系统评估报告 ║
║ 生成时间: {datetime.now().isoformat()} ║
╠══════════════════════════════════════════════════════╣
║ ║
║ 📊 RAGAS 离线深度评测 (v2.0) ║
║ ┌──────────────────────┬────────┐ ║
║ │ 指标 │ 分数 │ ║
║ ├──────────────────────┼────────┤ ║
"""
for metric, score in ragas.items():
bar = "█" * int(score * 20)
report += f"║ │ {metric:<21}│ {score:.2f} {bar}│\n"
report += f"""║ └──────────────────────┴────────┘ ║
║ ║
║ 📈 TruLens 在线监控 (最近 100 条) ║
║ ┌──────────────────────┬────────┐ ║
"""
for metric, score in trulens.items():
bar = "█" * int(score * 20)
report += f"║ │ {metric:<21}│ {score:.2f} {bar}│\n"
report += """║ └──────────────────────┴────────┘ ║
║ ║
║ 💡 改进建议: ║
║ 1. Context Relevancy 偏低 → 优化 chunking 策略 ║
║ 2. Answer Relevancy 可提升 → 调整生成 Prompt ║
║ 3. Groundedness 表现良好 → 幻觉控制到位 ║
║ ║
╚══════════════════════════════════════════════════════╝
"""
print(report)
return report
# ================ 使用示例 ================
if __name__ == "__main__":
evaluator = RAGPipelineEvaluator()
evaluator.generate_report()
六、评估最佳实践与避坑指南
6.1 评估数据集的构建
| 坑 | 正确做法 |
|---|---|
| 所有问题都是"What is X?"类型 | 覆盖 What / How / Why / Compare / Yes-No 等多种类型 |
| 只用简单问题测试 | 加入长尾、多跳推理、反事实问题 |
| ground truth 只有一句话 | ground truth 应包含所有关键信息点(用于 Context Recall 计算) |
| 测试集太小(< 30 条) | 建议至少 100+ 条才能有统计意义 |
6.2 LLM-as-Judge 的可靠性
- 使用强模型做评判:GPT-4o 或 Claude 3.5 Sonnet 级别,开源模型评判质量显著下降
- 设置 temperature=0:确保可复现性
- 做一致性检验:同一批数据评两次,检查分数波动
- 人工抽样验证:定期抽取 10-20% 的评测结果做人工复核
6.3 评估频率建议
日常开发:每次修改 RAG 参数后,跑快速评测(TruLens,10-20 条)
周度评审:每周一次深度评测(RAGAS,100+ 条),生成趋势报告
发布前: 完整评测 + 与上一版本对比 + 人工复核
生产环境: TruLens 持续追踪,设置阈值告警(如 Groundedness < 0.7)
6.4 常见误区
| 误区 | 实际情况 |
|---|---|
| "分数越高越好" | 过度优化指标可能导致过拟合评测集,真实场景反而退化 |
| "一个指标就够了" | 单一指标无法反映全貌:高 Faithfulness 可能伴随低 Answer Relevancy |
| "评测完就结束了" | 评测是起点,不是终点------低分项需要驱动系统优化 |
| "自动评测 100% 可靠" | LLM-as-Judge 有固有偏差,定期人工校准不可或缺 |
七、总结
| 要点 | 说明 |
|---|---|
| RAGAS 适合深度评测 | 8 大指标体系完整,学术认可度高,适合离线深度分析和 CI/CD 集成 |
| TruLens 适合快速迭代 | RAG 三角直观易用,Dashboard 可视化友好,适合日常开发和在线监控 |
| 两者互补使用 | RAGAS 做离线深度评测 + TruLens 做在线监控 = 完整的 RAG 质量保障体系 |
| LLM-as-Judge 有局限 | 依赖评判模型质量,需定期人工校准;开源模型评判效果有差距 |
| 评估驱动优化 | 不要为了"刷分"而优化,要结合真实用户反馈做综合判断 |
RAG 评估不再是"感觉不准"的黑箱艺术。借助 RAGAS 和 TruLens 这两套工具,你可以用数据量化每一个优化动作的效果------从 chunk size 调整到 embedding 模型切换,从 prompt 改写到底层检索算法替换,都能看得见、说得清、复现得了。
下一步建议:找一个小型 RAG 项目(50-100 条 QA 对),先用 RAGAS 跑一次 baseline,再用 TruLens 做日常迭代追踪,两周后你会发现------你的 RAG 系统变好了多少,不再靠猜了。
本文是「RAG 技术演进」系列的第 7 篇,前 6 篇涵盖了架构演进、向量库选型、知识图谱增强、文档解析、Reranker 实战和混合检索。下一篇我们将进入 AI Agent 架构与框架的世界。