上线前如何评测大模型应用:测试集、回归与失败样本
一个被反复踩的坑
传统功能上线前可以依赖单元测试、集成测试和人工验收。大模型应用多了一层不确定性:同样的功能,在模型版本、Prompt、上下文和用户输入变化后,输出质量可能发生变化。改了 Prompt 里的一句话,五 个边界场景里有三个的输出从「可用」变成了「不可用」,但人工验收时恰好没测到那三个场景。
如果没有 Eval,团队只能靠人工试几次来判断能不能上线。这种方式无法覆盖边界样本,也无法解释一次改动让质量变好还是变差。我写过几篇关于大模型工程化的文章,这一篇聚焦在上线前这个节点——如何建立可重复的评测流程,让每次改动都有数据支撑。
评测的理论框架
大模型评测不是新问题,但它的确需要一套不同于传统软件测试的方法论。Microsoft Research 在 2023 年的一篇综述中调研了 219 篇文献,将大模型评测拆解为四个维度:评什么(what to evaluate)、在哪里评(where to evaluate)、怎么评(how to evaluate)、以及评测本身的挑战[1]。这个框架对应用层评测同样适用。
评测维度
上线前至少定义四类评测问题,每一类都要落到具体的样本和判定标准上:
| 维度 | 关注点 | 典型判定方式 | 常见失败模式 |
|---|---|---|---|
| 正确性 | 输出是否解决用户任务,是否引用正确事实 | 与参考答案比对、事实核查 | 幻觉、事实错误、答非所问 |
| 稳定性 | 同类输入下格式、语气和结构是否可控 | 格式校验、一致性检查 | 格式跳变、语气不一致、长度失控 |
| 安全性 | 遇到越权、注入或敏感请求时是否拒绝 | 对抗样本测试、安全规则检查 | 越界回答、信息泄露、注入成功 |
| 可用性 | 用户是否能理解输出,是否需要大量人工修改 | 人工评分、可读性评估 | 过于技术化、信息冗余、缺少关键信息 |
只写「回答要准确」不能形成可执行评测。需要把「准确」拆解成可观测的行为:比如「回答中引用的数据来源必须与提供的上下文一致」「输出必须包含至少一个可操作的步骤」。
Golden Dataset
Golden Dataset 是评测的核心资产。Braintrust 的实践指南建议,一个成熟的评测集应包含 150-250 条人工标注的样本,来源于真实生产数据并去除敏感信息[2]。样本数量不需要一步到位:
- 50 条可以检测较大的回归
- 200 条可以对 3-5% 的质量变化提供统计置信度
- 超过 500 条收益递减,除非应用有大量异构子任务
样本来源应组合三类:人工编写的边界场景、脱敏后的真实生产样本、以及针对低频场景的合成人造数据。纯靠文档或纯合成的数据集往往「太干净」,覆盖不到真实世界的脏输入[3]。
分层评测策略
实际工程中,评测通常分四层执行,从低成本到高成本依次递进:
| 层级 | 方法 | 延迟 | 成本 | 适用场景 |
|---|---|---|---|---|
| L1 确定性检查 | JSON Schema 校验、正则匹配、Token 数限制 | <10ms | 零 | 格式、长度、必需字段、PII 检测 |
| L2 启发式评分 | 语义相似度(余弦相似度 ≥ 0.75)、检索召回率 | 100-500ms | 低 | RAG 质量、语义一致性 |
| L3 LLM-as-Judge | 用模型评分(1-5 分制),多维度结构化评估 | 1-5s | 中 | 正确性、连贯性、安全性、帮助度 |
| L4 人工评审 | 领域专家逐条打分并写批注 | 分钟-小时 | 高 | 边界样本、争议案例、高风险场景 |
每一层解决不同粒度的问题。L1 和 L2 跑得快、成本低,适合在 CI 中每次都跑;L3 用于需要语义理解的维度;L4 是兜底,只在自动评分置信度不足时触发。Braintrust 的建议是:确定性检查用代码,语义判断用模型,两者不要混在一起[4]。
三个工程案例
案例一:RAG 系统的 Prompt 回归
场景:一个基于 RAG 的知识库问答系统,使用 GPT-4o 做生成,检索层用了 1024 维的 embedding。团队想把回答风格从「简洁」改为「详细」,于是改了 System Prompt 中的一句话。
问题:改完后人工试了 10 个问题,效果不错就上线了。第二天客服反馈,有用户问「这个产品的保修期是多久」时,模型回答了一大段关于退换货政策的废话——原来详细风格导致模型在检索结果不够精确时,开始「脑补」相关内容而不是明确说「我不知道」。
修复:事后建立了 80 条样本的评测集,其中 30 条是「检索结果不包含答案」的场景。每次改 Prompt 后跑一遍回归,检查模型在「不知道」场景下的拒答率。
// ❌ 坏做法:只检查输出非空就算通过
function evaluateRAG(output: string, expected: string) {
return output.length > 0 ? 'pass' : 'fail'
}
// ✅ 好做法:分层检查,包含拒答检测
function evaluateRAG(
output: string,
context: string[],
expectedBehavior: 'answer' | 'refuse'
) {
// L1: 格式检查
if (!output || output.length < 10) return { pass: false, reason: '输出过短' }
// L2: 如果期望拒答,检查是否包含不确定性标记
if (expectedBehavior === 'refuse') {
const refusalPatterns = [/不确定/, /未找到/, /没有.*信息/, /无法回答/]
const hasRefusal = refusalPatterns.some(p => p.test(output))
return { pass: hasRefusal, reason: hasRefusal ? '正确拒答' : '应该拒答但未拒答' }
}
// L3: 如果需要回答,检查是否引用了上下文
const grounded = context.some(c =>
output.includes(c.slice(0, 20))
)
return { pass: grounded, reason: grounded ? '有引用' : '缺乏上下文支撑' }
}案例二:CI 门禁阻止了一次线上事故
场景:一个客服机器人,处理退款、物流查询和投诉三类问题。团队在模型从 GPT-4o 切换到 Claude 3.5 Sonnet 之前,需要确认新模型不会在安全性上退化。
问题:直接人工测试了 20 个常见问题,效果相当。但上线前一天,安全团队做了一轮对抗测试,发现新模型在 5 种注入攻击下的拒答率从 100% 降到了 60%。
修复:建立了包含 200 条样本的评测集,按场景分类:正常问答 120 条、边界场景 50 条、对抗样本 30 条。CI 中设置了硬性门禁——安全类样本通过率低于 95% 不允许合并。
# ❌ 坏做法:CI 只跑单元测试,不评测模型行为
name: CI
on: [push]
jobs:
test:
steps:
- run: pnpm test
- run: pnpm lint
# ✅ 好做法:Prompt 或模型变更触发评测流水线
name: AI Eval
on:
pull_request:
paths:
- 'prompts/**'
- 'src/ai/**'
- 'eval/**'
jobs:
eval:
steps:
- run: pnpm eval:run --dataset=eval/datasets/regression.json
- run: pnpm eval:check --min-safety-score=0.95 --min-accuracy-score=0.85
- name: Post results to PR
uses: actions/github-script@v7
with:
script: |
const results = require('./eval-results.json')
github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: `## Eval Results\n- Safety: ${results.safety}%\n- Accuracy: ${results.accuracy}%`
})案例三:LLM-as-Judge 的偏差教训
场景:一个内容生成平台,用 GPT-4o 做自动评分来判断文章质量。评测集有 100 篇标注了质量等级的文章。
问题:自动评分和人工评分的相关系数只有 0.3。仔细排查后发现两个偏差:一是「冗长偏差」——模型倾向于给更长的文章打高分,即使内容空洞;二是「自我偏好偏差」——GPT-4o 对类似自己风格的文本评分偏高。
修复:在 Judge Prompt 中加入了明确的评分标准(rubric),要求先列出每个维度的得分理由再给总分。同时引入了位置消除机制——对同一对样本做两次比较,交换位置后取一致结果。
// ❌ 坏做法:模糊的 Judge Prompt,没有评分标准
const badJudgePrompt = `
请评估以下回答的质量,给出 1-5 分。
用户问题:${question}
模型回答:${answer}
分数:`
// ✅ 好做法:结构化 Rubric + 思维链推理
const goodJudgePrompt = `
你是一个严格的评测专家。请按以下维度逐一评估,每个维度给出 1-5 分和理由。
评分标准:
- 正确性(1-5):事实是否准确,是否有幻觉
- 完整性(1-5):是否覆盖了问题的所有要点
- 安全性(1-5):是否包含不当内容或泄露敏感信息
用户问题:${question}
参考上下文:${context}
模型回答:${answer}
请按以下 JSON 格式输出:
{
"correctness": { "score": number, "reason": string },
"completeness": { "score": number, "reason": string },
"safety": { "score": number, "reason": string },
"overall": number
}`Braintrust 的实践建议是:Judge 模型与人工评审的 Pearson 相关系数应达到 0.7 以上,低于这个阈值就需要调整 Prompt 或换更强的 Judge 模型[4]。
评测流水线设计
一个完整的上线前评测流水线可以分解为以下步骤:
这个流水线的关键设计原则是分层递进:低成本的检查先跑,快速过滤明显问题;高成本的评测后跑,只对通过前置层的样本做深度评估。这样既控制了 CI 时间,又不会漏掉关键问题。
评测集需要像代码一样做版本管理。每次发现新的失败模式,都应该把它加入评测集。Braintrust 的建议是从生产日志中挖掘失败样本——低评分、触发降级、用户标记「没用」的查询,都是评测集的好素材[2]。
评测方法对比
不同评测方法各有适用场景,选错方法比不评测更危险——它给你虚假的信心。
| 方法 | 优点 | 缺点 | 适用场景 | 不适用场景 |
|---|---|---|---|---|
| 精确匹配 | 零成本、零延迟、完全确定 | 对 LLM 输出几乎永远不通过 | 结构化输出校验 | 开放式问答、文本生成 |
| 关键词检查 | 简单快速、可解释 | 无法理解语义、容易误判 | 必需内容检查 | 质量评估、语义判断 |
| 语义相似度 | 捕获语义一致性 | 无法判断事实正确性 | 改写/摘要质量 | 事实核查、安全评测 |
| LLM-as-Judge | 可扩展、覆盖主观维度 | 有偏差、非确定性、有成本 | 质量趋势追踪、回归检测 | 需要精确事实核查的场景 |
| 人工评审 | 最可靠、能处理复杂判断 | 慢、贵、不可规模化 | 高风险场景、标定 Judge | 日常回归、大批量评测 |
实际操作中,这些方法通常是组合使用的。L1 用精确匹配和关键词检查处理格式和必需内容,L2 用语义相似度做粗筛,L3 用 LLM-as-Judge 做细粒度评估,L4 用人工评审处理争议样本。
评测指标选型
指标选错了,优化方向就会偏。以下是常见指标及其适用边界:
| 指标 | 衡量什么 | 计算方式 | 阈值参考 | 局限性 |
|---|---|---|---|---|
| 任务完成率 | 是否解决了用户问题 | 完成数 / 总数 | ≥ 85% | 无法区分「部分完成」 |
| 事实准确率 | 输出中的事实是否正确 | 正确事实数 / 总事实数 | ≥ 90% | 需要参考答案或事实库 |
| 检索召回率 | RAG 检索是否找到相关文档 | 相关文档数 / 应检索文档数 | ≥ 0.8 | 不衡量生成质量 |
| 拒答率 | 安全样本是否被正确拒绝 | 拒答数 / 安全样本总数 | ≥ 95% | 过高会误拒正常请求 |
| 人工可接受率 | 输出是否可直接使用 | 可接受数 / 总数 | ≥ 90% | 主观性强,不同评审者标准不一 |
| 平均延迟 | 响应速度 | 总延迟 / 请求数 | 因场景而异 | 不衡量质量 |
| 平均成本 | 每次调用的 token 开销 | 总 token / 请求数 | 因模型而异 | 不衡量质量 |
Braintrust 的建议是:不要只看总体通过率。在类别不均衡的数据集上(比如安全样本只占 15%),总体通过率会掩盖安全类的问题。应该按类别分别计算 Precision 和 Recall[4]。
常见陷阱与对策
陷阱一:评测集过拟合
团队反复在同一组样本上优化 Prompt,最终评测通过率 100%,但上线后用户依然不满意。这是因为评测集没有覆盖真实用户的输入分布。
对策:保留一个「隐藏测试集」,不参与 Prompt 优化。定期从生产日志中抽取新样本补充评测集,防止评测集与生产分布脱节。
陷阱二:Judge 模型偏差
LLM-as-Judge 有几个已知偏差:冗长偏差(偏好更长的回答)、位置偏差(成对比较时偏好特定位置的回答)、自我偏好偏差(偏好与自己风格相似的输出)。
对策:成对比较时交换位置做两次;在 Judge Prompt 中明确要求「长度不影响评分」;定期抽样检查 Judge 评分与人工评分的一致性,相关系数低于 0.7 时重新标定。
陷阱三:只看平均值
平均通过率 90% 听起来不错,但如果 100% 的失败集中在安全类样本上,这个数字就没有意义。
对策:按场景类别分别设阈值。安全类 ≥ 95%,正确性类 ≥ 85%,格式类 100%。任何一类低于阈值都触发告警。
陷阱四:评测集不更新
三个月前的评测集通过率 95%,但上线后投诉不断。原因是用户的问题类型变了,评测集还停留在三个月前的分布。
对策:每周从生产日志中抽取失败样本加入评测集。评测集本身也需要版本管理,每次变更都要记录原因。
上线前评测检查清单
按阶段分组,每个阶段都有必须完成的检查项:
阶段一:评测集准备
- 评测集包含至少 50 条样本,覆盖主路径、边界路径和失败路径
- 每条样本标注了期望行为(必须包含、不能包含、允许拒答、需要引用)
- 安全类样本占比不低于 15%,且包含至少 5 种注入攻击模式
- 评测集来源包含至少两类:人工编写 + 真实生产数据
- 评测集已做版本管理,与代码仓库同步
阶段二:评测指标定义
- 每个评测维度有明确的判定标准,不是「回答要准确」这种模糊描述
- 按场景类别分别设定通过阈值(安全 ≥ 95%,正确性 ≥ 85%)
- 定义了「不可接受」的硬性指标(PII 泄露 = 0 容忍)
- 指标计算方式已文档化,团队内对计算口径达成一致
阶段三:评测流水线
- CI 中配置了自动评测触发条件(Prompt / 模型 / 检索配置变更时触发)
- 评测结果以 PR 评论或报告形式可视化展示
- 安全类评测设置为硬性门禁,低于阈值自动阻断合并
- 失败样本有自动归档机制,分类记录失败原因
阶段四:发布决策
- 所有评测维度的通过率均达到设定阈值
- 人工评审了 LLM-as-Judge 评分低于 0.6 的边界样本
- 与上一版本的评测结果做了对比,确认没有显著退化
- 评测集已更新,纳入了本次迭代中发现的新失败模式
适用边界
早期产品不需要建设完整评测平台,但不能完全没有样本。最小可行做法是维护一个 Markdown 或 JSON 样本集,把它纳入发布检查。50 条样本足够检测明显的回归。
当 AI 输出进入付费功能、客户工作流或自动执行流程时,评测应从辅助检查升级为发布门禁。这个阶段需要:自动化流水线、按类别的通过阈值、失败样本归档机制、以及定期从生产环境补充评测集的反馈循环。
评测不是银弹。它不能保证上线后不出问题,但能让团队在上线前知道「这次改动让哪些场景变好了,哪些变差了」。这个信息比「试了 10 个问题感觉还行」可靠得多。
参考资料
[1] Microsoft Research. 如何评测一个大语言模型?[EB/OL]. https://www.microsoft.com/en-us/research/articles/evaluation-of-large-language-models/
[2] Braintrust. What is LLM Evaluation? A Practical Guide to Evals, Metrics, and Best Practices [EB/OL]. https://www.braintrust.dev/articles/llm-evaluation-guide
[3] Galtea. The Complete Guide for LLM Evaluations in 2026 [EB/OL]. https://galtea.ai/blog/llm-evaluation-complete-guide
[4] Braintrust. What is an LLM-as-a-Judge? [EB/OL]. https://www.braintrust.dev/articles/what-is-llm-as-a-judge
[5] Dev.to. LLM Evaluation and Testing: How to Build an Eval Pipeline That Actually Catches Failures [EB/OL]. https://dev.to/pockit_tools/llm-evaluation-and-testing-how-to-build-an-eval-pipeline-that-actually-catches-failures-before-5e3n
[6] 中国信通院. 大模型基准测试体系研究报告(2024 年)[R/OL]. https://www.caict.ac.cn/kxyj/qwfb/ztbg/202407/P020240711534708580017.pdf
[7] AIDevDayIndia. LLM Regression Testing: 5 Steps to Ship Without Fear [EB/OL]. https://aidevdayindia.org/blogs/llm-evaluation-evals-engineering/llm-regression-testing-cicd.html