出报告
上一篇把 RAGAS 的五个坑讲完了——同源偏置、单跑方差、中文 NaN、成本失控、Judge 误判。你现在知道哪些分数差异是真的,哪些是噪声,怎么用多轮取均值压制方差,怎么用人工校准修正误判。
指标也全算完了。_scores.json 里躺着十几个指标的 overall、by_intent_l1、by_intent_l2、per_sample——从意图准确率到 TTFT P50,从 faithfulness 到 answer_correctness,该有的都有了。
然后呢?
打个比方,你考完试了,答题卡已经批完了,每道题的分数 都有了。但你把一张写满分数的 Excel 发到班级群里,家长看得懂吗?班主任能拿着这张表在家长会上讲两分钟吗?你自己能从里面一眼看出哪个知识点最弱、下一步该补哪块吗?
评测报告也是一样的道理。_scores.json 是原始成绩单,但不同的人需要不同的呈现方式。CI 脚本只需要一个 JSON 判阈值,研发需要看逐样本明细找具体问题,老板需要打开浏览器看几个大数字和一张漂亮的看板。
这篇讲怎么把指标变成不同角色能消费的报告——三种人,三种产物,一套数据源。
报告产物总览
1. 三类受众,各看什么
想一想你平时工作里的场景:
- CI 流水线只需要一个 JSON,判断 Hit@5 有没有跌破 90%,跌了就阻断合入——它不需要看图表,不需要看失败样本,只需要一个布尔值
- 研发同事想知道哪几条样本最差、差在哪个环节——需要逐样本的明细表和失败归因,能直接定位到具体 query
- 技术负责人要在周会上花两分钟看一眼系统质量——需要几个大数字加一张漂亮的看板,翻几页就能讲完
一份报告服务不了这三种需求。所以评测产出拆成了五个文件,各司其职:
| 产物 | 文件路径 | 受众 | 格式 | 用途 |
|---|---|---|---|---|
_scores.json | reports/<run>/ | CI / 自 动化脚本 | JSON | 所有指标的全量数据,给脚本读 |
report.md | 同目录 | 研发 / Reviewer | Markdown | 指标总览 + 意图切片表 |
per_sample.csv | 同目录 | 研发 / Reviewer | CSV | 逐样本明细 + 人工复核列 |
failures.jsonl | 同目录 | 研发 / Reviewer | JSONL | 失败样本归因,一行一条 |
slides.html | 同目录 + reports/latest_slides.html | 老板 / 周会 | HTML | 16:9 横向翻页,浏览器全屏演示 |
所有产物都在 reports/<run>/ 目录下。<run> 是 runs 文件的名称,类似 v1_20260601_143022——哪一次录制产生的结果,一目了然。
2. 数据怎么流的:三段缓存
五个产物不是各自独立生成的,它们共享同一个数据源 _scores.json。而 _scores.json 本身也不是凭空出来的——整个评测的数据流是三段式的,每段产物独立缓存:

用一句话概括这个设计的核心思路:录制一次,评分 N 次,报告 M 次。
runner 跑一次调两个接口,成本最高(RAGAS 要花钱调 judge),录好之后落 runs/*.jsonl。score 阶段从 runs 文件算指标,改了 judge 模型或调了参数之后可以复用同一份 runs 重跑——不花接口费。report 阶段从 _scores.json 渲染各种产物,秒级出结果——改失败判定阈值、调报告格式、重跑人工校准,都不需要重新调被评系统的接口。
三段缓存互不耦合,这是优化过程中反复跑评测的基础。
给研发看的三份报告
研发需要的是能直接定位问题的信息:整体水平怎么样、哪个场景最差、哪几条样本出了什么问题。这三份文件从粗到细,覆盖了研发 review 评测结果的完整流程。
1. report.md:一页纸总览
report.md 由 markdown.py 的 write_all() 函数生成,包含三部分内容:
自建指标总览表:按 BASELINE_ORDER 列出 13 个自建指标——intent_top1、Hit@1/3/5/10、Recall@1/3/5/10、MRR@10、误拒率、错答率、TTFT 等,每个给出 overall 值。一眼看到系统各个环节的健康度。
RAGAS 指标表:5 个 RAGAS 指标的 overall 值——faithfulness、answer_relevancy、answer_correctness、context_precision、context_recall。语义层面的质量判断。
二级意图切片表:这是这份报告最有价值的部分。每个二级意图一行,列出该意图下的核心指标值。
切片表的价值在哪?举个例子:overall Hit@5 = 90%,看起来还不错。但切到 by_intent_l2 一看,S1_选购推荐 只有 60%,S14_退换货咨询 是 100%。退换货类问题检索得很好,但选购推荐类一半以上没命中——90% 的 overall 把一个严重问题给掩盖了。
优化资源永远有限。切片表让你知道该把精力集中在哪几个意图场景上,而不是眉毛胡子一把抓。
2. per_sample.csv:逐样本明细 + 人工复核列
report.md 告诉你哪个意图最差,per_sample.csv 让你钻到每一条样本里去看。
每行一条评估样本,列分三组:
| 列类型 | 包含内容 |
|---|---|
| 基础信息列 | query_id、intent_l1、intent_l2、difficulty、requires_rag、final_status |
| 指标值列 | 所有指标的 per_sample 值(Hit@5 是 0 或 1、faithfulness 是 0~1 的浮点数等) |
| 人工复核列 | 5 个 *_manual 空列(对应 5 个 RAGAS 指标) |
前两组好理解,重点说人工复核列。上一篇讲过 RAGAS 偶尔会误判——judge 给某条样本的 faithfulness 打了 0.3,但你人工看过之后发现回答完全忠实于上下文,只是拆 claim 的方式有问题。这时候不需要重跑 RAGAS(贵且慢),直接在 CSV 里改就行。