A/B 测试平台
问题
如何设计一个企业级 A/B 测试平台?核心模块有哪些?
答案
平台架构
分流引擎设计
分流算法
import hashlib
def assign_experiment(
user_id: str,
experiment_id: str,
layer_id: str,
traffic_ratio: float = 0.1, # 实验占总流量 10%
group_ratio: list = None # 组间分配 [50, 50]
) -> dict:
"""多层分流引擎"""
if group_ratio is None:
group_ratio = [50, 50]
# Step 1: 判断是否命中实验(流量控制)
traffic_key = f"{layer_id}_{user_id}"
traffic_hash = int(hashlib.md5(traffic_key.encode()).hexdigest(), 16) % 10000
if traffic_hash >= traffic_ratio * 10000:
return {"in_experiment": False, "group": None}
# Step 2: 分配实验组(组间分流)
group_key = f"{experiment_id}_{user_id}"
group_hash = int(hashlib.md5(group_key.encode()).hexdigest(), 16) % 100
cumulative = 0
for i, ratio in enumerate(group_ratio):
cumulative += ratio
if group_hash < cumulative:
group = "control" if i == 0 else f"treatment_{i}"
return {"in_experiment": True, "group": group}
return {"in_experiment": True, "group": "control"}
分层与互斥
| 策略 | 说明 | 适用场景 |
|---|---|---|
| 分层 | 不同实验在不同层,互不干扰 | 多个实验同时跑 |
| 互斥 | 同一层内的实验流量互斥 | 同一功能的不同方案 |
| 正交 | 不同层的实验相互独立 | 不同功能的实验 |
Layer 1 和 Layer 2 正交——一个用户可以同时参与首页实验和结账实验。
指标计算管线
核心数据表
| 表 | 字段 | 说明 |
|---|---|---|
| 曝光表 | user_id, experiment_id, group, timestamp | 用户分组记录 |
| 事件表 | user_id, event, properties, timestamp | 用户行为记录 |
| 指标表 | experiment_id, group, metric, value, ci | 计算结果 |
指标计算 SQL 示例
-- 计算各组转化率
WITH exposure AS (
SELECT user_id, group_name
FROM experiment_exposure
WHERE experiment_id = 'exp_001'
),
conversion AS (
SELECT DISTINCT user_id
FROM events
WHERE event = 'purchase'
AND timestamp BETWEEN '2024-01-01' AND '2024-01-14'
)
SELECT
e.group_name,
COUNT(DISTINCT e.user_id) AS total_users,
COUNT(DISTINCT c.user_id) AS converted_users,
ROUND(COUNT(DISTINCT c.user_id) * 1.0 / COUNT(DISTINCT e.user_id), 4) AS conversion_rate
FROM exposure e
LEFT JOIN conversion c ON e.user_id = c.user_id
GROUP BY e.group_name;
自动化分析报告
一份完整的实验报告应包含:
| 模块 | 内容 |
|---|---|
| 实验概况 | 名称、假设、周期、流量比例 |
| SRM 检查 | 分流比例检验 |
| 主指标结果 | 均值/转化率、差异、p 值、置信区间、效应量 |
| 次要指标 | 多指标结果(含多重比较校正) |
| 护栏指标 | 是否有负面影响 |
| 分层分析 | 按平台、地区、用户群等拆分 |
| 时间趋势 | 效应随天数的变化 |
| 建议 | 上线 / 继续观察 / 放弃 |
业界实践
| 公司 | 平台名称 | 特点 |
|---|---|---|
| Overlapping Experiments | 多层正交分流 | |
| Microsoft | ExP | CUPED、SRM自动检测 |
| Netflix | XP | 准实验、因果推断 |
| 字节跳动 | 火山引擎 A/B | 可视化编辑、Bandits |
| 阿里 | 闲鱼实验平台 | Bayesian AB、自动停止 |
开源方案
| 工具 | 语言 | 特点 |
|---|---|---|
| GrowthBook | TypeScript | 功能全面、Feature Flag |
| Unleash | TypeScript | 轻量、Feature Toggle |
| Wasabi | Java | Netflix 开源 |
| causalml | Python | 因果推断库 |
常见面试问题
Q1: 如何保证分流的一致性和正交性?
答案:
- 一致性:使用
hash(experiment_id + user_id)确保同一用户总是分到同一组 - 正交性:不同层使用不同的
layer_id作为 hash 种子 - 关键:分流逻辑必须无状态,不依赖数据库查询
Q2: 如果需要同时跑 100 个实验怎么办?
答案:
- 分层:将功能域划分为多个互不干扰的层
- 互斥:同一层内实验互斥,争抢流量
- 流量管理:设置每层最大并行实验数
- 自动下线:到达样本量自动触发分析和下线
- 优先级:高优先级实验优先获得流量
Q3: 指标计算延迟怎么处理?
答案:
- T+1 离线计算:Hive/Spark 批量计算,次日可见(最常见)
- 实时/准实时:Flink 流式计算,分钟级延迟(成本高)
- 混合方案:核心指标实时、次要指标 T+1
- 注意:不要因为看到实时数据就频繁做决策(Peeking 问题仍然存在)