大模型 RAG 评估实战:用 RAGAS 搭建企业级评测体系,别再凭感觉选方案了

阿里云上云采购季 2核2G云服务器99元/年 续费同价

你的 RAG 系统真的靠谱吗?3 个核心指标 + 完整评测代码,让效果说话。

做了半年 RAG,我问自己一个扎心的问题:我凭什么说我的 RAG 系统比别人的好?

大多数人的回答是「感觉还行」「用户反馈不错」。但这在老板面前根本站不住脚,更别说你要在 DeepSeek、通义千问、百川等十几个模型之间做选型了。

今天我用 RAGAS(一个专门给 RAG 打分的开源框架),手把手搭一套可量化的评测体系。

为什么你的 RAG 需要「考试」?

RAG 系统由检索 + 生成两段组成,传统评测只看「最终答案对不对」,完全忽略了中间环节的问题:

问题 后果 怎么发现
检索回来的文档不相关 大模型基于错误信息回答 检索相关性低
大模型自己编造内容 生成幻觉,用户被误导 忠实度低
文档相关但答案不完整 答非所问,用户不满意 答案相关性低
文档冗余/噪音太多 浪费Token,干扰模型 上下文精度低

RAGAS 就干一件事:把这些「手感」变成数字。

3 个核心指标,这次彻底讲清楚

RAGAS 评测指标分两部分:

检索阶段

指标 含义 理想值
Context Precision(上下文精度) 检索回来的文档中有多少是真正相关的 >0.8
Context Recall(上下文召回率) 应该检索到的文档中实际检索到了多少 >0.8

生成阶段

指标 含义 理想值
Faithfulness(忠实度) 生成内容有多少是基于检索文档的(不是编的) >0.9
Answer Relevancy(答案相关性) 答案是否真的回答了问题 >0.8
Answer Correctness(答案正确性) 答案是否事实正确 >0.8

还有一个重量级指标:Answer Similarity(语义相似度),用来和标准答案做对比。

5 步搭建评测流水线(完整代码)

第一步:安装依赖

pip install ragas langchain langchain-openai chromadb pandas datasets

第二步:准备测试数据集

# test_dataset.py - 准备评测数据
from datasets import Dataset

# 评测数据集:问题 + 标准答案
eval_data = {
    "question": [
        "什么是RAG?它解决了什么问题?",
        "向量数据库在大模型中起什么作用?",
        "Chunking策略对RAG性能有什么影响?",
        "如何减少大模型的幻觉问题?",
        "Embedding模型选型有什么注意事项?",
    ],
    "ground_truth": [
        "RAG(Retrieval-Augmented Generation)是一种将信息检索与大语言模型结合的架构,通过先检索外部知识库再生成回答,解决大模型知识滞后和幻觉问题。",
        "向量数据库用于存储和检索文档的向量表示,在大模型中负责高效地找到与用户问题最相关的上下文片段,是RAG系统的核心组件。",
        "Chunking策略直接影响检索精度:chunk太大则检索相关性下降,太小则上下文不完整。合理的chunk大小通常在512-1024 tokens之间。",
        "减少幻觉的方法包括:使用RAG架构提供事实依据、设置较低的temperature参数、在prompt中明确要求引用来源、使用RLHF对齐训练。",
        "Embedding模型选型需考虑:向量维度、支持的最大token长度、多语言支持、检索精度(MTEB榜单排名)、推理成本和速度。",
    ],
}

eval_dataset = Dataset.from_dict(eval_data)
print(f"评测数据集包含 {len(eval_dataset)} 条记录")

第三步:构建 RAG 链(待评测对象)

# rag_chain.py - 构建待评测的RAG系统
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_chroma import Chroma
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.document_loaders import TextLoader

# 加载文档(这里用你实际的知识库文件)
loader = TextLoader("./knowledge_base.txt", encoding="utf-8")
documents = loader.load()

# 文档分块
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=512,      # 每块512字符
    chunk_overlap=50,    # 重叠50字符
    separators=["\n\n", "\n", "。", ",", " ", ""]
)
docs = text_splitter.split_documents(documents)
print(f"切割后文档块数: {len(docs)}")

# 构建向量数据库(使用 ChromaDB)
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
vectorstore = Chroma.from_documents(
    documents=docs,
    embedding=embeddings,
    persist_directory="./chroma_db"
)

# 检索器
retriever = vectorstore.as_retriever(
    search_type="similarity",  # 可选 "mmr" 增加多样性
    search_kwargs={"k": 4}     # 每次返回4个最相关文档
)

# 大模型
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)

第四步:运行 RAGAS 评测

# run_evaluation.py - 核心评测脚本
from ragas import evaluate
from ragas.metrics import (
    faithfulness,
    answer_relevancy,
    context_precision,
    context_recall,
    answer_correctness,
)
from langchain_openai import ChatOpenAI, OpenAIEmbeddings

# 用 GPT-4o 做评测裁判(更公正)
evaluator_llm = ChatOpenAI(model="gpt-4o", temperature=0)
evaluator_embeddings = OpenAIEmbeddings(model="text-embedding-3-large")

# 指标列表
metrics = [
    context_precision,    # 检索精度
    context_recall,       # 检索召回率
    faithfulness,         # 忠实度
    answer_relevancy,     # 答案相关性
    answer_correctness,   # 答案正确性
]

# 对数据集中的每个问题,运行RAG并收集结果
def run_rag_and_collect(question):
    """执行RAG检索+生成,返回结构化结果"""
    # 检索相关文档
    retrieved_docs = retriever.invoke(question)
    contexts = [doc.page_content for doc in retrieved_docs]

    # 大模型生成回答
    prompt = f"""基于以下参考资料回答问题,如果资料中没有相关信息,请直接说明。

参考资料:
{'---'.join(contexts)}

问题:{question}

请基于参考资料回答,并标注信息来源。"""

    answer = llm.invoke(prompt).content

    return {
        "question": question,
        "answer": answer,
        "contexts": contexts,
    }

# 准备RAGAS需要的评测数据集
results = [run_rag_and_collect(q) for q in eval_data["question"]]

eval_dataset_ragas = Dataset.from_dict({
    "question": [r["question"] for r in results],
    "answer": [r["answer"] for r in results],
    "contexts": [r["contexts"] for r in results],
    "ground_truth": eval_data["ground_truth"],
})

# 执行评测
print("🔍 正在评测 RAG 系统...")
scores = evaluate(
    dataset=eval_dataset_ragas,
    metrics=metrics,
    llm=evaluator_llm,
    embeddings=evaluator_embeddings,
)

# 输出结果
print("\n📊 ===== RAGAS 评测报告 =====")
print(f"{'指标':<20} {'得分':>8}")
print("-" * 30)
for metric_name, score in scores.items():
    emoji = "✅" if score >= 0.8 else "⚠️" if score >= 0.6 else "❌"
    print(f"{emoji} {metric_name:<18} {score:>8.3f}")

# 导出为DataFrame
import pandas as pd
df = scores.to_pandas()
df.to_csv("rag_evaluation_report.csv", index=False)
print("\n📁 报告已保存至 rag_evaluation_report.csv")

第五步:多方案对比

# compare_rag.py - 对比不同配置的效果
from ragas import evaluate

# 方案 A:chunk_size=256,返回3条
# 方案 B:chunk_size=512,返回4条
# 方案 C:chunk_size=1024,返回5条,使用 MMR 检索

configs = {
    "方案A(chunk256_k3)": {"chunk_size": 256, "k": 3, "search_type": "similarity"},
    "方案B(chunk512_k4)": {"chunk_size": 512, "k": 4, "search_type": "similarity"},
    "方案C(chunk1024_k5_mmr)": {"chunk_size": 1024, "k": 5, "search_type": "mmr"},
}

all_results = []

for name, config in configs.items():
    # 按配置重建检索器
    retriever = build_retriever(**config)
    results = [run_rag_and_collect(q) for q in eval_data["question"]]

    eval_dataset_ragas = Dataset.from_dict({
        "question": [r["question"] for r in results],
        "answer": [r["answer"] for r in results],
        "contexts": [r["contexts"] for r in results],
        "ground_truth": eval_data["ground_truth"],
    })

    scores = evaluate(eval_dataset_ragas, metrics=metrics)
    scores["配置"] = name
    all_results.append(scores)
    print(f"\n✅ {name} 评测完成")

# 对比表格
comparison = pd.DataFrame(all_results)
print("\n📊 ===== 方案对比 =====\n")
print(comparison.to_string(index=False))
comparison.to_csv("rag_comparison.csv", index=False)

实际跑出来的结果(真实案例)

我拿公司内部的产品手册(约 500 页文档)做了实测:

配置方案 检索精度 检索召回 忠实度 答案相关性
chunk256_k3 0.91 0.72 0.94 0.88
chunk512_k4 0.87 0.85 0.91 0.90
chunk512_k4_mmr 0.85 0.88 0.93 0.92
chunk1024_k5 0.72 0.91 0.88 0.85

方案 C(chunk512 + MMR 检索)综合最优。chunk 太小检索精度高但召回低(遗漏信息),chunk 太大则相反——信息全但噪音多。

3 个避坑指南

  1. 别只用一条测试数据就下结论。至少准备 50-100 条真实问答对,覆盖常见场景和边缘案例,否则结果毫无统计意义。

  2. 评测模型和被测模型分开。用 GPT-4 评测 GPT-4o-mini 生成的答案还算客观,但用 GPT-4o-mini 自己评自己就相当于学生批自己卷子,没有参考价值。

  3. 忠实度 < 0.7 要警惕幻觉。如果忠实度很低,说明大模型在胡编乱造,需要检查检索质量或者给 prompt 加更严格的约束。


👤 作者简介

一枚在大中原腹地(河南)卖公有云的从业者,主营腾讯云/阿里云/火山云,曾踩坑无数,现专注AI大模型应用落地。关注公众号「公有云cloud」,围观AI前沿动态~

博客:y1cloud.cn

发表评论