3080 字
约 10 分钟
14
S20-B06 · RAG 效果评测入门:怎么知道答得准不准

"换了个 embedding,感觉回答变好了"——这种判断的方差常常比改动本身带来的收益还大。RAG 的效果不是单一数字,它由两段决定:检索有没有把对的材料捞上来,生成有没有照着材料说。这两段的失败表现不同、修法不同,评测也必须分开做。


1. 为什么必须拆成两层

层 输入 输出 典型失败
检索 问题 top-k 材料 该在的没捞到、捞到一堆无关的
生成 问题 + 材料 答案 有材料也答错、无材料时编造

拆开的原因很直接:同一个坏答案,可能来自任一层的任一环节。不拆,就只能靠换模型碰运气;拆了,才能判断"该修索引还是该修提示"。

只测总体 分层测
知道变差,不知道差在哪 定位到召回、切分、拼装或生成
换模型成了唯一手段 可以只改一层做单变量对比
改动收益无法归因 每层的涨跌各自可解释

2. 检索侧的三个指标

命中率 Hit@k   = 有至少一条相关文档进入 top-k 的问题数 / 总问题数
召回率 Recall@k = |相关 ∩ top-k| / |全部相关|     (每题标注全部相关文档时可用)
MRR            = 每题「第一条相关文档的排名」取倒数后求平均
指标 回答什么 敏感于 不敏感于
Hit@k "有没有捞到" k 的大小 相关文档排在第几位
Recall@k "捞到了多少" 相关文档的数量 排序质量
MRR "第一条相关的排多前" 首条相关的位置 第二条之后的相关文档

入门阶段先算 Hit@k:它最直观、标注成本最低(只需标"哪几条算相关",不必标全部)。等标注能力上来,再补 Recall@k 与 MRR。


3. 生成侧的四个判定项

判定项 问法 不通过的典型表现
正确性 结论与材料是否一致 数字对不上、条件漏了
完整性 是否回答了问题的全部要点 只答一半、漏了例外条款
是否编造 有没有材料里没有的事实 凭空补流程、补人名日期
是否该说不知道 材料里没有时是否明确说没有 硬答、或用通用知识糊过去

第四项最容易被忽略:"问题超出资料范围"时,正确行为是拒答或声明无依据,而不是给一个听起来合理的答案。评测集里必须有这类题,否则系统会一直在"编造也算对"的口径下被评高分。


4. 评测集怎么造

eval/questions.jsonl   (每行一题)
{"id":"q01","q":"试用期多久可以转正","type":"in_scope",
 "acceptable":["三个月","3 个月"],"relevant_docs":["hr-001#3"]}
{"id":"q02","q":"年假可以折现吗","type":"out_of_scope",
 "acceptable":["没有相关规定","资料中未提及"],"relevant_docs":[]}
原则 做法 反例
从真实问法来 客服记录、群聊、搜索日志里抄 自己按文档标题出题
含超出范围的问题 至少 20% 是资料里没有的 全是能答的题
每题标可接受答案 列几种表述,不写唯一标准句 只写一句"标准答案"
一题一义 一题只问一件事 一句话里塞三个问题
标注相关文档 检索层才有对照 只标答案不标出处

规模上,几十条即可起步(20–50 条),关键是覆盖问题类型而不是堆数量。一条标得准的题胜过十条含糊的题。


5. LLM 判分的三档提示与偏差

档位 输出 优点 偏差来源
打分制(1–5) 分数 区分度细 分数刻度不稳定,跨批次不可比
通过/不通过 布尔 稳定、易聚合 边界样本反复横跳
对比二选一 A/B/平 对相对好坏最敏感 有位置偏好,需交换顺序各测一次
你是评分员。只依据【资料】判断【答案】,不要用自己的知识补充。

资料:{{context}}
问题:{{question}}
答案:{{answer}}

按顺序判断:
1. 答案的结论是否都能在资料中找到依据?
2. 是否遗漏了问题要求的要点?
3. 资料不足以回答时,答案是否明确说明"资料中未提及"?

只输出一行 JSON:
{"grounded": true|false, "complete": true|false, "should_abstain": true|false, "reason": "一句话"}

三条控制偏差的做法:固定提示与模型版本、要求给理由(理由比分数更可核查)、抽样人工复核(10%–20% 即可发现系统性偏差)。对比档务必交换 A/B 顺序跑两遍,位置偏好是稳定存在的。


6. 标注的最小流程

  1. 先标 20–30 条,两个人独立标;
  2. 算一致率,逐条看分歧;
  3. 分歧集中在哪类问题,就细化那类的判定标准;
  4. 标准写清楚后再扩大规模。
阶段 规模 目的
试标 20–30 条 暴露标准歧义
定标准 — 把分歧写成判定条目
扩标 50–100 条 建立稳定基线
维护 每次改动加几条 覆盖新出现的问题类型

一致率不必追高,关键是分歧能被解释。两人对"是否编造"判断不同,往往说明判定标准里缺了"允许改写还是必须逐字引用"这一条。


7. badcase 分类

类别 表现 该改哪里
召回缺失 top-k 里根本没有对的材料 切分、embedding、检索参数、同义词
切分破坏语义 答案被切在两块之间 分块大小与重叠、按结构切
拼装丢上下文 材料在,但提示里被截断或顺序混乱 上下文预算、去重、排序
模型忽略资料 材料齐全,答案仍跑偏 提示约束、引用要求、换模型
问了资料外的问题 系统硬答 拒答策略、范围判定
表述歧义 问题本身有多种理解 查询改写、澄清式追问

分类的价值在于它能直接指向改动。同样是"答错",落在第一类和第四类的修法完全不同——这也是必须分层评测的原因。


8. 改动前后对比与线上信号

对比的三条纪律:同一评测集、单变量、重复多次。

纪律 含义 违反后果
同一评测集 基线版与改动版跑同一份题 涨跌无法归因
单变量 一次只改一个因素 不知道是谁的功劳
重复多次 温度非零时同一题跑多次取分布 单次波动被当成改进

线上信号作为补充,覆盖评测集到不了的部分:

信号 含义 高了说明什么
无结果率 检索没返回任何内容 索引缺失或查询改写失败
追问率 用户马上换个说法再问 第一次答偏或答不全
人工介入率 转人工 置信度低或问题超范围

线上信号是方向指示,不是评测结论:追问率高可能是答得差,也可能是产品引导设计问题。用它发现问题,用评测集确认原因。


9. 频率与成本

改动类型 评测规模 频率
提示词微调 全量评测集 每次改动
换模型 / 换 embedding 全量 + 人工复核样本 每次改动
切分策略调整 全量(检索与生成都要跑) 每次改动
仅在线上发现的问题 补题进评测集 发现即补

成本主要在人工标注与 LLM 判分调用。检索侧指标不需要 LLM,纯脚本即可;生成侧只跑当次评测集,不做历史全量回归。


10. 最小可跑示例

① 20 条评测集(eval/questions.jsonl,结构见第 4 节,先写 20 行)。

② 检索命中率脚本

# eval/hit_rate.py
import json, sys
K = 4
rows = [json.loads(l) for l in open("eval/questions.jsonl", encoding="utf-8")]
hits = total = 0
for r in rows:
    if not r["relevant_docs"]:
        continue                      # 超范围题不参与检索侧统计
    total += 1
    got = retrieve(r["q"], k=K)        # 返回 doc_id 列表
    if set(got) & set(r["relevant_docs"]):
        hits += 1
print(f"Hit@{K} = {hits}/{total} = {hits/total:.2f}")

③ LLM 判分(提示见第 5 节,逐题调用并解析 JSON,汇总 grounded/complete 的通过率)。

④ 对比表

版本 Hit@4 正确性通过率 编造率
基线 按实测填 按实测填 按实测填
改动后 按实测填 按实测填 按实测填

三列必须一起看:召回涨而编造率也涨,说明材料变多但约束变松了。

⑤ 结果存档

mkdir -p eval/runs/$(date +%F)-baseline
cp eval/questions.jsonl eval/runs/$(date +%F)-baseline/questions.snapshot.jsonl
python eval/hit_rate.py | tee eval/runs/$(date +%F)-baseline/hit.txt

评测集随改随变,存档时必须把当次使用的题目快照一起存,否则半个月后无法解释分数差异。


11. 排错

现象 根因 处理
分数很高但线上投诉多 评测集是照文档出的题 换成真实问法重出题
只改了提示,检索指标也涨了 对比时换了评测集 固定评测集重跑
同一题两次判分结论不同 温度高、判分提示模糊 降温、要求给理由、重复取多数
判分与人工判断系统性不一致 判分模型用了自己的知识 提示里明确"只依据资料"
检索指标很好,答案仍差 拼装丢上下文或截断 单独测生成层,检查实际送进提示的内容
全部通过 题目太简单或可接受答案列太宽 加超范围题、收紧可接受答案
回归时找不到基线 没存版本与评测集快照 评测集与结果一起存档

12. 边界

场景 更合适的做法 理由
主观问答(风格、语气) 人工小样本 + 对比二选一 自动判分对风格不敏感
需要精确数值核对 规则校验 + 单元测试 LLM 判分不适合精确比对
冷启动、还没有评测集 先上线并埋线上信号 从真实问法里攒题比凭空造题准

一句话:评测集是测量工具,回答"这次改动相比基线是涨是跌",不回答"这个系统绝对有多好"。


13. 自测

  1. 为什么检索质量与生成质量必须分开评?
  2. Hit@k 与 Recall@k 的差别在哪,什么时候才需要后者?
  3. 评测集里为什么必须有"资料里没有"的问题?
  4. LLM 判分的对比档为什么要交换 A/B 顺序各跑一遍?
  5. 一个答错的 badcase,怎么判断是召回缺失还是模型忽略资料?
  6. 改动前后对比的三条纪律分别防的是什么误差?
S20-B06 · RAG 效果评测入门:怎么知道答得准不准
https://www.clxhxhhr.top/posts/6115/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。