跳到主内容

从凭感觉坏例到可归因:RAGAS 四维评估实战 ​

问题背景:RAG 上线后,为什么“看起来能答”仍然不够 ​

很多 RAG 系统上线前依赖人工抽测:问几个问题,看回答是否通顺。但线上真实流量会迅速暴露三类问题:检索没找到、找错了但模型强行解释、找到了证据却没有回答用户问题。仅靠最终答案的主观打分,很难判断问题出在知识库、召回、排序、上下文拼装,还是生成模型。

RAG 评估的核心价值,是把一条 badcase 拆成可定位的环节:

  • 用户问题是否清晰;
  • 检索上下文是否包含正确证据;
  • 上下文是否混入噪声;
  • 答案是否忠于证据;
  • 答案是否真正回应问题。

RAGAS 提供了一套面向 RAG 的自动化指标体系。生产中最常用的是四个维度:Faithfulness(忠实度)、Answer Relevancy(答案相关性)、Context Precision(上下文精确率)、Context Recall(上下文召回率)。它们分别对应“有没有胡说”“有没有答非所问”“检索结果是否靠前且有用”“正确证据是否被召回”。

方案对比:人工评估、规则评估与 LLM-as-a-Judge ​

方案优点局限适用阶段
人工专家评估准确、能判断业务语义成本高、速度慢、标准易漂移金标集验收、争议样本复核
规则与关键词评估稳定、便宜、可重复难以识别同义表达和推理答案格式校验、强事实字段检查
RAGAS/LLM 自动评估可批量跑、维度清晰、便于归因受裁判模型影响,需要抽样校准回归测试、日常监控、版本对比
线上用户反馈接近真实效果噪声大、滞后、样本有偏持续迭代与告警

建议不要把 RAGAS 当作“绝对真理”,而是把它作为高吞吐的评测层:先用 RAGAS 找出低分样本和指标组合,再对边界样本进行人工复核。

RAGAS 四维指标:每个分数到底在诊断什么 ​

Faithfulness:答案是否忠于检索上下文 ​

忠实度检查回答中的每个主张能否由上下文支持。分数低通常意味着模型发生了幻觉、使用了参数记忆,或者把检索到的相似但错误的信息当成事实。

典型表现:上下文写“支持 7 天退款”,答案却写“支持 30 天无理由退款”。即使语言流畅,也应判为低忠实度。

Answer Relevancy:答案是否围绕问题 ​

答案相关性关注回答是否切题,而不是简单比对字数或关键词。常见低分原因有两类:一是答案堆砌背景资料,没有给出结论;二是问题本身有多个子问,回答只覆盖其中一部分。

Context Precision:有用上下文是否排在前面 ​

上下文精确率关注检索结果中有用片段的排名和噪声比例。即使正确片段在 Top 5,但排在最后,经过截断或长上下文稀释后,模型也可能忽略它。该指标适合诊断召回排序、rerank 和 chunk 质量。

Context Recall:标准答案所需证据是否被召回 ​

上下文召回率通常需要 ground truth,即人工标注的标准答案或证据。它检查回答标准答案所需的信息是否能在上下文中找到。该指标低,优先排查知识库缺失、切片粒度、过滤条件、Embedding 和召回参数。

用户问题检索上下文精确率/召回率生成答案忠实度/相关性指标报告检索类问题查切片、召回、过滤生成类问题查提示词、模型、截断数据类问题查知识缺失与冲突

实操步骤:用可运行代码完成一次 RAGAS 评估 ​

下面示例使用 OpenAI 兼容接口作为 RAG 系统和 RAGAS 裁判模型。你可以替换为内部模型网关,但要保证裁判模型具备较强的事实判断与指令遵循能力。

先安装依赖:

bash
pip install "ragas>=0.1.21" datasets openai pandas

第一步:构造评测样本 ​

评测集不要只收集“容易回答”的问题。建议按业务意图、文档来源、时间范围、问题难度分层抽样,并保留一定比例的多跳问题、拒答问题和过期知识问题。

python
# eval_rag.py
# 可直接运行:python eval_rag.py
import os
import pandas as pd
from datasets import Dataset
from openai import OpenAI
from ragas import evaluate
from ragas.metrics import (
    faithfulness,
    answer_relevancy,
    context_precision,
    context_recall,
)

# 如果使用公司内部 OpenAI 兼容网关,修改 OPENAI_BASE_URL 即可
client = OpenAI(
    api_key=os.getenv("OPENAI_API_KEY", "replace-with-your-key"),
    base_url=os.getenv("OPENAI_BASE_URL", "https://api.openai.com/v1"),
)

# 小规模金标集:ground_truth 用于上下文召回率评估
samples = [
    {
        "question": "会员退款有效期是多久?",
        "ground_truth": "会员服务在购买后 7 天内,且未使用核心权益时可申请退款。",
    },
    {
        "question": "企业版是否支持私有化部署?",
        "ground_truth": "企业版支持专有云私有化部署,需要联系商务开通。",
    },
]

# 模拟知识库检索结果。生产中替换成向量库、混合检索或 rerank 后的结果
fake_knowledge_base = {
    "会员退款有效期是多久?": [
        "会员服务购买后 7 天内,且未使用核心权益,可申请退款。",
        "退款将在审核通过后的 3 到 5 个工作日原路退回。",
    ],
    "企业版是否支持私有化部署?": [
        "企业版支持专有云私有化部署,适用于对数据隔离要求较高的客户。",
        "私有化版本需要联系商务确认资源、版本和交付周期。",
    ],
}

def retrieve(question: str):
    """返回检索片段列表。"""
    return fake_knowledge_base.get(question, ["知识库中未找到相关说明。"])

def generate_answer(question: str, contexts: list[str]) -> str:
    """根据上下文生成答案,禁止使用无依据信息。"""
    context_text = "\n".join(f"[{i+1}] {c}" for i, c in enumerate(contexts))
    prompt = f"""
你是严谨的客服助手。请只能依据以下资料回答问题。
如果资料不足,请回答“根据现有资料无法确认”。

资料:
{context_text}

问题:{question}
答案:
"""
    resp = client.chat.completions.create(
        model=os.getenv("RAG_MODEL", "gpt-4o-mini"),
        messages=[{"role": "user", "content": prompt}],
        temperature=0,
    )
    return resp.choices[0].message.content

# 组装 RAGAS 需要的字段
rows = []
for item in samples:
    contexts = retrieve(item["question"])
    answer = generate_answer(item["question"], contexts)
    rows.append({
        "question": item["question"],
        "answer": answer,
        "contexts": contexts,
        "ground_truth": item["ground_truth"],
    })

dataset = Dataset.from_list(rows)

# 运行四维评估
result = evaluate(
    dataset=dataset,
    metrics=[
        faithfulness,
        answer_relevancy,
        context_precision,
        context_recall,
    ],
)

# 输出总体分数与逐条明细
print("总体指标:")
print(result)

df = result.to_pandas()
print("\n逐条明细:")
print(df[[
    "question",
    "faithfulness",
    "answer_relevancy",
    "context_precision",
    "context_recall",
]])

df.to_csv("ragas_result.csv", index=False, encoding="utf-8-sig")

第二步:固定裁判模型与参数 ​

RAGAS 的多数指标依赖 LLM-as-a-Judge。为了让历史版本可比较,需要记录:

  • 裁判模型名称与版本;
  • temperature,建议设为 0;
  • RAGAS、依赖库和指标提示词版本;
  • 评测集版本;
  • 检索 TopK、rerank 模型、切片大小和重叠长度。

否则一次分数上升可能只是裁判模型变了,而不是 RAG 效果真的改善。

第三步:建立 badcase 归因表 ​

不要只看平均分,建议导出逐条结果并按指标组合归因:

指标现象更可能的问题优先动作
召回率低、精确率也低知识库缺失或检索语义不匹配补文档、优化切片、调整 Embedding 查询
召回率高、精确率低噪声片段太多,排序差加 rerank、降低 TopK、增强元数据过滤
上下文指标高、忠实度低模型忽略证据或自行补全强化约束、降低温度、要求引用证据
忠实度高、相关性低回答保守或没有覆盖问题改答案模板、拆分子问题、补充回答要求
所有指标都高但用户不满意评测集与真实问题分布不一致引入线上问题,重建金标集

可以用下面的规则做自动归因:

python
# attribution.py
import pandas as pd

def attribute_case(row):
    """根据 RAGAS 四维分数给出初步归因。"""
    f = row["faithfulness"]
    a = row["answer_relevancy"]
    p = row["context_precision"]
    r = row["context_recall"]

    if r < 0.6 and p < 0.6:
        return "检索失败:疑似知识缺失或查询语义不匹配"
    if r >= 0.6 and p < 0.6:
        return "排序失败:正确证据存在,但噪声过多或排名靠后"
    if f < 0.7 and p >= 0.6 and r >= 0.6:
        return "生成幻觉:上下文足够,但答案引入无依据信息"
    if f >= 0.7 and a < 0.7:
        return "答非所问:答案有依据,但未完整回应用户意图"
    return "表面通过:建议结合用户反馈人工复核"

df = pd.read_csv("ragas_result.csv")
df["attribution"] = df.apply(attribute_case, axis=1)
df.to_csv("ragas_badcase_attribution.csv", index=False, encoding="utf-8-sig")
print(df[["question", "attribution"]])

如何设计一套可持续的 RAG 评测集 ​

第一,金标答案要写“可验证事实”,不要只写营销话术。例如“支持私有化部署”比“企业版能力强大、安全可靠”更容易评估。

第二,问题要覆盖真实用户语言。用户通常不会直接输入文档标题,而会说“我买错了能不能退”“你们能不能部署到我们自己机房”。这些口语化问法能检验查询改写和语义召回。

第三,必须包含反事实和无答案问题。如果知识库没有说明,就应该拒答,而不是让模型猜。可以在 ground_truth 中明确写“资料不足,应拒答”。

第四,评测集要版本化。每次知识库大更新、切片策略调整、模型替换、rerank 上线,都应在同一评测集上回归,再补充新增业务问题。

避坑总结:RAGAS 落地最容易踩的 5 个坑 ​

1. 只看平均分,忽略指标组合 ​

错误现象:整体均分 0.85 就认为系统合格,但某类售后问题忠实度只有 0.55。修正方法是按问题类型、文档来源、时间范围分组统计,并设置单项阈值,例如忠实度低于 0.7 必须阻断发布。

2. 没有 ground_truth 却误读上下文召回率 ​

错误现象:只传 question、answer、contexts,发现召回率结果不稳定或无法反映真实缺失。修正方法是为核心评测集标注标准答案或必需证据点;没有标注时,只能把召回率作为辅助指标,不能作为主要验收依据。

3. 检索片段过长,导致裁判模型“看起来都相关” ​

错误现象:一个 chunk 包含整篇文档,上下文精确率虚高,但生成答案抓不住重点。修正方法是控制 chunk 粒度,保留标题路径和小节信息;对长文档先做语义切分,再用 rerank 选择最相关片段。

4. 用同一个弱模型既生成答案又当裁判 ​

错误现象:模型把自己的错误表述判成正确,尤其是数字、日期、权限类问题。修正方法是裁判模型使用能力更强、更稳定的模型,并对低分样本、高分但人工怀疑的样本进行双向抽检。

5. 把 RAGAS 分数当成分数线,而不是诊断信号 ​

错误现象:团队为了提高答案相关性,在提示词中要求模型多写背景,结果忠实度和用户满意度下降。修正方法是每次只改动一个环节,例如只替换 rerank 模型或只调整切片大小,并对比四维指标变化,避免用一个指标掩盖另一个问题。

结语 ​

RAGAS 的价值不在于给出一个漂亮总分,而在于把 RAG 系统拆成“检索—排序—生成—问答意图”四个可观测环节。真正有效的评估流程应当是:固定金标集,自动计算四维指标,按指标组合归因 badcase,再通过人工复核校准裁判模型。这样,每次优化 Embedding、切片、rerank、提示词或生成模型时,才能知道收益来自哪里,也能避免修复一个问题却引入新的幻觉。

免责声明

本工具与文章内容仅用于学习测试场景,优化建议仅供参考,请勿直接用于生产环境,由此产生的风险自行承担。