大模型应用怎么做 A/B 测试?
一句话回答
A/B 测试是把真实用户随机分成两组,分别使用旧方案和新方案(新 Prompt、新模型、新的检索策略),比较真实的业务和质量指标。要按用户分流,同一个用户始终在同一组,否则他在对话中会前后体验不一致,指标也会互相污染;要同时看业务指标、质量指标和成本延迟;大模型的输出波动大,要事先估算样本量,用显著性检验下结论。新方案要先通过离线评测,再从小流量开始,出了问题能随时回滚。
详细解析
上线流程:离线评测、灰度和回滚
离线评测通过 → 小流量灰度(只看错误、安全、成本)→ A/B 实验(看效果)→ 全量
↑ │ │
└───────────── 不达标,回到离线迭代 ←──────────────────┘
离线评测回答"会不会变差、能不能上",便宜、快,但评测集的覆盖有限;A/B 测试回答"真实用户是不是更满意、业务指标有没有变好",结果真实,但慢、有风险。离线评测是 A/B 测试的前置门槛,A/B 测试里发现的问题再补进评测集。灰度和回滚要提前准备好:
- Prompt 版本、模型名放在配置中心或功能开关里,回滚只改配置,不用重新发版
- 设置自动回滚条件:错误率、延迟、费用超过阈值就自动切回旧版本
- 扩大流量时,已经在新版本里的用户不应该被切回去,代码示例里的分桶方式天然满足这一点
按用户分流
- 用"实验 ID + 用户 ID"做哈希,取模分桶。带上实验 ID,不同实验的分组才相互独立,不会总是同一批人进新版本
- 为什么不按请求随机:同一个用户在多轮对话里前后风格不一致;留存、满意度这类以用户为单位的指标没法归因;用户多次重试时会在两组之间来回切换
- 未登录的用户,用设备 ID 或 Cookie 里的标识分流
- 每次请求都记录所在的实验组,日志和 trace 里都要有,事后才能按组分析
看哪些指标
| 类别 | 例子 | 作用 |
|---|---|---|
| 主要指标 | 问题解决率、采纳率、转人工率,选一个 | 决定实验的成败,要在实验开始前定好,不能事后挑 |
| 质量指标 | 点踩率、重新生成率、抽样评分 | 解释为什么变好或变差 |
| 护栏指标 | 错误率、P95 延迟、每次请求的成本、安全拦截率、投诉 | 不能明显变差,否则主要指标再好也不上 |
样本量和显著性
- 大模型的输出有随机性,用户行为本身也有波动,样本少时看到的差异可能只是噪声
- 实验前先估算每组需要的样本量,它取决于基线比率、想检测出的最小提升、显著性水平和统计功效。比如基线解决率是 60%,想检测出提升到 63%,取显著性水平 0.05、功效 80%,每组大约需要 4100 个用户(计算见下面的代码)
- 比率类指标用两比例的 z 检验或卡方检验,费用、时长这类连续指标用 t 检验或 bootstrap
- 不要每天看一眼、一显著就停:反复查看并在显著时停止,会大大提高把无效改动误判为有效的概率。事先定好实验时长,至少覆盖完整的一周(工作日和周末的用户行为不同),或者使用专门的序贯检验方法
代码示例
import { createHash } from 'node:crypto'
// 同一个用户在同一个实验里,总是落在同一个桶(0~99)
function bucketOf(userId: string, experimentId: string): number {
const hex = createHash('sha256').update(`${experimentId}:${userId}`).digest('hex')
return parseInt(hex.slice(0, 8), 16) % 100
}
// 新版本的流量从 5% 放到 50% 时,原来桶号小于 5 的用户仍然在新版本里
function variantOf(userId: string, experiment = { id: 'kb-prompt-v13', treatmentPercent: 5 }) {
return bucketOf(userId, experiment.id) < experiment.treatmentPercent ? 'treatment' : 'control'
}
// 比较两个比率时,每组需要的样本量(双侧显著性水平 0.05,功效 80%)
function sampleSizePerGroup(p1: number, p2: number, zAlpha = 1.96, zBeta = 0.8416): number {
const variance = p1 * (1 - p1) + p2 * (1 - p2)
return Math.ceil(((zAlpha + zBeta) ** 2 * variance) / (p1 - p2) ** 2)
}
sampleSizePerGroup(0.6, 0.63) // 4126
面试官可能追问
实验结果不显著,说明两个版本没区别吗?
不一定,可能只是样本量不够,检测不出这么小的差异。要看差异的置信区间:区间很宽,说明数据不够,结论待定;区间很窄而且包含 0,说明即使有差异也很小,这时可以按成本、延迟等其他因素做决定。不要为了等到显著而无限延长实验。
按用户分流,但指标按对话统计,有什么问题?
同一个用户的多次对话之间不是独立的,直接把每次对话当作独立样本做检验,会低估方差、高估显著性。应该先按用户聚合(比如每个用户的解决率),再做检验;或者使用考虑了这种相关性的方法,比如按用户重采样的 bootstrap。
流量太小,做不了 A/B 测试怎么办?
加强离线评测,用人工或模型对新旧版本做成对比较。先给小范围的内部用户或种子用户试用,收集详细的反馈。也可以对比上线前后的指标,但同期的其他因素(活动、季节、其他改动)会干扰结果,结论要谨慎。
新模型效果更好但更贵,怎么决策?
把成本放进同一本账:比较"每个成功解决的问题的成本",或者估算效果提升带来的业务收益能不能覆盖增加的成本。也不一定二选一,可以按问题难度路由,只把复杂的问题交给贵的模型。
易错点
- 按请求随机分流,同一个用户在两个版本之间来回切换
- 实验中途反复查看结果,一显著就停
- 事后从一堆指标、一堆分组里挑出显著的那个,宣布实验成功
- 只看主要指标,忽略成本和延迟这类护栏指标
AI 模拟面试官
用自己的话回答,AI 对照参考答案打分、指出遗漏,再追问,最多 3 轮
这道题你掌握了吗?
选一个最接近的状态,没掌握的题会出现在"我的进度 · 待复习"里。
学习记录暂存在本机浏览器。登录后自动同步到账号,换设备也能看到。