灰度与 A/B 怎么分
改一句提示词、换一个模型、调一个检索参数——这是 AI 应用里最高频的三类变更,但它们通常既没有 code review,也没有回滚预案,改完直接全量。在确定性系统里这是可以接受的(好在不好一测就知道),在输出是分布的系统里不行。
这篇讲怎么给这类变更建立最小可用的灰度与对照机制。
1. 三类变更都要当成"发布"
提示词变更。 改一句话可能改变整体行为,而且改动通常没有 diff 的习惯——它是配置文件里的一段字符串,或者后台里的一个文本框。
模型变更。 换供应商、换型号、或者供应商更新了权重(你没动,但它变了)。后者尤其隐蔽:你什么都没改,指标掉了。
检索与工具配置变更。 切片大小、top-k、重排开关、工具描述。这些改动的效果通常比换模型还大,而且最容易被当成"调参"随手改。
这三类有一个共同点:它们的效果是分布性的。改完之后单次测试看不出差别,只有跑足够多的样本才知道变好还是变坏。这正是需要灰度而不是直接全量的原因。
2. 分桶键必须稳定
分流的最小要求是:同一个用户在整个实验期间始终落在同一组。
用 user_id 或某个稳定的账号标识做哈希,不要用会话 ID、不要用请求 ID、更不要用随机数。用会话 ID 的后果是同一个用户每次刷新看到的行为不一样——体验碎掉,实验数据也不可用(因为同一用户的行为被分到了两边)。
对未登录用户,用设备 ID 或一条长期 cookie,并在实验期间保持。
还有一个常见错误:分桶之后又在别处按别的键分流(比如网关层按请求随机路由)。两层分流叠加会让分组比例失控。分流点必须只有一个。
3. 影子流量:先在真实流量上跑一遍不返回
提示词或模型变更的第一次验证,不一定要让用户看到。
影子模式是让新版本在真实请求上并行跑一遍,结果只进日志不返回给用户。这样你能拿到:
- 新版本在真实分布上的输出(不是评测集上的)
- 成本与延迟的对比(评测集通常不测这个)
- 输出里有没有出现触发护栏的内容
影子模式的两条约束:成本翻倍(两个版本都跑),以及写操作不能影子跑(只适用于只读的生成类任务,涉及工具调用的不能这么干)。
它适合用来做"这一步值不值得上灰度"的判断,而不是替代灰度——因为不返回给用户,就拿不到用户侧的成功指标。
4. 护栏指标和成功指标要分开
这是 AI 实验里最容易混淆的一处。
护栏指标是不能变差的,它们管的是"不要出事":
- 错误率、超时率、schema 校验失败率
- 单次成本与延迟的 P95
- 触发安全策略的比例
- 用户投诉率、转人工率
成功指标是你想改善的,它们管的是"值不值":
- 任务成功率、用户是否采纳
- 单位成本(应当下降)
- 满意度、重问率
判据很明确:护栏不过就回滚,不管成功指标多好看;成功指标没改善就别放量,因为多一套配置的维护成本是真实的。
5. 样本量要按方差算,不是按感觉
AI 输出的方差比传统 Web 指标大得多。同样两个版本,点击率差 2% 可能几百个样本就显著,而"回答质量"差 2% 可能需要几千个样本。
两条实践建议:
先做一次空跑(A/A 测试)——两边用同一个版本,看指标能自然波动多少。这个波动幅度就是你的噪声基线,比任何理论估算都准。
不要提前看结果就下结论。实验跑了一天看到 B 组领先 15% 就放量,是经典的提前窥探问题——方差大的指标在早期波动剧烈,早期领先经常是噪声。定好样本量再看,或者用序贯检验的方法。
6. 每次只改一个变量
这条听起来是常识,实际最常被违反。典型场景:换模型的同时顺手改了提示词、调了温度、更新了工具描述。结果指标改善了,但你不知道是哪一项起的作用——而下次你还得重新试一遍。
一次一个变量,其余全部钉住。 如果必须一起改(比如新模型需要不同的提示词写法),那就把它当成一次整体方案对比,接受"无法拆分归因"这个事实,并在记录里写清楚。
7. 版本化:提示词、模型、检索配置要一起打版本号
实验要可复现,前提是配置有版本号。至少这三样要一起版本化:
prompt_version 提示词版本(含系统指令与工具定义)
model_version 模型名 + 供应商 + 构建指纹
retrieval_version 切片策略 + top-k + 重排开关
每条请求都要带上这三个版本号写入日志。否则事后看指标时,你无法把"提示词改了"和"模型权重更新了"分开——而这两者都可能在你没动的情况下变化。
还有一处耦合要注意:提示词一改,前缀哈希就变,提示缓存会失效。所以灰度期间缓存命中率会掉,成本会上升,这个上升不是新版本本身更贵。把缓存命中率单独盯住,否则会把缓存冷启动误判成模型变贵(详见《提示缓存怎么才命中》)。
8. 回滚必须是一键的
灰度方案里最重要的一条是能不能立刻回到旧版本。具体要求:
- 旧版本在放量期间继续保留在服务中,不能下线
- 回滚开关是配置级的,不需要重新发布代码
- 回滚之后,实验数据仍然完整(不要把日志一起清掉)
没有一键回滚的灰度等于没有灰度,因为发现问题时你还要走一遍发布流程。
9. 四个常见的实验污染
分流不均。 哈希函数或分桶逻辑有问题,导致 90/10 变成 70/30。放量前先验证实际分组比例。
缓存污染。 A 组的结果被 B 组读到(或反过来)。缓存键必须包含实验分组——这一条和《语义缓存的命中边界》里讲的租户隔离是同一类问题,只是维度换成了实验组。
只看平均值。 AI 指标经常是长尾分布:平均值改善,P95 恶化。成本和延迟尤其要看分位数。
评测集和线上分布不一致。 离线评测集上改善 5%,线上没变化,通常是因为评测集的样本分布和真实流量不一样。这也是为什么评测集要从线上日志里捞(见《评测集怎么变成门禁》)。
10. 什么时候不用做灰度
不是所有变更都值得走一遍流程。三类可以例外:
- 纯修 bug 且影响面明确(比如修一个明显的格式错误)
- 只读的内部工具,出错的代价是慢一点,不是错
- 完全新增的功能,没有对照组可言——这种直接小流量开放,盯紧护栏指标即可
反过来,凡是影响对外答复内容、影响计费、或影响写操作的变更,一律走灰度。这几类出问题都不是"回滚一下就好"能解决的。
灰度机制真正买到的东西不是"更谨慎",是把"我感觉新版本更好"变成"在 N 个样本上,护栏没退化且成功率提高了 X%"。前者是意见,后者是证据。