目录

RAG 评估指南:怎么知道你的 RAG 好不好

你搭了一个 RAG 系统,回答问题,Demo 看起来很好。然后有用户提了一个问题,系统自信地给出了一个错误答案——引用的是一个完全不相关的文档。问题出在哪?你不知道,因为你没有任何量化评估。在 RAG 上线之前,你需要一套评估体系,不然问题只会在生产环境里被用户发现。

RAG 评估的三个核心指标

RAG 系统的质量由三个正交的维度决定:

Faithfulness(忠实度)

问题:模型的回答,是否真的来自检索到的上下文?还是在凭空捏造?

忠实度低 = 幻觉。即使检索到了正确文档,模型也可能「不按文档回答」,编造内容。

评分示意:

  • 高忠实度(> 0.85):回答中每个声明都能在检索文档中找到依据
  • 低忠实度(< 0.6):回答中存在文档中没有的信息

Answer Relevance(回答相关性)

问题:模型的回答,有没有真正回应用户的问题?

可能出现的失败模式:检索到正确文档,但模型回答了文档里的其他内容,没有正面回答用户的问题。

Context Precision(上下文精度)

问题:检索到的文档,有多少是真正有用的?

情况 说明
高 Precision + 低 Recall 检索到的都是对的,但漏了重要文档
低 Precision + 高 Recall 检索了很多,但大多数不相关
高 Precision + 高 Recall 理想状态

工具选型

RAGAS

最成熟的 RAG 评估指标库。直接实现了 Faithfulness、Answer Relevancy、Context Precision 等指标,原生支持 LangChain 和 LlamaIndex。评分基于 LLM-as-Judge,不需要人工标注。

TruLens

评估 + Tracing 二合一框架。可以对 LangChain、LlamaIndex 应用进行端到端追踪,同时实时计算质量指标。适合需要把评估嵌入应用监控的场景。

LLM-as-Judge(自建)

用另一个 LLM 调用评估输出质量,成本可控,灵活度高,但需要精心设计评估 prompt。

实战:用 RAGAS 评估你的 RAG Pipeline

from datasets import Dataset
from ragas import evaluate
from ragas.metrics import (
    faithfulness,
    answer_relevancy,
    context_precision,
    context_recall,
)

# 每条数据需要:问题、生成的答案、检索到的上下文、(可选)标准答案
eval_data = {
    "question": [
        "What is the return policy?",
        "How do I reset my password?",
        "What payment methods are accepted?",
    ],
    "answer": [
        "You can return items within 30 days of purchase.",
        "Click 'Forgot Password' on the login page and follow the email instructions.",
        "We accept Visa, Mastercard, and PayPal.",
    ],
    "contexts": [
        ["Our return policy allows returns within 30 days. Items must be unused."],
        ["To reset your password, click 'Forgot Password' and check your email."],
        ["Accepted payment methods: Visa, Mastercard, American Express, PayPal."],
    ],
    "ground_truth": [
        "Items can be returned within 30 days if unused.",
        "Use the 'Forgot Password' link and follow email instructions.",
        "Visa, Mastercard, American Express, and PayPal are accepted.",
    ],
}

dataset = Dataset.from_dict(eval_data)

result = evaluate(
    dataset,
    metrics=[faithfulness, answer_relevancy, context_precision, context_recall],
)

print(result)
# 输出示例:
# {'faithfulness': 0.92, 'answer_relevancy': 0.88,
#  'context_precision': 0.85, 'context_recall': 0.79}

参考分数线(不同场景会有差异):

指标 合格 良好 优秀
Faithfulness > 0.75 > 0.85 > 0.92
Answer Relevancy > 0.70 > 0.80 > 0.90
Context Precision > 0.65 > 0.80 > 0.90

构建评估数据集

评估的质量取决于数据集的质量。三种构建方式:

合成数据集(最快,适合起步)

用 LLM 从你的语料库自动生成问答对:

from ragas.testset.generator import TestsetGenerator
from ragas.testset.evolutions import simple, reasoning, multi_context

generator = TestsetGenerator.with_openai()
testset = generator.generate_with_langchain_docs(
    documents,       # 你的知识库文档
    test_size=50,    # 生成 50 个问答对
    distributions={
        simple: 0.5,         # 50% 简单问题
        reasoning: 0.3,      # 30% 推理问题
        multi_context: 0.2,  # 20% 多文档问题
    },
)

人工标注数据集(最准确,适合关键场景)

  • 由领域专家手工编写问题和标准答案
  • 成本高,但质量最可靠
  • 建议至少准备 20 条「黄金问答」覆盖核心场景

生产数据采样(最接近真实,需要隐私处理)

从生产流量中随机采样真实用户问题,人工标注:

sampled_queries = (
    db.query(ProductionTrace)
    .filter(ProductionTrace.date >= "2024-01-01")
    .order_by(func.random())
    .limit(100)
    .all()
)

for q in sampled_queries:
    print(f"Q: {q.user_query}")
    print(f"A: {q.model_response}")
    print("---")

最小可行数据集:50 个问答对足以起步。其中至少包含:

  • 10 个核心场景的「应该能回答好」的问题
  • 10 个「答案不在语料库里」的问题(测试模型是否知道说不知道)
  • 10 个需要跨多个文档综合的问题

持续评估:CI 里跑 RAG 评分

每次改动检索参数(embedding 模型、chunk size、top-k)都应该跑一次评估:

# evaluate_rag.py — 在 CI 中运行
import sys
from ragas import evaluate
from ragas.metrics import faithfulness, answer_relevancy

THRESHOLDS = {
    "faithfulness": 0.80,
    "answer_relevancy": 0.75,
}

def run_evaluation(dataset):
    result = evaluate(dataset, metrics=[faithfulness, answer_relevancy])

    failed = []
    for metric, threshold in THRESHOLDS.items():
        score = result[metric]
        status = "✅" if score >= threshold else "❌"
        print(f"{status} {metric}: {score:.3f} (threshold: {threshold})")
        if score < threshold:
            failed.append(metric)

    if failed:
        print(f"\nFailed metrics: {failed}")
        sys.exit(1)  # CI 失败

if __name__ == "__main__":
    dataset = load_eval_dataset("eval_dataset.json")
    run_evaluation(dataset)
# .github/workflows/rag-eval.yml
name: RAG Evaluation
on:
  push:
    paths:
      - "rag/**"
      - "embeddings/**"
jobs:
  evaluate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Run RAG evaluation
        run: python evaluate_rag.py
        env:
          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}

常见失败模式

理解常见失败模式能帮你更快定位问题:

检索失败(Retrieval Failure)

症状:Context Precision 低,但语料库里有正确答案。

原因

  • Chunk size 太大或太小,把关键信息切断了
  • Embedding 模型对领域词汇不理解(通用模型 vs 领域模型)
  • Top-k 太小,正确文档没被召回

排查方法:用已知答案的问题,检查检索到的 top-5 文档,看正确文档排在第几位。

生成失败(Generation Failure)

症状:Context Precision 高,但 Faithfulness 低——正确文档检索到了,但模型没有按文档回答。

原因

  • 上下文太长,模型「忘记」了关键部分(Long Context Forgetting)
  • Prompt 指令不够明确,没有要求模型严格基于上下文
  • 模型本身的幻觉倾向(小模型问题更严重)

修复:在 System Prompt 中明确加入「只基于提供的上下文回答,如果上下文中没有答案,请说不知道」。

覆盖失败(Coverage Failure)

症状:用户问了一个答案确实不在语料库里的问题,但模型没有说「不知道」,而是编造了答案。

防护:在评估集中加入「超出范围的问题」,测试模型是否能正确拒绝回答。

延伸阅读