第 04 篇我们把检索链路从单路 BM25 升级成了混合检索。但有一个残酷的事实:凡是”感觉更好”的优化,都可能在两周后被打回原形。因为”感觉”不留下数据,而数据才是不被推翻的依据。
本篇解决这个问题的工程手段:离线评测体系。包括三部分——评估集怎么来、指标怎么算、指标怎么驱动迭代。
一、RAG 评测的两个层次
RAG 系统要评测两层,缺一不可:
1 | ┌─────────────────────────────────────┐ |
先测 L1 再测 L2。如果检索层 Recall@K 是 0.3,生成层指标再高都是幻觉侥幸——模型在用自己的知识回答,而不是用你的知识库。测试顺序就是问题定位顺序。
二、评估集:没有评估集,一切指标都是摆设
2.1 从博客真实读者收集
ByteBot 最珍贵的资产是真实问题。ai-assistant.js 的 trackEvent 只统计 opens/sends/errors,没有记录问题文本。改造第一步:后端把每次对话的 user 消息(脱敏后)落库。
评估集的问题来源分级:
| 来源 | 价值 | 数量目标 |
|---|---|---|
| 真实读者问题(线上埋点) | 最高,反映真实需求 | ≥ 30 |
| 博客评论区 / 留言板 | 高 | ≥ 10 |
| 从文章标题反推(”每个系列至少 1 个导航问题”) | 中,覆盖边界 | ≥ 20 |
| 手工构造的刁钻问题(跨文章、模糊意图) | 高,测鲁棒性 | ≥ 10 |
2.2 评估集的格式
1 | { |
关键字段:
- expected_answer_articles:L1 检索层的”标准答案”——这个问题应该召回哪些文章。这是人工标注成本最高的字段,但对 Recall 计算必不可少。
- expected_keywords:生成层的弱标注,自动粗略校验”回答是否提到关键概念”。
- source:区分线上/手工/反推,跑评测时可以分层看指标(比如”线上问题集”的分数才是用户真实体验)。
2.3 用 RAGAS 自动生成评估集
纯人工标注 70 个问题太累。RAGAS 提供 TestsetGenerator,从文档自动生成”问题 + 答案”对——生成的答案是文档里的原文,可以直接当 ground truth。流程:
1 | 260 篇文章 → 抽样 30 篇 → RAGAS 生成 60~90 个 QA 对 |
注意 RAGAS 生成的问题偏”文档内容复述型”,覆盖不了”导航型”问题(”有哪些 Unity 教程”),所以必须和真实问题混合。
三、核心指标:怎么算、怎么解读
3.1 检索层指标
Recall@K:Top-K 结果里包含多少标准答案。
1 | Recall@5 = 标准答案文章在 Top5 召回中的比例 |
MRR(Mean Reciprocal Rank):第一个正确答案出现在第几位。
1 | 问题期望文章在 Top5 的第 2 位 → RR = 1/2 |
Context Precision:注入 prompt 的上下文里,相关 chunk 的占比。第 04 篇做了 Rerank 后,这个指标应该显著上升。
3.2 生成层指标(RAGAS 三件套)
Faithfulness(忠实度):回答里的每条陈述是否都能在检索到的上下文中找到依据。这是防幻觉的核心指标。
1 | 评估方式:LLM-as-Judge,把回答拆成陈述句,逐句问"上下文里有没有依据" |
Answer Relevancy(回答相关性):回答是否回答了用户的问题,还是答非所问。
Context Relevancy(上下文相关性):注入的上下文整体上是否切题。
3.3 LLM-as-Judge 的可信度
RAGAS 这些生成层指标依赖一个”评委 LLM”。评委要可信,必须遵守:
- 盲审:评委不知道哪个是改造前、哪个是改造后,避免顺序偏好。
- 多评委取平均:至少两个模型(如 DeepSeek + 本地 Qwen)打分,分歧大时人工复核。
- 分数而非”好/坏”:让评委输出 1~5 分或百分比,比二分类更有区分度。
- 评委 prompt 里写清楚评分标准,避免主观漂移。
四、指标驱动迭代的完整闭环
1 | ① 收集问题 → ② 标注/生成评估集 → ③ 跑基线评测 |
关键规则:一次只改一个变量。想验证”加 Rerank 有没有用”,就只加 Rerank 跑一次;想验证”换 chunk 大小”,就只改 chunk 大小。同时改三个东西,指标变了你都不知道是哪个的功劳。
4.1 诊断决策树
1 | 看 L2 指标(Faithfulness 低)? |
五、ByteBot 的实测流程(附示例数据)
设计一个可复现的评测脚本 tools/rag-eval/eval.py:
1 | python tools/rag-eval/eval.py \ |
输出示例(改造前后对比):
1 | === 检索层 === |
注:以上数字为示例,实际改造后应跑出真实数据回填。这个脚本会作为系列工具留存,CI 里加一步”评测不劣化”的回归检查(第 11 篇细说)。
5.1 评测的工程化细节
- 每次评测记录 git 环境:评估集版本 + 代码 commit + 检索配置,否则跑完不知道测的是哪一版。
- 评测集要”滚雪球”:每次线上发现回答翻车,就把这个问题追加进评估集。评估集从 70 → 100 → 150,会越来越贴近真实。
- 成本:一次全量评测用 150 个问题 × 2 评委 ≈ 300 次 judge 调用,DeepSeek 下成本约 1 块钱以内,完全可以每天跑。
六、落地清单与小结
| 优先级 | 改造 | 收益 |
|---|---|---|
| P0 | 线上问题埋点落库(脱敏) | 评估集有活水 |
| P0 | 建评估集 v1(真实+生成混合) | 一切指标的前提 |
| P1 | 写 eval 脚本 + 跑基线 | 把”感觉”变成数字 |
| P1 | 一次只改一个变量,逐项验证第 04 篇改动 | 每个优化都有归因 |
| P2 | CI 回归检查(评测不劣化) | 防止后续改坏 |
| P2 | 翻车问题进评估集 | 评估集滚动进化 |
核心结论:
- 先测检索层再测生成层;检索 Recall 低时,生成层指标再高都是幻觉。
- 评估集 = 真实问题(主体)+ RAGAS 生成(扩充)+ 手工刁钻题(边界),且要带
expected_answer_articles标注。 - RAGAS 的 Faithfulness / Relevancy 是标准生成层指标,但评委必须盲审、多模型、打分制。
- 一次只改一个变量,用指标归因每步优化;”感觉更好”不算数。
- 评测不是一次性的,评估集要滚雪球、CI 要回归——这是工程化的护城河。
下一篇转向模型部署:本地模型量化与推理优化。把第 01 篇诊断的”降级路径 3”落地——用 Ollama/vLLM 跑量化模型做 ByteBot 的兜底,并给出量化级别实测对比。
本系列持续更新中,每周一篇。