RAG评测指标体系

RAG 系统怎么评测:把“回答看起来不错”拆成四组指标

摘要:RAG 的问题可能出在数据、检索、上下文或生成,单一“答案正确率”无法定位原因。本文给出一套从离线测试到线上反馈的分层评测框架。

标签:RAG 评测 大模型 LLMOps 质量保障

一、为什么主观体验不够

演示 RAG 时,人们常挑几个熟悉问题,看回答是否流畅。这种方式容易被语言表达迷惑:答案读起来完整,不代表引用支持它;引用存在,也不代表检索到了最佳版本。

评测的第一步,是把链路拆开:

知识数据 → 检索 → 上下文拼装 → 答案生成 → 用户使用

每一层都应有独立指标。这样出现问题时,才能知道该改索引、排序、提示词还是产品交互。

二、第一组:知识数据质量

入库前先测数据,而不是等问答失败后再排查。常见指标包括:

  • 文档解析成功率;
  • 标题、版本、日期等元数据完整率;
  • 重复片段比例;
  • 过短与过长片段比例;
  • 表格、列表、页码的保真率;
  • 过期或失效文档占比;
  • 权限标签缺失率。

数据质量指标应随每次增量导入自动生成。如果源文档解析错误,换更大的模型也无法补救。

三、第二组:检索质量

检索评测需要“问题—相关证据”对。可以由业务人员标注每个问题对应的一个或多个证据片段。

重点指标包括:

  • Recall@K:前 K 个结果是否包含正确证据;
  • MRR:第一个正确证据的平均倒数排名;
  • nDCG@K:考虑多个相关结果及其相关程度的排序质量;
  • 过滤准确率:版本、权限和时间条件是否被正确执行;
  • 无答案识别率:知识库不存在答案时,是否避免召回弱相关内容。

检索评测最好按问题类型分桶,例如精确编码、自然语言解释、多条件问题和时效性问题。平均分可能掩盖某一类严重缺陷。

四、第三组:生成质量

生成部分至少要评估四件事:

  1. 正确性:结论是否符合标准答案;
  2. 忠实性:答案是否能由提供的上下文支持;
  3. 引用准确性:引用是否真实、定位是否正确;
  4. 完整性:问题中的关键子项是否都被覆盖。

“正确性”和“忠实性”不能合并。一个答案可能碰巧正确,却没有被当前证据支持;也可能忠实复述了材料,但材料本身已经过期。

自动评审模型可以提高效率,但不能作为唯一裁判。建议用一部分人工标注样本定期校准自动评审,并记录评审提示词与模型版本。

五、第四组:系统与业务指标

模型质量之外,还要关注系统是否可用:

  • P50、P95 响应时间;
  • 单次请求的模型与检索成本;
  • 超时率、解析失败率、重试率;
  • 人工接管率;
  • 用户采纳率与纠错率;
  • 高风险问题的安全拦截率。

线上“点赞率”只能作为信号,不能直接等同于答案正确率。用户可能因为回答简短而点赞,也可能因为结论不符合预期而点踩。

六、构建一个可持续的评测集

评测集不应是一次性文件。建议包含以下来源:

  • 业务专家编写的核心问题;
  • 线上高频问题的脱敏改写;
  • 历史失败案例;
  • 对抗样例,如错误前提、冲突证据和越权请求;
  • 无答案样例,检验系统是否会拒答。

每条样本记录问题类型、标准证据、可接受答案要点、风险等级和适用版本。政策或知识版本变化时,评测集也要同步更新。

七、评测集应该怎样分层

一个实用的评测集可以分为三层:

1. 冒烟集

数量不必多,通常几十条即可,覆盖系统最核心的能力和高风险边界。每次提交代码或修改配置后快速运行,用于发现明显错误,例如索引不可用、引用丢失、权限过滤失效。

2. 回归集

包含几百到几千条稳定样本,覆盖主要问题类型、知识来源和难度等级。模型、Embedding、切分、重排和提示词升级前后都运行,用来比较版本差异。

3. 挑战集

专门收集复杂和对抗样例,例如多跳问题、冲突材料、过期文档、错误前提、越权请求、诱导模型忽略规则的文本。挑战集的目标不是获得高平均分,而是暴露安全边界。

三层数据应尽量隔离。频繁根据同一批回归样本调参,会让系统“记住测试题”。可以保留一组只在重要版本发布前使用的隐藏测试集。

八、标准答案不一定是一段固定文本

开放式回答很难用字符串完全匹配。更合理的标注包括:

{
  "question": "示例问题",
  "required_facts": ["要点A", "要点B"],
  "forbidden_claims": ["不应出现的结论"],
  "gold_evidence": ["doc-12#chunk-3"],
  "acceptable_variants": ["允许的表达方式"],
  "risk_level": "high",
  "valid_version": "2026.1"
}

这样既允许模型使用自然语言表达,又能检查关键事实、禁用结论和引用证据。对于计算、编码或枚举题,则可以使用严格字段匹配。

标注过程中若专家意见不一致,不要强行选一个答案。可以记录分歧和适用条件,这本身也是重要的知识治理信息。

九、自动评审模型怎样用才可靠

自动评审适合大规模初筛,但容易受到答案长度、措辞和评审提示词影响。使用时可以采取以下措施:

  • 让评审模型按明确量表逐项打分,而不是只给“好/坏”;
  • 隐藏被测模型名称和版本,减少偏见;
  • 随机交换对比答案顺序,检查位置偏好;
  • 要求评审给出对应证据,但限制自由发挥;
  • 使用人工标注集计算自动评审的一致率;
  • 对高风险样本坚持人工复核。

如果自动评审与人工经常不一致,应先修订量表,而不是简单更换一个更大的评审模型。

十、一次实验应该记录什么

RAG 系统有大量可变因素。若只记录“新版本分数提高了”,很快就无法复现实验。建议为每次运行保存:

  • 评测集版本和样本范围;
  • 文档索引版本;
  • 切分参数;
  • Embedding 模型与维度;
  • 关键词检索参数;
  • 融合与重排配置;
  • 生成模型、采样参数和提示词版本;
  • 代码提交号与运行时间;
  • 分项指标、失败样本和成本。

对于随机生成,可以固定种子或降低温度,并在重要样本上重复运行多次,观察结果稳定性。单次偶然成功不应被当成能力提升。

十一、从失败样本反推改进方向

评测报告最有价值的部分不是总分,而是错误分布。可以为失败样本建立原因标签:

  • missing_document:知识库本身缺少材料;
  • parse_failure:文档解析破坏了内容;
  • retrieval_miss:正确证据未被召回;
  • ranking_error:正确证据排名过低;
  • context_overflow:证据被上下文预算截断;
  • generation_hallucination:模型无依据扩写;
  • citation_error:结论与引用不匹配;
  • policy_failure:应拒答但没有拒答。

每个错误类型对应不同责任模块。只有完成归因,团队才能把时间花在真正的瓶颈上。

十二、把核心指标写清楚

假设每个问题有一个相关文档集合 Rel(q),系统返回按相关性排序的列表。常用指标可以这样理解:

Recall@K

Recall@K = |TopK(q) ∩ Rel(q)| / |Rel(q)|

如果一个问题只有一个标准证据,它就退化为“正确证据是否进入前 K 名”。当一个问题需要多段证据时,应使用完整公式,避免召回其中一段就算成功。

MRR

MRR = (1 / N) × Σ 1 / rank_first_relevant(q)

MRR 只关心第一个相关结果,适合“找到一个正确答案即可”的任务,不适合评估多证据完整性。

nDCG@K

DCG@K  = Σ (2^rel_i - 1) / log2(i + 1)
nDCG@K = DCG@K / IDCG@K

rel_i 可以是 0、1、2 等分级相关度。nDCG 同时考虑相关程度和排序位置,适合一个问题存在多个不同质量证据的情况。

忠实性

忠实性很难用一个通用公式表示。工程上可以把答案拆成原子陈述,检查每条陈述是否被引用上下文支持:

faithfulness = 被证据支持的陈述数 / 全部可验证陈述数

关键是先定义“原子陈述”和“支持”的标注规则,否则不同评审者会得到完全不同的分数。

十三、实现一个可扩展的评测 Runner

from dataclasses import dataclass
from time import perf_counter

@dataclass(frozen=True)
class EvalCase:
    case_id: str
    question: str
    relevant_ids: frozenset[str]
    required_facts: tuple[str, ...]

async def run_case(case: EvalCase, rag_service) -> dict:
    started = perf_counter()
    result = await rag_service.ask(case.question)
    latency_ms = (perf_counter() - started) * 1000
    retrieved_ids = [hit.chunk_id for hit in result.retrieval_hits]

    return {
        "case_id": case.case_id,
        "recall@5": len(set(retrieved_ids[:5]) & case.relevant_ids)
                    / max(len(case.relevant_ids), 1),
        "first_relevant_rank": next(
            (i for i, doc_id in enumerate(retrieved_ids, 1)
             if doc_id in case.relevant_ids),
            None,
        ),
        "latency_ms": latency_ms,
        "prompt_tokens": result.usage.prompt_tokens,
        "completion_tokens": result.usage.completion_tokens,
        "answer": result.answer,
        "citations": result.citations,
    }

Runner 只收集客观数据;答案要点评分和忠实性评审放到独立模块中。这样可以替换评审模型,而不必重新运行昂贵的检索与生成。

结果建议保存为 JSONL 或 Parquet,每行包含完整配置哈希。聚合报告只用于展示,原始逐题结果必须保留,便于定位退化样本。

十四、在 CI 中设置质量门禁

普通提交运行冒烟集,合并到主分支前运行核心回归集,模型或索引大版本升级再运行完整评测。门禁不要只看平均分:

quality_gates:
  recall_at_20_min: 0.93
  citation_precision_min: 0.98
  high_risk_pass_rate: 1.00
  p95_latency_ms_max: 8000
  max_cost_increase_ratio: 0.15
  allowed_core_case_regressions: 0

如果评测使用外部服务,应固定区域、模型版本和重试策略。网络错误样本单独标记为基础设施失败,不能混进质量失败,也不能简单丢弃。

对非确定性模型,可以为关键样本运行 3~5 次,统计最差值和方差。发布门槛最好关注最差表现,而不仅是均值。

十五、用门槛控制发布

每次调整切分、Embedding、重排器、提示词或模型,都运行同一套回归测试。可以设置发布门槛:核心问题不得退化,高风险问题必须全部通过,整体指标达到基线,同时延迟和成本不超过预算。

若新方案在平均正确率上提升,却导致引用错误率或高风险误答上升,就不应直接上线。评测的价值不是产生漂亮分数,而是帮助团队做可解释的发布决策。

RAG 系统的评测不是“给回答打一个分”,而是建立一条质量诊断链。只有数据、检索、生成和业务指标一起看,优化才不会停留在凭感觉调参数。

posted @ 2026-09-20 15:47  楼主好菜啊  阅读(5)  评论(0)    收藏  举报