大模型回答准确率从 65% 到 95%:评估数据集构建与量化指标体系

"准确率提升了 30 个百分点"——这个数字不是拍脑袋说的,背后有一套完整的评估方法。本文记录趣玩搭智能客服的评估数据集是怎么构建的、用了哪些指标、以及如何通过评估驱动 RAG 系统的持续优化。

一、为什么必须建立评估体系

1.1 没有评估的窘境

RAG 系统上线初期,我们对"效果好不好"的判断完全依赖主观感受——产品经理试几个问题觉得"还行",就上线了。结果上线后用户投诉不断,但我们甚至说不清"到底哪里不行":是检索没找到正确的文档?还是找到了但大模型没有正确理解?还是 Prompt 写得不好导致输出格式有问题?

没有量化评估,优化就是盲人摸象。改了 chunk size 不知道有没有变好,换了 Embedding 模型不知道值不值得,调了 Prompt 不知道是改进还是退化。

1.2 评估体系的目标

我需要一套评估体系来回答三个问题:

第一,系统整体效果如何? 给一个总体的数字,方便向团队和管理层汇报。

第二,瓶颈在哪个环节? 是检索的问题还是生成的问题,精确定位优化方向。

第三,每次改动是变好了还是变差了? 支撑 A/B 测试和版本迭代决策。

二、评估数据集构建

2.1 数据来源

评估数据集的质量决定了评估结论的可信度。我从三个渠道收集数据:

渠道一:真实用户问题。 从上线后的客服对话日志中,人工挑选了 200 个有代表性的用户真实提问。这些问题覆盖了各种表达方式(口语化、模糊、带错别字等),最接近真实使用场景。

渠道二:运营团队贡献。 让客服运营团队根据日常工作经验,补充了 50 个"高频但表述多样"的问题。比如同一个问题"怎么退款"可能有十几种问法:"退钱怎么退""我不想参加了能退吗""报名后反悔了怎么办"等。

渠道三:边界测试用例。 我自己构造了 50 个刁钻的边界问题,专门用来测试系统的弱点:跨文档的组合问题("A 活动的退款政策和 B 活动一样吗")、知识库中没有答案的问题("你们平台有线下门店吗")、包含时间条件的问题("上个月的积分活动还有效吗")。

最终数据集共 300 条,每条包含:

{
    "id": "eval_001",
    "question": "户外活动开始前一天可以退款吗",
    "category": "退款政策",
    "expected_answer": "活动开始前24小时内不支持退款。如需退款,请在活动开始前48小时申请,48小时以上可全额退款,24-48小时可退50%。",
    "relevant_doc_ids": ["doc_refund_policy_001", "doc_refund_policy_002"],
    "difficulty": "medium",
    "answer_type": "factual"
}

2.2 标注规范

expected_answer 不是要求模型一字不差地输出,而是一个参考标准答案,后续评估时用来判断模型回答是否包含了关键信息点。

每条数据由两个人独立标注,不一致的交由运营主管裁决。这个过程比较耗时(大约两周完成 300 条标注),但磨刀不误砍柴工。

2.3 数据集的分层

300 条数据按多个维度打了标签,方便分析不同场景下的表现:

维度

分类

数量

业务类别

退款(65) / 活动规则(80) / 支付(45) / 积分(35) / 操作指南(40) / 其他(35)

300

难度级别

简单(120) / 中等(130) / 困难(50)

300

答案类型

事实型(180) / 流程型(70) / 拒绝型(50,知识库中无答案)

300

"拒绝型"问题非常重要。好的 RAG 系统不仅要"答对",还要"知道自己不知道"——对于知识库中没有答案的问题,应该诚实说"我不确定,建议联系人工客服",而不是编一个答案。

三、评估指标体系

3.1 端到端指标:整体效果

回答准确率(Answer Accuracy)。 核心指标。评估模型回答是否包含了 expected_answer 中的关键信息点,且没有事实性错误。

评判标准:

等级

定义

得分

完全正确

包含所有关键信息点,无事实错误

1.0

部分正确

包含主要信息但遗漏了次要细节

0.5

错误

包含事实性错误,或答非所问

0.0

正确拒绝

对"拒绝型"问题正确表示不确定

1.0

错误拒绝

对有答案的问题错误地表示不知道

0.0

幻觉回答

对"拒绝型"问题编造了答案

0.0

准确率 = 所有样本得分之和 / 样本总数

初始方式是人工评估——由运营团队的两个人对模型的每条回答打分。300 条数据人工评估大约需要半天时间。

后来引入了 LLM 辅助评估。 使用一个更强的模型(qwen-max)作为"评审官",对比模型回答和标准答案,给出评分和理由:

public EvalResult evaluateWithLLM(String question, String expectedAnswer, String actualAnswer) {
    String evalPrompt = """
        你是一个严格的质量评审员。请对比以下标准答案和实际回答,给出评分。
​
        【用户问题】
        %s
​
        【标准答案】
        %s
​
        【实际回答】
        %s
​
        评分标准:
        - 1.0分:实际回答包含标准答案的所有关键信息,无事实错误
        - 0.5分:包含主要信息但遗漏次要细节,或表述不够准确
        - 0.0分:包含事实错误、答非所问、或编造了标准答案中没有的信息
​
        请以JSON格式回复:{"score": 0.0/0.5/1.0, "reason": "评分理由"}
        """.formatted(question, expectedAnswer, actualAnswer);
​
    // 调用 qwen-max 评估
    String response = llmClient.chat(evalPrompt, "qwen-max");
    return parseEvalResult(response);
}

LLM 评估和人工评估的一致率达到 88%。对于不一致的样本再由人工复核。这样将评估效率提升了 10 倍(从半天缩短到 30 分钟跑一次自动评估 + 半小时复核不一致样本)。

3.2 检索环节指标

检索召回率(Recall@K)。 前 K 个检索结果中,是否包含了标准答案所需的文档片段。

Recall@5 = 检索结果Top5中包含相关文档的问题数 / 总问题数

这个指标用来判断"检索有没有找到正确的文档"。如果召回率低,问题出在文档切分、Embedding 模型或向量检索环节。

检索精确率(Precision@K)。 前 K 个检索结果中,有多少是真正相关的。

Precision@5 = 每个问题Top5中相关文档的数量之和 / (问题数 × 5)

精确率低意味着召回了太多噪音片段,会干扰 LLM 的判断。

3.3 生成环节指标

忠实度(Faithfulness)。 模型的回答是否忠实于检索到的上下文,而没有引入上下文中不存在的信息(幻觉)。

评估方式:将模型回答中的每个事实陈述,逐一核对是否能在检索到的上下文中找到依据。

Faithfulness = 有据可查的事实陈述数 / 总事实陈述数

拒绝准确率。 对于"拒绝型"问题(知识库中没有答案),模型是否正确拒绝了回答。

拒绝准确率 = 正确拒绝的数量 / 拒绝型问题总数

这个指标直接衡量系统的"幻觉控制"能力。初始版本只有 40%(大多数情况下模型会编一个答案),优化后提升到了 82%。

3.4 指标总览与各版本对比

指标

无 RAG (v0)

RAG v1

RAG v2 (当前)

回答准确率

65%

85%

95%

检索召回率 (Recall@5)

82%

91%

检索精确率 (Precision@5)

61%

78%

忠实度

52%

88%

96%

拒绝准确率

12%

55%

82%

平均响应时间

1.2s

1.8s

1.9s

从 v0 到 v1 的提升(65% → 85%): 主要靠引入 RAG 检索,让模型"有据可依"地回答问题。

从 v1 到 v2 的提升(85% → 95%): 多管齐下的优化——分类型文档切分(解决了切分不合理导致的召回遗漏)、混合打分 Re-ranking(减少了噪音片段对 LLM 的干扰)、优化 Prompt 中的忠实度约束(明确要求模型"只基于提供的上下文回答,不知道就说不知道")。

四、评估驱动的迭代流程

4.1 评估流水线

我搭建了一个半自动化的评估流水线,每次系统有变更时触发:

代码/配置变更
    │
    ▼
Jenkins 触发评估任务
    │
    ▼
对 300 条测试数据逐一调用 RAG 系统获取回答
    │
    ▼
LLM 评审员自动评分
    │
    ▼
生成评估报告(各维度指标 + 与上一版本的对比)
    │
    ▼
人工复核不一致样本(可选,每周一次)
    │
    ▼
决定是否发布

评估报告示例(简化版):

=== RAG 系统评估报告 ===
版本: v2.3.1 | 日期: 2025-11-15 | 测试样本: 300
​
总体准确率: 94.7% (↑0.5% vs v2.3.0)
​
按类别:
  退款政策: 96.9% (63/65)
  活动规则: 93.8% (75/80)
  支付问题: 95.6% (43/45)
  积分规则: 94.3% (33/35)
  操作指南: 92.5% (37/40)
  其他:     91.4% (32/35)
​
按难度:
  简单: 98.3% | 中等: 94.6% | 困难: 86.0%
​
关键指标:
  检索召回率: 91.3%
  忠实度: 95.8%
  拒绝准确率: 80.0%
​
退化样本(本版本答错但上版本答对): 2 条
  - eval_137: "积分过期时间" (v2.3.0: ✓ → v2.3.1: ✗)
  - eval_251: "拼团活动最低人数" (v2.3.0: ✓ → v2.3.1: ✗)

退化样本分析是报告中最关键的部分。每次改动后如果有原本答对的变答错了,必须分析原因。上面的例子中,eval_137 退化是因为调整了积分相关文档的切分方式,把"积分有效期"的描述不小心切断了——这类问题在测试集中就能被发现,避免了带着回退上线。

4.2 持续优化的案例

举一个评估驱动优化的具体案例。

评估报告显示"操作指南"类别的准确率(88%)明显低于其他类别。深入分析错误样本,发现共性问题:操作指南中经常有"步骤 1... 步骤 2... 步骤 3..."的连续步骤描述,而固定长度切分经常把一组步骤切断了。比如用户问"怎么报名活动",检索到的是步骤 3-5,而步骤 1-2 在另一个 chunk 中没有被召回。

优化方案:对操作指南类文档,改为按"完整步骤组"切分,一个完整操作流程作为一个 chunk,即使稍微超出 chunk size 的限制也不强行切断。

优化后"操作指南"类别的准确率从 88% 提升到 92.5%,总体准确率提升了 0.8 个百分点。没有评估数据的定位,这个问题根本发现不了。

五、经验总结

评估数据集是 RAG 系统最重要的资产之一。 它的投入产出比极高——花两周标注 300 条数据,换来后续所有优化都有据可依。

拒绝型问题必须纳入评估。 一个"什么都敢答"的系统不是好系统。知道自己不知道,比瞎答更重要。

LLM 辅助评估大幅降低了评估成本。 但不能完全替代人工——LLM 评审员和人工有 12% 的不一致率,关键决策时仍需人工复核。

关注退化比关注提升更重要。 每次改动后如果有退化样本,必须分析原因。如果新版本提升了 2% 但退化了 1%,那实际有效提升只有 1%,而且退化的那 1% 可能是高频问题。

准确率从 65% 到 95% 不是一步到位的,而是持续迭代的结果。 65% → 85%(引入 RAG) → 89%(优化切分)→ 92%(加 Re-ranking)→ 95%(优化 Prompt + 修复边界 case)。每一步都只有 3-6 个百分点的提升,但积少成多。


如果这篇文章对你有帮助,欢迎访问我的博客 robinzhu.top 获取更多实战分享。