RAG 评估体系:黄金集、检索指标与 LLM-as-Judge 落地
一句话结论 :RAG 优化必须拆成 检索评估 与 生成评估 两层;LLM-as-Judge 可用,但必须固定 rubric、校准偏差、保留人工抽检。没有评估,所有"优化"都是感觉。
适用版本 :LangChain4j
1.23.0/ JDK21
0. 先说结论
四个问题,决定你有没有"真正的评估":
- 有没有固定数据集?还是每次临时找几个问题?
- 能不能区分"检索没召回"和"模型没答好"?
- 换了 Prompt/分块/Rerank,指标是升还是降?
- 业务方问"效果怎么样",你能不能拿出可复现的数据?
如果答案是否定的,你需要的不是新模型,而是评估体系。
1. 为什么 RAG 评估难
| 难点 | 表现 | 对策 |
|---|---|---|
| 非确定性 | 同一问题多次回答不同 | 固定参数、多次采样、看分布 |
| 多阶段 | 检索/重排/生成都可能错 | 分层评估,定位到阶段 |
| 缺标注 | 没有"标准答案" | 建黄金集,人工+规则 |
| 成本高 | 每次评估都调模型 | 分层:离线/夜间/抽样 |
| 指标多 | 不知道看哪个 | 一主两辅,业务指标优先 |
RAG 不是"一个模型调用",而是一条流水线。用单一"答案对不对"评估,无法定位问题。
1.1 一个"没有评估"的代价
团队改了一版 Prompt,内部试了几个问题,觉得"回答更自然了",直接上线。
一周后投诉增加:
- 新 Prompt 更爱自由发挥,引用变少;
- 简单问题变长,延迟上升;
- 旧版能答对的政策问题,新版开始编造。
没有基线、没有黄金集,团队只能靠"感觉"回滚。回滚后又无法证明旧版更好。
没有评估,你连"回滚"都无法证明是对的。
2. 评估分三层
| 层 | 评什么 | 指标 | 何时跑 |
|---|---|---|---|
| 检索层 | 正确文档有没有被召回/排前 | Recall@K、MRR、nDCG@K | 每次改分块/检索 |
| 生成层 | 回答是否基于证据、是否相关 | Faithfulness、Answer Relevance | 每次改 Prompt/模型 |
| 端到端 | 用户是否得到正确答案 | 人工正确率、任务完成率 | 发布前/每周 |
#mermaid-svg-aBLvE6i6WVfUnRQ8{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-aBLvE6i6WVfUnRQ8 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-aBLvE6i6WVfUnRQ8 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-aBLvE6i6WVfUnRQ8 .error-icon{fill:#552222;}#mermaid-svg-aBLvE6i6WVfUnRQ8 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-aBLvE6i6WVfUnRQ8 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-aBLvE6i6WVfUnRQ8 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-aBLvE6i6WVfUnRQ8 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-aBLvE6i6WVfUnRQ8 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-aBLvE6i6WVfUnRQ8 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-aBLvE6i6WVfUnRQ8 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-aBLvE6i6WVfUnRQ8 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-aBLvE6i6WVfUnRQ8 .marker.cross{stroke:#333333;}#mermaid-svg-aBLvE6i6WVfUnRQ8 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-aBLvE6i6WVfUnRQ8 p{margin:0;}#mermaid-svg-aBLvE6i6WVfUnRQ8 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-aBLvE6i6WVfUnRQ8 .cluster-label text{fill:#333;}#mermaid-svg-aBLvE6i6WVfUnRQ8 .cluster-label span{color:#333;}#mermaid-svg-aBLvE6i6WVfUnRQ8 .cluster-label span p{background-color:transparent;}#mermaid-svg-aBLvE6i6WVfUnRQ8 .label text,#mermaid-svg-aBLvE6i6WVfUnRQ8 span{fill:#333;color:#333;}#mermaid-svg-aBLvE6i6WVfUnRQ8 .node rect,#mermaid-svg-aBLvE6i6WVfUnRQ8 .node circle,#mermaid-svg-aBLvE6i6WVfUnRQ8 .node ellipse,#mermaid-svg-aBLvE6i6WVfUnRQ8 .node polygon,#mermaid-svg-aBLvE6i6WVfUnRQ8 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-aBLvE6i6WVfUnRQ8 .rough-node .label text,#mermaid-svg-aBLvE6i6WVfUnRQ8 .node .label text,#mermaid-svg-aBLvE6i6WVfUnRQ8 .image-shape .label,#mermaid-svg-aBLvE6i6WVfUnRQ8 .icon-shape .label{text-anchor:middle;}#mermaid-svg-aBLvE6i6WVfUnRQ8 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-aBLvE6i6WVfUnRQ8 .rough-node .label,#mermaid-svg-aBLvE6i6WVfUnRQ8 .node .label,#mermaid-svg-aBLvE6i6WVfUnRQ8 .image-shape .label,#mermaid-svg-aBLvE6i6WVfUnRQ8 .icon-shape .label{text-align:center;}#mermaid-svg-aBLvE6i6WVfUnRQ8 .node.clickable{cursor:pointer;}#mermaid-svg-aBLvE6i6WVfUnRQ8 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-aBLvE6i6WVfUnRQ8 .arrowheadPath{fill:#333333;}#mermaid-svg-aBLvE6i6WVfUnRQ8 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-aBLvE6i6WVfUnRQ8 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-aBLvE6i6WVfUnRQ8 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-aBLvE6i6WVfUnRQ8 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-aBLvE6i6WVfUnRQ8 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-aBLvE6i6WVfUnRQ8 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-aBLvE6i6WVfUnRQ8 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-aBLvE6i6WVfUnRQ8 .cluster text{fill:#333;}#mermaid-svg-aBLvE6i6WVfUnRQ8 .cluster span{color:#333;}#mermaid-svg-aBLvE6i6WVfUnRQ8 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-aBLvE6i6WVfUnRQ8 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-aBLvE6i6WVfUnRQ8 rect.text{fill:none;stroke-width:0;}#mermaid-svg-aBLvE6i6WVfUnRQ8 .icon-shape,#mermaid-svg-aBLvE6i6WVfUnRQ8 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-aBLvE6i6WVfUnRQ8 .icon-shape p,#mermaid-svg-aBLvE6i6WVfUnRQ8 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-aBLvE6i6WVfUnRQ8 .icon-shape rect,#mermaid-svg-aBLvE6i6WVfUnRQ8 .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-aBLvE6i6WVfUnRQ8 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-aBLvE6i6WVfUnRQ8 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-aBLvE6i6WVfUnRQ8 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-aBLvE6i6WVfUnRQ8 .data>*{fill:#0F2A1D!important;stroke:#22C55E!important;color:#E8EEF9!important;stroke-width:2px!important;}#mermaid-svg-aBLvE6i6WVfUnRQ8 .data span{fill:#0F2A1D!important;stroke:#22C55E!important;color:#E8EEF9!important;stroke-width:2px!important;}#mermaid-svg-aBLvE6i6WVfUnRQ8 .data tspan{fill:#E8EEF9!important;}#mermaid-svg-aBLvE6i6WVfUnRQ8 .system>*{fill:#111A2E!important;stroke:#4F8CFF!important;color:#E8EEF9!important;stroke-width:2px!important;}#mermaid-svg-aBLvE6i6WVfUnRQ8 .system span{fill:#111A2E!important;stroke:#4F8CFF!important;color:#E8EEF9!important;stroke-width:2px!important;}#mermaid-svg-aBLvE6i6WVfUnRQ8 .system tspan{fill:#E8EEF9!important;}#mermaid-svg-aBLvE6i6WVfUnRQ8 .metric>*{fill:#2A1F3D!important;stroke:#A78BFA!important;color:#E8EEF9!important;stroke-width:2px!important;}#mermaid-svg-aBLvE6i6WVfUnRQ8 .metric span{fill:#2A1F3D!important;stroke:#A78BFA!important;color:#E8EEF9!important;stroke-width:2px!important;}#mermaid-svg-aBLvE6i6WVfUnRQ8 .metric tspan{fill:#E8EEF9!important;}#mermaid-svg-aBLvE6i6WVfUnRQ8 .judge>*{fill:#2A1F0B!important;stroke:#F5A524!important;color:#E8EEF9!important;stroke-width:2px!important;}#mermaid-svg-aBLvE6i6WVfUnRQ8 .judge span{fill:#2A1F0B!important;stroke:#F5A524!important;color:#E8EEF9!important;stroke-width:2px!important;}#mermaid-svg-aBLvE6i6WVfUnRQ8 .judge tspan{fill:#E8EEF9!important;}#mermaid-svg-aBLvE6i6WVfUnRQ8 .report>*{fill:#1E293B!important;stroke:#94A3B8!important;color:#E8EEF9!important;stroke-width:2px!important;}#mermaid-svg-aBLvE6i6WVfUnRQ8 .report span{fill:#1E293B!important;stroke:#94A3B8!important;color:#E8EEF9!important;stroke-width:2px!important;}#mermaid-svg-aBLvE6i6WVfUnRQ8 .report tspan{fill:#E8EEF9!important;} 黄金集
query + 标注
被测系统
检索 + 生成
检索指标
Recall/MRR/nDCG
生成指标
Faithfulness/Relevance
LLM Judge
- 人工抽检
报告/看板
版本对比
图 1:分层评估。检索指标与生成指标分开看,才能定位问题。
2.1 端到端指标与业务指标
| 指标 | 定义 | 业务含义 |
|---|---|---|
| Answer Correctness | 回答与参考答案一致 | 答对了吗 |
| Task Completion | 用户任务是否完成 | 解决问题了吗 |
| Citation Accuracy | 引用是否可验证 | 可信吗 |
| Escalation Rate | 转人工比例 | 省人力了吗 |
| CSAT/Thumbs | 用户反馈 | 满意吗 |
技术指标(Recall/Faithfulness)用于定位;业务指标用于证明价值。两者都要有,但不要混为一谈。
2.2 评估前先回答四个问题
- 评什么:检索、生成,还是端到端?
- 为什么评:选型、回归,还是向业务证明?
- 阈值是什么:下降多少算退化?
- 谁来决策:指标不达标时,谁拍板回滚?
没有这四个答案,评估会变成"跑一堆数字,没人用"。
3. 黄金集:评估的地基
3.1 规模与来源
| 项 | 建议 |
|---|---|
| 规模 | 200--500 条起步 |
| 来源 | 真实用户问题 + 业务专家补充 |
| 难度 | easy / medium / hard 分层 |
| 类型 | 事实型、流程型、对比型、否定型、多跳型 |
| 标注 | 相关文档/块 + 参考答案 + 关键点 |
| 版本 | 数据集版本化,变更可追溯 |
3.2 数据结构
json
{
"id": "q001",
"query": "退货时效是几天?",
"relevant_chunk_ids": ["policy-2026-11#3"],
"reference_answer": "签收后 7 天内可无理由退货。",
"key_points": ["7 天", "签收后"],
"difficulty": "easy",
"type": "fact"
}
3.3 三个原则
- 不要用训练/调参用过的数据做最终评估:留 hold-out;
- 覆盖真实分布:不要只挑简单问题;
- 标注可复核:谁标的、依据什么、版本何时。
黄金集不是"一次性作业"。业务变化、文档更新后,要补充与修订。
3.4 黄金集的构建流程
| 步骤 | 产出 | 负责人 |
|---|---|---|
| 1. 收集 query | 真实问题/日志脱敏 | 产品/运营 |
| 2. 去重分类 | 事实/流程/对比/否定/多跳 | 标注负责人 |
| 3. 标注证据 | relevant_chunk_ids | 业务专家 |
| 4. 写参考答案 | reference_answer + key_points | 业务专家 |
| 5. 交叉复核 | 双人标注/仲裁 | 技术负责人 |
| 6. 冻结版本 | golden-v1.jsonl |
工程 |
标注时最容易犯的错:只标"最相关的一个块",忽略同义块、父子块、多个正确来源。评估时会误判为"没召回"。
3.5 黄金集的维护
- 每月把线上真实失败案例补进数据集;
- 每季度做一次全量复核,删除过时问题;
- 新增问题要标注难度与类型,保持分布;
- 数据集变更写 changelog,版本号递增;
- 不要把调参用过的样本放进最终测试集。
黄金集会"老化":业务变了、文档变了,旧问题可能不再有意义。维护它,比一次性建 1000 条更有价值。
4. 检索指标:先看有没有召回到
4.1 Recall@K
text
Recall@K = 前 K 个结果中包含的相关文档数 / 全部相关文档数
它回答:"正确证据有没有进候选集?"如果 Recall@K 低,后面的重排/生成都无从谈起。
4.2 MRR
text
MRR = 平均(1 / 第一个相关结果的排名)
它关注"第一个正确结果有多靠前",适合"只需要一条证据"的问答。
4.3 nDCG@K
nDCG 考虑相关性等级与位置折扣,适合"多条证据、相关性有强弱"的场景。
| 指标 | 关注 | 适用 |
|---|---|---|
| Recall@K | 覆盖率 | 多证据、召回评估 |
| MRR | 首个正确结果位置 | 单证据问答 |
| nDCG@K | 排序质量 | 有分级相关性 |
4.4 常见陷阱
- 用"答案对不对"代替检索指标,无法定位;
- K 取太大,Recall 好看但上下文噪声高;
- 标注只标一个块,忽略同义/重复块;
- 不区分"没召回"和"召回了但没排前"。
4.5 指标计算示例
假设一条 query 有 3 个相关块,检索 Top-5 中命中了 2 个,位置分别是 2 和 5:
text
Recall@5 = 2 / 3 ≈ 0.67
MRR = 1 / 2 = 0.5
如果只命中位置 5 的一个块:
text
Recall@5 = 1 / 3 ≈ 0.33
MRR = 1 / 5 = 0.2
这两组数字不是 Benchmark,只是计算示例。它们说明:Recall 看覆盖,MRR 看首个命中的位置,两者不能互相替代。
nDCG 还要考虑相关性等级(如 2/1/0)与位置折扣。实现时固定折损函数与等级定义,否则跨版本不可比。
5. 生成指标:回答是否基于证据
| 指标 | 定义 | 关注 |
|---|---|---|
| Faithfulness | 回答中的结论是否能被上下文支持 | 不编造 |
| Answer Relevance | 回答是否切题 | 不跑题 |
| Context Precision | 上下文中相关内容的占比 | 噪声 |
| Context Recall | 回答所需信息是否都在上下文 | 漏证据 |
| Citation Accuracy | 引用是否指向真实证据 | 可验证 |
这些指标可以由规则、模型或人工评估。数字/否定/条件类问题,建议人工抽检比例更高。
5.1 生成指标的计算思路
- Faithfulness:把回答拆成若干 claim,逐条检查是否能被上下文支持;
- Answer Relevance:根据回答反推问题,看是否与原问题语义一致;
- Context Precision:上下文中相关块的比例/排序;
- Context Recall:回答所需信息是否都能在上下文中找到。
text
faithfulness = 被证据支持的 claim 数 / 总 claim 数
这些指标可以由 Judge 或人工计算。关键是固定"claim 拆分规则"和"支持判定标准",否则不同批次不可比。
6. LLM-as-Judge:能用,但要校准
6.1 两种模式
| 模式 | 做法 | 优点 | 缺点 |
|---|---|---|---|
| Pointwise | 给单个回答打分 | 简单、可批量 | 分数尺度不稳定 |
| Pairwise | 比较两个回答 | 更稳定、适合 A/B | 成本翻倍 |
6.2 常见偏差
| 偏差 | 表现 | 缓解 |
|---|---|---|
| 位置偏差 | 偏好第一个/最后一个 | 交换顺序跑两次 |
| 冗长偏差 | 偏好更长的回答 | rubric 明确"简洁" |
| 自我偏好 | 偏好同模型输出 | 多模型交叉评审 |
| 顺从偏差 | 被 Prompt 引导 | 盲评、隐藏系统信息 |
| 分数漂移 | 不同批次标准不一 | 固定 rubric/版本 |
6.3 Judge Prompt 模板
text
你是严格的评审员。只依据给定证据评分,不要使用外部知识。
评分维度:
1. 忠实度(0-2):结论是否都能被证据支持
2. 相关性(0-2):是否回答了用户问题
3. 引用(0-2):引用是否指向证据中的原文
输出 JSON:{"faithfulness":0,"relevance":0,"citation":0,"reason":"..."}
6.4 校准
- 人工标注 50--100 条,和 Judge 分数对比;
- 计算一致性(如 Spearman/Cohen's kappa);
- 一致性低时,先改 rubric,不要直接信 Judge;
- 定期抽检,防止模型/数据漂移。
langchain4j-test在 1.23 增强了 LLM Judge 能力,可用于回归;具体 API 以版本为准。
6.5 Judge 的工程实现
java
// 伪代码:固定 rubric + 低温度 + JSON 输出
String prompt = judgeTemplate
.replace("{question}", c.query())
.replace("{answer}", r.answer())
.replace("{context}", r.context());
JudgeResult score = chatModel.chat(prompt, JudgeResult.class);
工程要求:
- temperature 设低(如 0),减少波动;
- 输出 JSON,带 reason;
- 保存原始输入/输出,便于复核;
- 失败重试一次,仍失败标为
UNKNOWN,不要默认满分; - Judge 版本号写入报告。
不要用 Judge 的分数直接做"绝对质量"结论;它更适合版本间相对比较。
6.6 Judge 的抽样校验
| 步骤 | 做法 |
|---|---|
| 抽样 | 每次评估抽 10% 人工复核 |
| 双人 | 两名评审独立打分 |
| 一致性 | 计算一致率/kappa |
| 仲裁 | 分歧样本由第三人裁定 |
| 反馈 | 不一致的 rubric 条款要修订 |
Judge 与人工一致性低,不代表 Judge 一定错;也可能是 rubric 模糊。先修 rubric,再修模型。
7. 评估流水线
java
// 伪代码:批量评估
for (EvalCase c : dataset) {
Result r = system.answer(c.query());
retrieval.add(recallAtK(c.relevantChunkIds(), r.retrievedIds(), 5));
retrieval.add(mrr(c.relevantChunkIds(), r.retrievedIds()));
judge.add(judge.score(c, r)); // 固定 rubric
}
report(dataset.version(), retrieval, judge);
流水线要固定:
- 数据集版本;
- 系统版本(模型/Prompt/分块/索引);
- 参数(temperature、Top-K);
- 运行时间与环境。
否则两次报告不可比。
7.1 评估成本控制
| 策略 | 做法 | 节省 |
|---|---|---|
| 分层 | 检索每次跑,生成夜间跑 | 模型调用 |
| 抽样 | 全量检索 + 10% 生成 | 成本 |
| 缓存 | 相同输入复用结果 | 重复评估 |
| 小模型 | Judge 用小模型 | 成本 |
| 批处理 | 合并请求 | 网络/调用 |
评估本身也是成本中心。先保证"能定位问题",再追求"统计显著"。
8. CI 与看板
| 层 | 频率 | 是否阻塞合并 |
|---|---|---|
| 单元/契约测试 | 每次提交 | 是 |
| 检索指标回归 | 每次改检索 | 是(阈值) |
| 生成 Judge 回归 | 每日/发布前 | 视成本 |
| 人工抽检 | 每周 | 否,但必须做 |
阈值建议(示例,需按业务校准):
- Recall@5 下降 >5%:阻塞;
- Faithfulness 下降 >5%:阻塞;
- 答案正确率下降 >3%:人工复核。
看板至少展示:指标趋势、版本对比、失败案例、成本。
8.1 评估报告模板
| 字段 | 内容 |
|---|---|
| 数据集 | 名称 + 版本 + 条数 |
| 系统版本 | 模型、Prompt、分块、索引版本 |
| 参数 | temperature、Top-K、Rerank |
| 检索指标 | Recall@K / MRR / nDCG |
| 生成指标 | Faithfulness / Relevance / Citation |
| 端到端 | 人工正确率/任务完成率 |
| 失败案例 | Top-5 典型失败 |
| 成本 | Token/金额/耗时 |
| 结论 | 发布/回滚/继续观察 |
报告要能回答:"和上一版比,哪里变好、哪里变差、为什么。"
8.1 看板指标设计
| 区域 | 内容 | 作用 |
|---|---|---|
| 趋势 | Recall/Faithfulness/正确率 | 是否退化 |
| 版本对比 | 当前 vs 上一版 | 变更影响 |
| 失败案例 | Top-5 典型失败 | 定位问题 |
| 延迟/成本 | P95/Token/金额 | 是否可接受 |
| 覆盖率 | 评估样本/真实流量 | 代表性 |
看板不是"数字越多越好"。一屏能回答三个问题:变好了吗?哪里变差?为什么?
9. 常见误区
- 只评估最终答案:无法定位检索/生成;
- 用同一批数据调参又评估:过拟合;
- Judge 分数当真理:不做人工校准;
- 指标越多越好:没有主指标,无法决策;
- 评估一次就结束:数据/模型漂移后失效;
- 忽略成本:评估本身也烧 Token。
9.1 一个评估驱动的优化案例
现象:用户反馈"退货政策答错"。
评估:
- Recall@5 低 → 正确块没进候选;
- 失败案例集中在表格类问题;
- 分块把表格切断了。
优化:表格转 Markdown、整表成块、补版本元数据。
复评:Recall@5 提升,Faithfulness 提升,引用能定位到表格块;生成指标没有下降。
结论:问题在摄取,不在模型。没有分层评估,团队可能会去换模型,浪费两周。
10. FAQ
黄金集要多大?
200--500 条起步,覆盖主要问题类型;先求"能定位问题",再求"统计显著"。
没有人工标注怎么办?
先用业务专家标 50--100 条,后续用 Judge 扩展,但保留人工抽检。
LLM-as-Judge 能完全替代人工吗?
不能。它适合批量回归与趋势,不适合作为唯一标准;高风险场景必须人工复核。
检索指标和生成指标哪个更重要?
先看检索。检索没召回,生成指标再好也是"基于错误证据的正确废话"。
评估要跑真实模型吗?
检索指标不需要;生成指标需要模型或 Judge。CI 里可以分层:检索每次跑,生成夜间跑。
10.1 评估与灰度发布
text
离线评估 → 影子流量 → 小流量灰度 → 全量
- 离线评估:黄金集 + 分层指标,决定是否值得上;
- 影子流量:真实请求并行跑新旧系统,不影响用户;
- 灰度:1% → 10% → 50%,观察业务指标;
- 回滚条件:正确率/延迟/成本任一超阈值。
离线好不等于线上好。真实 query 分布、长度、用户行为都可能不同。评估要延伸到线上。
10.2 评估与成本优化
成本优化也要评估:
- 换小模型后,正确率下降多少?
- 缩短上下文后,Faithfulness 是否下降?
- 关闭 Rerank 后,nDCG 损失多少?
没有这些数据,"降本"很容易变成"降质"。把成本作为评估报告的一列,而不是财务月底才发现。
10.3 评估失败的常见信号
- 指标很好,但用户投诉变多;
- Judge 与人工一致性持续走低;
- 数据集只有简单问题;
- 每次评估结果波动很大;
- 没有人看报告;
- 指标不达标也没有人回滚。
出现任意两条,说明评估体系需要重建,而不是继续加指标。
10.4 评估要与模型解耦
同一个检索结果,可以喂给不同模型做生成评估;同一个模型,也可以对比不同检索配置。解耦后,你才能判断"是检索的问题,还是模型的问题"。把检索指标和生成指标混在一起,是最常见的归因错误。先分层,再归因,这是评估的第一原则;否则你会在错误的方向上优化非常久,请务必记住。
11. 上线检查清单
- 有版本化黄金集;
- 有 hold-out 集;
- 检索/生成指标分开;
- Judge 有固定 rubric;
- Judge 做过人工校准;
- CI 有阈值与回滚;
- 有失败案例库;
- 报告记录数据/系统版本;
- 评估成本有预算;
- 每季度复核数据集。
11.1 评估数据的版本管理
- 数据集文件命名带版本:
golden-v1.jsonl; - 每次变更写 changelog:新增/修改/删除原因;
- 旧版本保留,支持回滚;
- 报告必须引用数据集版本,否则不可比;
- 数据集与代码同仓库/同制品库管理。
没有版本管理,三个月后你无法解释"为什么同一套系统指标变了"。
11.1 评估成熟度模型
| 级别 | 状态 | 特征 |
|---|---|---|
| L0 | 无评估 | 靠感觉/投诉 |
| L1 | 人工抽检 | 有案例,无指标 |
| L2 | 黄金集 + 指标 | 可版本对比 |
| L3 | CI 回归 | 自动阻塞退化 |
| L4 | 线上评估 + 漂移监控 | 持续闭环 |
大多数团队应该先到 L2,再谈 L3/L4。不要一开始就搭复杂平台。
12. 系列导航
- 上一篇:A10《Rerank 与上下文工程:重排、压缩与引用溯源的收益边界》
- 下一篇:A12《Spring Boot 4 集成:@AiService、多模型路由与多租户隔离》
- 全系列:《LangChain4j 生产级实战》20 篇路线图(专栏内查看)