可以同时,但要把“发布放量(灰度)”和“AB 实验”分层解耦,否则很容易出现样本污染、时序偏差、指标被放量节奏干扰等问题。下面给你一套落地做法(从策略到实现细节),直接照着搭就行。
结论先给
- 优先级:发布放量 > AB 实验。 先决定谁能看到新功能,再在这批人里做实验分桶。
- 样本范围:AB 的对照/实验两组都应来自“放量可见的同一人群”。 这样控制两组在环境与版本上一致。
-
节奏:要么“先稳后测”,要么“嵌套测”。
- 稳妥型:先用小流量灰度稳定,再在稳定区间做 AB。
- 快速型:在当前放量范围内嵌套 AB(见下文“嵌套式”)。
推荐的两种模式
A. 分阶段(稳妥)
- Canary/小流量灰度(如 1%→5%):只看稳定性、性能与关键风控指标,不做效果评估。
- 阶段性冻结放量(比如停在 10% 2\~3 天):在这 10% 内做 AB(50/50 或 90/10 取决于统计功效)。
- 实验得出结论后继续放量(按结果决定是否扩大开关默认值/参数)。
**优点:**干扰因素最少,结论更干净。
**缺点:**整体上线速度稍慢。
B. 同步进行(嵌套式)
- 在当前rollout 范围内(如已放到 20%),对这 20% 再做 AB(比如 50%/50%)。
- 实验只在这 20% 内产生曝光与采样,不要跨到未放量的 80%。
**优点:**快。
风险点:放量比例变化会带来时间变动的混杂因素(新老用户构成不同、学习/新鲜度效应)。见下文的防范措施。
核心实现要点(工程与数据)
1) 双层开关与一致性分桶(Sticky Bucketing)
-
层 1:放量灰度开关
- 逻辑:
in_ramp = hash(uid, "feature_ramp") % 100 < rollout_pct
- 只决定“是否有资格进入实验/看到功能”的外层门禁。
- 逻辑:
-
层 2:AB 实验开关
- 逻辑(仅对
in_ramp == true
的用户执行):
bucket = hash(uid, "exp:123") % 100
treatment = bucket < exp_treatment_pct
- 对照组与实验组都在同一代码版本/同一放量人群内,仅参数/开关不同。
- 逻辑(仅对
注意:hash 需稳定且带命名空间盐值(如 feature 名/实验 ID),避免不同实验相互干扰。
2) 优先级与兜底
- 优先级:Kill-switch(紧急关闭) > 灰度放量 > AB 实验 > 个性化/GR 检查。
- 一处评估(服务端),各端“粘性缓存”一段时间,但服务端仍然是权威(避免端上漂移)。
- 移动端要考虑离线与延迟:评估结果带有效期,过期后重拉。
3) 指标与日志
-
三类曝光日志都要打:
ramp_exposed
(进入灰度圈)experiment_assigned
(分到 A/B 哪组)feature_used
(真正被功能触达/使用)
- 做**ITT(意向到处理)与ATC(实际触达)**两套视图:前者反映策略价值,后者反映功能真实效益。
4) 与其他实验的互斥/并行
- 建立实验互斥组(同一页面/同一关键指标、互相影响大的实验不要并行)。
- 若必须并行,用域名空间或层级 allocator保证不同实验独立哈希与总配额上限(例如同页实验总共不超过 50% 流量)。
同步进行时的统计风险与对策
风险 1:放量比例变动导致时间混杂
- 对策 A:在实验的“测量窗口”内冻结 rollout_pct(强烈推荐)。
-
**对策 B:**若必须边放边测:
- 记录首曝时间与**“放量批次”标签**,做分层或协变量校正(如 CUPED / 回归控制)。
- 使用分布对齐(把对照/实验两组在首曝周次、地域、设备等维度对齐)。
风险 2:样本污染(跨版本/跨参数)
- 对策:分桶粘性;参数更新时更改版本号并入日志,过滤“跨版本切换期”的样本或做版本分层。
风险 3:连续监控带来的假阳性
- 对策:采用序贯检验(SPRT)或组序贯/贝叶斯框架;预先定义停表规则和最小可检测效应(MDE)。
风险 4:功效不足
- 对策:先做样本量计算(根据基线、MDE、α/β);不够就延长时间或提高放量/实验比例。
参考落地模板(伪代码)
// 评估入口(服务端)
def evaluateFeature(uid):
if isEmergencyOff("featureX"):
return OFF
// 灰度放量层
in_ramp = hash(uid, "featureX_ramp") % 100 < rollout_pct // e.g., 20
if not in_ramp:
return OFF // 不在实验总体母体内
// 实验层(只在 in_ramp 内)
bucket = hash(uid, "exp:featureX_v1") % 100
if bucket < 50: // 50% 实验
variant = "treatment"
enabled = true
else:
variant = "control"
enabled = false // 同一版本,参数关闭
logExposure(uid, ramp=in_ramp, exp="featureX_v1", variant=variant)
return enabled
运维与流程建议
- 发布面板:独立展示放量与实验的两条曲线与两套看板(护栏指标如崩溃率、延迟、错误率;业务指标如转化/留存)。
-
变更规范:
- 任何扩大
rollout_pct
的操作,需标注“是否处于实验测量窗口”,默认禁止在窗口内改。 - 实验开始/结束、参数版本号变更、紧急回滚都要自动写审计日志。
- 任何扩大
- 回滚策略:任一护栏指标越界→先关实验(保持灰度),若仍不恢复→关灰度(回到 0%)。
什么时候不建议同时做?
- 新功能对稳定性风险高(内核改动、资源消耗大)。
- 关键峰值期(大促/版本大迁移),更适合先稳后测。
一句话指南
同时做可以,但务必“外层灰度、内层 AB;冻结放量测量窗口;日志打全;分桶粘性;护栏优先”。
如果你愿意,我可以给你一份可直接接入的流量分配器代码(Go/Java/Node/Swift/Kotlin)和看板指标模板。