AB实验平台将实验配置、流量分配与效果分析流程产品化,支撑推荐系统的持续迭代。介绍实验生命周期管理、分层正交实验与指标看板设计,分析在多实验并行场景下如何保障流量隔离与统计有效性。通过代码示例、架构图与生产经验分享,帮助AI工程师掌握从技术原型到大规模生产的完整工程落地与持续优化能力。

岗位关联

连锁餐厅要做一道新菜,主厨不会直接把它印进菜单。他会先开一个小档口,请几百位顾客试吃:A 组尝新配方,B 组尝老配方,记下每桌顾客夹了几筷子、是否复点、嫌不嫌上菜慢。跑满两周后算一笔账——新配方真的更好吗?值得为它更换整条供应链吗?这套“试吃评审”搬到互联网产品上,就是 AB 实验平台:它管理实验的诞生、试跑、决策与归档,用分层正交把几十个并行实验的流量切得互不干扰,再通过指标看板和统计检验,把“感觉有效”变成“证据有效”。本文就用这家“算法餐厅”的故事,带你完整看懂 AB 实验平台从配置、分流、观测到决策的工程全貌。 对 AI 从业者的价值:掌握 AB 实验平台,你才能用数据证据证明模型改进的真实价值,完成从“模型能跑”到“业务真赚”的最后一公里。

目录
  1. 可视化演示
  2. 实验生命周期
  3. 分层正交实验
  4. 流量分配机制
  5. 指标看板设计
  6. 统计有效性保障
  7. 实验结果解读
  8. 工程化落地
  9. 实战经验沉淀
  10. AI 应用场景
  11. Python 演示
  12. 常见误区
  13. 面试题

可视化演示

演示AB实验平台核心流程:用户流量分流、分层正交哈希分组与指标显著性检验,直观展示多实验并行的流量隔离与统计判断方法。

本节配有交互动效(进入视口后自动加载,约 3KB)。

流量分配 用户流量按比例分流 实验组A / 对照组B 策略变更经AB验证后全量上线

实验生命周期

一家大餐厅要推新菜,不会直接把菜谱塞给后厨,而是先走一张“试吃登记表”:菜名叫什么、给哪几桌试吃、试吃多久、记录哪些反馈、谁拍板。实验在 AB 平台里的生命周期,就是这张登记表的产品化版本。算法团队想验证新推荐模型时,就登录平台“创建一次实验”:选一个空闲的域和层、填流量比例、勾选要看的指标、提交审批。审批通过后实验自动上线,到期自动停流,最终生成一份结算报告归档。

技术上讲,一个实验会经历四个不可跳过的状态:创建(configured)、运行(running)、停止(stopped)、归档(archived)。平台在创建时做三类校验:层冲突校验,防止两个实验在同一层叠加;流量校验,确保各实验分配的桶数之和不溢出;埋点校验,确认指标字段已经在数据管道里登记。运行中支持实时查看累计数据和预期剩余天数;停止后进入结算,产出报告供评审。

依赖关系的管理是平台“工业化”的起点。新厨师不知道什么时候该收档口,系统用这套状态机帮他自动收。对 AI 工程师来说,生命周期意味着“实验可追溯、决策有记录”:每个模型改动都有对应的实验报告,代码评审和效果评审在平台上闭环,而不是散落在聊天记录里。

状态(e)={创建,t<tstart运行,tstart≤t<tstop停止,tstop≤t<tarchive归档,t≥tarchive\text{状态}(e) = \begin{cases} \text{创建}, & t < t_{\text{start}} \\ \text{运行}, & t_{\text{start}} \le t < t_{\text{stop}} \\ \text{停止}, & t_{\text{stop}} \le t < t_{\text{archive}} \\ \text{归档}, & t \ge t_{\text{archive}} \end{cases}
实验像一道菜,从“登记”到“进档案”,由时间节点自动推动状态流转。
  1. 创建状态实验配置完成后,在设定的开始时间之前一直处于创建态,此时可修改参数。
    t<tstart⇒创建t < t_{\text{start}} \Rightarrow \text{创建}
  2. 运行状态到达开始时间后自动切流,进入运行态,开始积累两组数据。
    tstart≤t<tstop⇒运行t_{\text{start}} \le t < t_{\text{stop}} \Rightarrow \text{运行}
  3. 停止状态到达预定结束时间后停流,数据进入结算,不再引入新用户。
    tstop≤t<tarchive⇒停止t_{\text{stop}} \le t < t_{\text{archive}} \Rightarrow \text{停止}
  4. 归档状态结算报告生成后归档,实验进入历史库,供后续查询复盘。
    t≥tarchive⇒归档t \ge t_{\text{archive}} \Rightarrow \text{归档}

分层正交实验

餐厅同一天开多个试吃档口:1 号档试新宫保鸡丁,2 号档试新奶茶。规则是每个档口独立发券——1 号档给“尾号 0-3”的顾客,2 号档给“尾号 4-7”的顾客。同一位顾客可能同时拿到两张券,但他在 1 号档吃新菜,不影响在 2 号档喝老奶茶。这就是“分层”:每个实验层独立抽样、互不干扰。

推荐系统通常会同时改很多东西:召回模型、排序模型、重排策略、冷启动参数。如果所有实验都在同一份流量上叠加,A 模型带来的收益会被 B 策略的副作用掩盖。分层正交的解法是:用 user_id 拼上“层盐值”做哈希,每个层从零开始重新切一遍。用户在排序层进了实验组,在召回层可能就进了对照组——两层各算各的账。

正交的本质是“层之间独立随机”,就像每个档口独立洗牌。域的引入则进一步做物理隔离:推荐域、搜索域、广告域各自拥有独立流量池,域间根本不分桶,彻底避免业务面交叉污染。学习分层正交时,最重要的心法就是记住:流量是用户的,但实验是层的。

bucket(u,l)=H(user_id:saltl) mod N\text{bucket}(u, l) = H(\text{user\_id} \mathbin{:} \text{salt}_l) \bmod N
同一个用户像同一位顾客,在 1 号档拿新菜券、在 2 号档拿老奶茶券,互不牵连。
  1. 拼接层盐把用户 ID 与层专属的盐值拼成一个新字符串,让每层拥有独立的随机源。
    key=user_id:saltl\text{key} = \text{user\_id} \mathbin{:} \text{salt}_l
  2. 哈希映射对 key 做 MD5 或同类均匀哈希,输出在数值空间上近似均匀分布。
    h(key)=MD5(key)h(\text{key}) = \text{MD5}(\text{key})
  3. 取模落桶对哈希结果取 128 的模,得到桶号 0-127,保证不同用户被均匀撒进所有桶。
    bucket=h(key) mod 128\text{bucket} = h(\text{key}) \bmod 128

流量分配机制

一道新菜要让 3% 还是 30% 的顾客试吃?如果档口按“桌号尾号”发券,那么 3% 就是 3 个尾号,30% 就是 30 个尾号。AB 平台里,桶(bucket)就是档口号:把全量用户通过一致性哈希切成 128 个或 1024 个桶,配置实验时选定一部分桶进入实验组,其余桶留在对照组。

为什么强调“用户维度稳定”?同一个用户每次登录,哈希结果必须完全一样,否则他一会儿在实验组、一会儿在对照组,两组数据就变成一锅粥。分桶算法用用户 ID 而不是请求 ID,就是为了让“试吃资格”跟人绑定,而不是跟每次进店绑定。增量调配也很自然:想从 10% 扩到 30%,只需把实验组的桶数从 13 个增加到 38 个(128 桶下),不需要重新洗牌。

流量分配这门手艺,最怕的是“桶不均匀”。所以生产系统会先离线跑一遍分桶分布,再周期性地用 AA 实验验证:两组基线指标不应有显著差异。流量一旦均匀且稳定,实验结论才值得信赖。

bucket(u)=H(user_id) mod 128,Pexp⁡=∣E∣128\text{bucket}(u) = H(\text{user\_id}) \bmod 128, \qquad P_{\exp} = \frac{|\mathbb{E}|}{128}
档口号由用户 ID 的哈希决定,永不临时抽签;试吃量从 10% 提到 30%,只是多画几个桶,顾客不被惊动。
  1. 哈希取桶对用户 ID 哈希后取 128 的模,得到 0-127 的固定桶号。
    bucket(u)=H(user_id) mod 128\text{bucket}(u) = H(\text{user\_id}) \bmod 128
  2. 配置实验组平台把一组桶号划给实验组,比如 $\mathbb{E} = \{0,1,\ldots,25\}$。
    E={b1,b2,…,bk}\mathbb{E} = \{ b_1, b_2, \ldots, b_{k} \}
  3. 计算流量占比实验组桶数除以总桶数,就是实验流量百分比。
    Pexp⁡=∣E∣128P_{\exp} = \frac{|\mathbb{E}|}{128}

指标看板设计

试吃开始前,服务员手里要先有一张评分纸:夹了几筷子、是否复点、上菜慢了没有。AB 平台也一样,实验上线前就要设计好“评分纸”——指标看板。看板分两类:核心指标是实验最想优化的目标,比如推荐场景的点击率、转化率、人均曝光时长;护栏指标是业务绝不能受伤的底线,比如首屏时延、负反馈率、次留。

指标看板背后是完整的埋点链路:前端上报曝光和点击事件,经消息队列进入实时流计算,秒级刷新大盘;同时原样落数仓,离线任务每晚全量回刷,修正实时链路丢点带来的口径偏差。看板既要回答“现在差多少”,也要回答“差得是否可信”——所以看板上每个核心指标都带置信区间和预计显著性日期。

指标设计决定实验的上限。只盯点击率可能牺牲时长,只盯时长可能牺牲留存。成熟的平台会把“核心 + 护栏 + 长期”三层指标都固化在看板模型里,任何实验上线前必须全部勾选,缺一不可。

CTR=点击用户数曝光用户数×100%\text{CTR} = \frac{\text{点击用户数}}{\text{曝光用户数}} \times 100\%
评分纸要提前印好,而不是等顾客吃完再问“你刚才吃了啥”。
  1. 分子定义点击用户数按用户去重,避免同一个人狂点十次把比率拉爆。
    分子=∣{u∣u 有点击事件}∣\text{分子} = |\{ u \mid \text{u 有点击事件} \}|
  2. 分母定义曝光用户数同样按用户去重,代表真正被推荐触达的人群。
    分母=∣{u∣u 有曝光事件}∣\text{分母} = |\{ u \mid \text{u 有曝光事件} \}|
  3. 求比率分子除以分母再乘 100,得到可解释的百分数。
    CTR=点击用户数曝光用户数×100%\text{CTR} = \frac{\text{点击用户数}}{\text{曝光用户数}} \times 100\%

统计有效性保障

试吃只安排了 10 位顾客,碰巧 8 位说好吃,你敢把菜写进百城菜单吗?样本太少,结论就是运气。AB 实验开跑前,必须回答:“至少请多少位顾客试吃,才能让结论靠谱?”答案写在样本量公式里。

公式中,$p$ 是对照组基线转化率,$\delta$ 是希望检测到的最小提升,$\alpha$ 为显著性水平,$1-\beta$ 为统计功效。直观理解:基线越稳、想检测的提升越小、对错误越不能容忍,需要的试吃人数就越多。用这个公式,平台能在实验启动前预估所需天数——如果按当前流量要跑 60 天,就得决定“加流量”还是“放宽检测目标”。

实验结束后的显著性检验同样关键:比较两组的均值差和方差,计算 $p$ 值。$p < 0.05$ 只说明“差异不太像随机抖动”,不代表“收益一定大”。多个实验同时看结果时还要做多重比较校正,否则 20 个实验每人卡 5% 的假阳性线,整体误报率会飙升到 64%。统计有效性,是整个试吃评审的公信力地基。

n≈(zα/2+zβ)2⋅p(1−p)δ2n \approx \frac{(z_{\alpha/2} + z_{\beta})^2 \cdot p(1-p)}{\delta^2}
就像为一场试吃定预算:想精确到小数点后两位的满意度差异,就得请足够多的人,而且基线方差越大,预算越高。
  1. 取显著性临界值$\alpha=0.05$ 时,$z_{\alpha/2}=1.96$,控制“假阳性”风险。
    zα/2=1.96(α=0.05)z_{\alpha/2} = 1.96 \quad (\alpha = 0.05)
  2. 取功效系数$\beta=0.2$ 时,$z_{\beta}=0.84$,保证 80% 概率能检测出真实差异。
    zβ=0.84(β=0.2)z_{\beta} = 0.84 \quad (\beta = 0.2)
  3. 基线方差项$p(1-p)$ 是对照组的固有波动,基线越接近 50%,波动越大。
    p(1−p)p(1-p)
  4. 除以最小提升平方想检测的提升越小,$\delta^2$ 越小,需要的样本量越大。
    n≈(zα/2+zβ)2⋅p(1−p)δ2n \approx \frac{(z_{\alpha/2} + z_{\beta})^2 \cdot p(1-p)}{\delta^2}

实验结果解读

试吃结束后要结算:实验组人均夹了两口半,对照组两口,看着提升了 25%。但聪明的店长会先做一次“假试吃”:把同一道菜分给两组顾客,理论上两组评分应该完全一样。如果连 AA 实验都不一致,说明档口位置、上菜顺序、评分员偏好存在偏差,正式实验的结论也不能轻信。

完整的结果解读决策链是:先看 AA 校准,确认分流没歪;再看核心指标相对提升与置信区间,确认效应不是噪声;然后下钻细分人群,警惕辛普森悖论——整体看涨 5%,拆到新老客可能一个涨 10%、一个跌 8%;最后结合护栏指标与长期效应做出决策:推全、回滚、还是延长时间继续观察。

长期效应是新手最容易忽略的一环。短期点击率提升,可能来自新鲜感;两周后留存反而下降。因此结果解读不能只看实验窗口,还要跟踪“转全量后 14 天”的长期指标曲线。实验平台的意义,正是把这一整套判断流程沉淀成标准动作,避免每次凭感觉拍板。

相对提升=xˉ实验组−xˉ对照组xˉ对照组×100%\text{相对提升} = \frac{\bar{x}_{\text{实验组}} - \bar{x}_{\text{对照组}}}{\bar{x}_{\text{对照组}}} \times 100\%
看完评分纸和假试吃记录,再决定这道菜进不进正式菜单。
  1. 计算实验组均值对实验组每个用户的指标取平均,得到 $\bar{x}_{\text{实验组}}$。
    xˉ实验组=1ne∑i=1nexi\bar{x}_{\text{实验组}} = \frac{1}{n_e}\sum_{i=1}^{n_e} x_i
  2. 计算对照组均值同样取对照组平均,作为“老配方”的基线水平。
    xˉ对照组=1nc∑j=1ncxj\bar{x}_{\text{对照组}} = \frac{1}{n_c}\sum_{j=1}^{n_c} x_j
  3. 求相对提升两组均值之差除以基线,消除绝对量级带来的误读。
    相对提升=xˉe−xˉcxˉc×100%\text{相对提升} = \frac{\bar{x}_{e} - \bar{x}_{c}}{\bar{x}_{c}} \times 100\%

工程化落地

档口开得再漂亮,背后也离不开传菜电梯、冷藏柜和调料间。AB 平台的工程化,就是这座后厨的管道系统。第一层是数据管道:曝光、点击事件经 SDK 上报,走 Kafka 进实时计算引擎,为看板提供秒级指标;同时原始日志落 Hive 数仓,离线任务晚间回刷,保证口径一致可对账。第二层是配置中心:实验参数被缓存在内存里,线上请求在本地完成分桶,而不是每次都查数据库,将分桶耗时压到微秒级。

监控告警是后厨的消防系统:要盯分流成功率——实验组和对照组的请求量比例是否符合预期;要盯数据延迟——实时指标多久没更新了;要盯显著性异动——实验组指标突然暴涨暴跌,往往不是模型变好了,而是数据链路断了。为此平台定义 p95 延迟指标:95% 的请求延迟控制在某个阈值内,保证分桶逻辑没有拖垮主链路。

一键回滚是最后的安全带:实验配置在配置中心秒级生效,发现问题时把实验组桶数清零即可立即止血。工程上永远假设“新模型会闯祸”,所以灰度发布、双跑校验、回滚演练要常态化。这套基础设施,让算法团队敢放心大胆地频繁试错。

P(延迟≤T)=0.95P(\text{延迟} \le T) = 0.95
传菜电梯 95% 的趟次都能在 30 秒内到桌,才算没有拖后腿。
  1. 定义延迟分布延迟是一个随机变量,每请求一次记录一次耗时。
    latency∼F(t)\text{latency} \sim F(t)
  2. 写出分位约束p95 表示累计概率达到 0.95 时对应的延迟值不超过目标。
    F(T)=P(延迟≤T)=0.95F(T) = P(\text{延迟} \le T) = 0.95
  3. 工程理解如果 p95 延迟超限,说明分桶或日志上报拖慢了真正推荐逻辑,需要优化。
    Tp95=F−1(0.95)T_{\text{p95}} = F^{-1}(0.95)

实战经验沉淀

开过一百家档口的老师傅,会留下一本《试吃手册》:什么季节适合推新品、哪些菜系试吃成本高、尾号发券会不会得罪熟客。AB 平台的发展同样是经验沉淀的过程。自建平台初期,很多团队以为“写个函数分桶 + 拉个表算 p 值”就够了,跑过几轮才发现:没有生命周期管理,实验烂尾没人收;没有分层,实验互相污染;没有看板,结论全靠跑数小哥手动拼 SQL。

常见坑点榜上第一是“切分不等价”:实验组与对照组在用户属性上分布不均,导致差异根本不是模型带来的,而是人群本身就不同。第二是“交叉影响”:多个实验同时上线但没分到不同层,结论张冠李戴。最佳实践则包括:AA 实验常态化,每次新实验上线前先跑一轮 AA;样本量预评估;上线后持续追踪长期指标;每次复盘沉淀成文档回填平台的知识库。

团队协作上,算法工程师负责提出假设和解读结论,数据工程师保障埋点与数仓口径,平台工程师维护分桶稳定性和看板性能。三方通过实验平台这张“契约”协作:算法不碰数据管道,数据不碰模型参数,平台不碰业务判断。AB 实验平台最终沉淀的,不只是工具,更是一套“用证据说话”的团队文化。

ROI=实验带来的业务收益工程与流量成本\text{ROI} = \frac{\text{实验带来的业务收益}}{\text{工程与流量成本}}
试吃手册一代代更新,新厨师不用从零踩坑;平台也在手册的滋养下成长为团队的基础设施。
  1. 量化收益收益来自提升率乘业务规模,比如点击率提升 1% 带来的 GMV 增量。
    收益=提升率×业务基数\text{收益} = \text{提升率} \times \text{业务基数}
  2. 量化成本成本包括开发工时、实验期间损失的探索流量、以及数据计算资源。
    成本=C工程+C流量\text{成本} = C_{\text{工程}} + C_{\text{流量}}
  3. 做决策ROI 大于 1 才值得投入,否则不如把时间花在别处。
    ROI=收益成本\text{ROI} = \frac{\text{收益}}{\text{成本}}

AI 应用场景

推荐排序模型的灰度评估

阶段:模型上线前的效果验证与决策

解决的问题:新双塔排序模型在离线 AUC 上提升 0.3%,但离线指标与线上业务指标经常不一致。传统做法是直接全量上线,风险高、出问题难排查;AI 方式是通过 AB 平台在推荐域划出 20% 流量,分层正交地运行新老模型 7 天,用指标看板同时观察 CTR、人均时长和负反馈率三个指标。

具体案例:某资讯 App 新排序模型实验组 CTR 相对提升 4.2%(p<0.01),但护栏指标“人均曝光时长”下降 2.1%。团队因此没有贸然推全,而是再跑一周观察长期留存,确认时长下降来自新模型压缩了低质内容后,才决定全量。

冷启动探索策略的长期观测

阶段:策略调参与探索类实验

解决的问题:冷启动探索参数(如 $\epsilon$-greedy 的探索概率)对短期点击率有负面影响,但能提升新用户次日留存。常规“跑三天看 CTR”的评估方式会误杀这类长线策略。AB 平台通过实验生命周期管理把实验设为运行 14 天,并启用“长期指标”看板追踪新用户 7 日留存。

具体案例:某短视频平台将探索概率从 0.1 调到 0.2 的实验组,第 1 周 CTR 略降 0.8%,第 2 周新用户 7 日留存率提升 5.3%,结论从“回滚”反转成“推全”,验证了长期观测的价值。

跨团队共享流量池的实验治理

阶段:多团队并行的实验资源调度

解决的问题:推荐组、搜索组、广告组共用同一批用户流量,如果各自为政地切割流量,会互相挤占且统计失真。AI 方式是平台统一管理“域”与“层”,各部门在各自的层里跑实验,共享流量池但统计上互不干扰。

具体案例:某电商大促期间,推荐组、首页信息流组、营销弹窗组在同一入口同时上线 12 个实验,通过分层正交和统一指标看板,12 个实验全部获得独立结论,无一个因流量打架而返工。

Python 演示

python73 行
import hashlibimport mathimport random  def bucket_of(user_id, layer_salt, num_buckets=128):    """用户在第 layer_salt 层被稳定分到 0~127 的某个桶"""    key = "%s:%s" % (user_id, layer_salt)    digest = hashlib.md5(key.encode("utf-8")).hexdigest()    return int(digest[:8], 16) % num_buckets  class ExperimentLayer(object):    """一个实验层:由层盐值和实验组桶集合定义"""     def __init__(self, name, salt, exp_buckets):        self.name = name        self.salt = salt        self.exp_buckets = set(exp_buckets)     def group(self, user_id):        if bucket_of(user_id, self.salt) in self.exp_buckets:            return "experiment"        return "control"  def simulate_trial(user_id, layer):    """模拟一次曝光:实验组点击率 6%,对照组 4%"""    p = 0.06 if layer.group(user_id) == "experiment" else 0.04    return 1.0 if random.random() < p else 0.0  def run_experiment(layer, user_ids, days=7):    """每个用户每天曝光 3 次,返回两组的平均点击率序列"""    stats = {"control": [], "experiment": []}    for uid in user_ids:        group = layer.group(uid)        clicks = sum(simulate_trial(uid, layer) for _ in range(3 * days))        stats[group].append(clicks / (3 * days))    return stats  def paired_t_test(a, b):    """两独立样本 t 检验,返回 (t 统计量, 近似 p 值)"""    na, nb = len(a), len(b)    ma = sum(a) / na    mb = sum(b) / nb    pooled_var = (sum((x - ma) ** 2 for x in a) +                  sum((x - mb) ** 2 for x in b)) / (na + nb - 2)    t = (ma - mb) / math.sqrt(pooled_var * (1.0 / na + 1.0 / nb))    p = 2.0 * (1.0 - normal_cdf(abs(t)))    return t, p  def normal_cdf(x):    return 0.5 * (1.0 + math.erf(x / math.sqrt(2)))  if __name__ == "__main__":    layer = ExperimentLayer(        "排序模型_v2", 2024001, list(range(0, 20)))    users = list(range(1, 2001))    stats = run_experiment(layer, users, days=7)    t, p = paired_t_test(stats["control"], stats["experiment"])    ctr_ctl = sum(stats["control"]) / len(stats["control"]) * 100    ctr_exp = sum(stats["experiment"]) / len(stats["experiment"]) * 100    print("对照组 CTR: %.3f%%" % ctr_ctl)    print("实验组 CTR: %.3f%%" % ctr_exp)    print("t = %.3f, p = %.4f" % (t, p))    if p < 0.05:        print("结论: 新模型显著优于基线,可进入推全评审")    else:        print("结论: 差异不显著,继续积累样本或停止实验")
目的:演示一个最小可用的 AB 实验闭环——分层哈希分桶、模拟两组线上点击、t 检验判断显著性。
  1. def bucket_of(user_id, layer_salt, num_buckets=128)用“用户 ID + 层盐”构造 key,保证同一用户在不同层落到不同桶。
  2. int(digest[:8], 16) % num_buckets取 MD5 前 8 位转整数再取模,让用户均匀分布到 128 个桶。
  3. class ExperimentLayer用层盐和实验组桶集合封装一整个实验层,模拟平台中的“档口”。
  4. p = 0.06 if ... else 0.04模拟实验组 6% 点击率、对照组 4%,埋入真实差值的“真相”。
  5. clicks / (3 * days)把点击次数归一化成平均点击率,消除曝光次数差异带来的口径问题。
  6. pooled_var合并两组方差估计总体方差,对应正文中的方差齐性假设。
  7. 2.0 * (1.0 - normal_cdf(abs(t)))用正态近似算出双侧 p 值,是显著性检验的标准动作。
  8. p < 0.05判定差异是否显著,呼应正文中的决策门槛。

常见误区

误区新手部署完实验,看到实验组 CTR 高了 1% 就兴奋地发周报:“新模型显著提升!”实际上实验才跑了 6 个小时。

正解AB 实验的结论可靠性取决于样本量而非自然天数。样本量不足时,指标波动极大。就像试吃只来了 10 位顾客、碰巧 8 位说好吃,不能代表百万用户的口味。正确做法是先按样本量公式估算所需天数,跑满周期再下结论。

为何常见:在线看板的数字实时跳动,人脑天然倾向于把短期波动当成趋势,尤其当结果符合自己预期时。

误区p 值小于 0.05 就万事大吉,立即推全,不再关心其他指标。

正解统计显著只说明“这个提升不太像随机噪声”,不等于“收益足够大”,更不等于“没有副作用”。点击率显著提升 0.5%,可能换来首屏时延 p95 暴涨,或者次留暴跌。顾客确实多夹了一筷子,但结账时抱怨上菜太慢——护栏指标就是用来拦住这种“拆东墙补西墙”的实验。

为何常见:教材里教的是“p < 0.05 拒绝原假设”,初学者容易把统计结论直接等同于业务决策,忽略效应量和护栏指标。

误区以为按用户 ID 前几位切流量,推荐组、搜索组各用各的,天然就隔离了。

正解如果两个实验直接在用户层各自切一份流量,同一个用户可能同时被两个实验改版,两组指标都受到污染,结论无法归因。正确做法是分层正交:每个层用独立盐值重新哈希分桶,用户跨层随机性独立。就像同一顾客在 1 号档试新菜、2 号档喝老奶茶,互不影响。

为何常见:直觉上觉得“各用各的流量”就完成了隔离,没有意识到用户在多层之间是共享的,分桶必须按层重新洗牌。

误区总 CTR 从 4% 涨到 4.5%,直接写进周报:“模型大获成功”,不做人群拆分。

正解整体上涨而细分下降是完全可能的——辛普森悖论。比如新模型对老用户 CTR 提升 8%、对新用户下降 6%,如果新老用户基数不等,整体可能表现为上涨。看板必须支持按新老客、渠道、机型等下钻,同时盯漏斗各层转化,才能定位真实效应。

为何常见:平均数天然会掩盖结构差异,人又习惯用“一个数字”总结一切,看到总指标涨就容易跳过分组验证。

面试题

Q1. 分层正交实验要解决的核心问题是什么?

单选题 · easy

  • A.多实验并行时流量互不干扰← 正确答案
  • B.提升推荐模型训练速度
  • C.减少数据埋点的上报量
  • D.保证实验组人数多于对照组

答案:A。分层正交让每个实验层用独立盐值重新分桶,使多实验并行时每组流量互不污染,结论可以归因到单一改动。B 是训练层面问题,C 是埋点工程问题,D 违背实验设计的等量原则,均不是分层正交的目的。

Q2. AB 平台中用户分桶通常采用哪种方式?

单选题 · easy

  • A.按请求随机打标分桶
  • B.对用户ID做稳定哈希← 正确答案
  • C.按 IP 段切分用户
  • D.按访问时间切分

答案:B。按用户 ID 做稳定哈希,保证同一用户每次请求落入同一桶,避免用户在实验组和对照组间抖动。A 和 D 会导致同一用户反复切换,C 中 IP 段与用户身份不是稳定映射,都不满足分桶稳定性要求。

Q3. 想检测 1% 的 CTR 提升,样本量会如何变化?

单选题 · mid

  • A.提升越小所需样本越少
  • B.与可检出提升无关
  • C.提升越小所需样本越多← 正确答案
  • D.样本量只由基线决定

答案:C。样本量公式中 $\delta$ 在分母且带平方,想检测的提升越小,需要的样本越大。检测 1% 提升比检测 5% 提升要精细得多,需要更多顾客“试吃”才能把信号从噪声中捞出来。

Q4. p 值小于 0.05 通常表示什么?

单选题 · mid

  • A.实验效应必然真实存在
  • B.差异来自随机误差的概率较低← 正确答案
  • C.实验组指标一定优于对照
  • D.可以无视护栏指标上线

答案:B。p 值是在“两组真实无差异”假设下,观察到当前差异的极端概率。p<0.05 说明这个差异如果只是运气,出现的概率不足 5%。它不保证效应真实存在、也不代表效应量大,更不能抵消护栏指标。它只是说明“不像随机”。

Q5. AA 实验的主要用途是什么?

单选题 · easy

  • A.验证分流系统是否公平← 正确答案
  • B.加速实验组点击率上升
  • C.替代正式实验的显著性
  • D.用于模型效果对比测试

答案:A。AA 实验把同一桶用户随机切成两组跑同样的策略,理论上指标应一致。如果 AA 都出现显著差异,说明分桶不均匀或数据链路有偏,正式实验结论不可信。它像“假试吃”,验证评分体系本身没坏。

Q6. 多实验并行时,保障统计有效的方法有哪些?

多选题 · mid

  • A.使用独立正交分层← 正确答案
  • B.各自占用独立流量池← 正确答案
  • C.实验组间共享用户分桶
  • D.每层用稳定哈希分桶← 正确答案

答案:ABD。独立正交分层让各层重新随机,独立流量池则彻底隔离域,稳定哈希保证用户不抖动,三者都是统计有效的手段。C 让多个实验共享同一套分桶,会让用户同时受多个实验影响,破坏因果归因。

Q7. 指标看板设计中,哪些做法是正确的?

多选题 · hard

  • A.核心指标配护栏指标← 正确答案
  • B.区分实时与离线口径← 正确答案
  • C.只看整体点击率即可
  • D.关注人群细分与漏斗← 正确答案

答案:ABD。指标要分层看:核心指标定目标、护栏指标防受伤;实时流与离线数仓双口径对账;人群细分能发现辛普森悖论、漏斗能定位问题环节。C 只看整体单击率会掩盖结构问题,是典型错误。

Q8. 辛普森悖论在 AB 实验中的典型表现是什么?

单选题 · hard

  • A.整体看显著提升,分组后反而下降← 正确答案
  • B.样本量越大显著性必然越强
  • C.实验组方差总是小于对照组
  • D.分层实验无法发现真实差异

答案:A。当实验组和对照组的人群结构比例不同时,整体均值会被结构效应主导,出现“整体涨、分组跌”的悖论。解法是实验前保证人群分布一致,实验后按人群维度下钻验证。B、C、D 都不符合悖论定义。

Q9. 面对多重比较问题,正确的应对方式有哪些?

多选题 · mid

  • A.减少同时检验的指标数量← 正确答案
  • B.使用 FDR 等校正手段← 正确答案
  • C.只看一次显著结果
  • D.设置护栏指标辅助判断← 正确答案

答案:ABD。同时检验 20 个指标,每人卡 5% 假阳性线,整体误报率会大幅上升。减少指标数、用 FDR/Bonferroni 校正、靠护栏指标交叉验证,都能降低误判。C 只看一次的显著结果,正是多重比较的经典坑。

Q10. 方差齐性假设下,两独立样本 t 检验的自由度是多少?

单选题 · extreme

  • A.两样本量之和减 2← 正确答案
  • B.两样本量之和减 1
  • C.两样本量之和
  • D.较小样本量减 1

答案:A。方差齐性时自由度 = $n_e + n_c - 2$,因为两组均值各消耗一个自由度。B 少减一个,C 完全未减,D 是 Welch 不等方差检验的近似自由度思路,用于此处不正确。