1. AB 测试流程
一个完整的 A/B test 主要包括如下几部分:
- 分析现状,建立假设:分析业务,确定最高优先级的改进点,作出假设,提出优化建议。
- 设定指标:设置主要指标来衡量版本的优劣;设置辅助指标来评估其他影响。
- 设计与开发:设计优化版本的原型并完成开发。
- 确定测试时长:确定测试进行的时长。
- 确定分流方案:确定每个测试版本的分流比例及其他分流细节。
- 采集并分析数据:收集实验数据,进行有效性和效果判断。
- 给出结论:① 确定发布新版本;② 调整分流比例继续测试;③ 优化迭代方案重新开发,回到步骤 1。
2. AB Test 的相关组成部分
本方案将 AB 测试分为三个部分:
-
接入方
需要实现实验功能的细节部分。可以是客户端,也可以是服务端,AB 测试平台会提供客户端和服务端两种接入方式。
-
⭐️ AB 测试平台
- 分流:流量过滤、实验分流
- 实验数据管理:实验决策、实验配置
- 接入支持:提供 open api 或 SDK
- 其他功能:用户命中分析…
-
数据采集和分析
不管是客户端还是服务端,将实验命中信息以及用户反馈信息应该上报到埋点平台,而不是 AB Test 平台,最终实验结果最终应该从日志平台中进行统计,在实验结束之后进行知识总结和提炼。
本文主要给出关于第二部分 AB 测试平台的几个组成部分相关方案,不包含采集数据的方案以及最终分析数据知识提取的指导。
3. 接入方案
✅ 方案 1:
将分流模型放在平台进行实现 优点是接入方只需要调用接口获取实验配置即可;缺点是平台需要承受比较大的压力,对平台的稳定性和分流效率要求较高。
方案 2:
将分流模型放在接入 SDK 进行实现 优点很明显,平台承受的压力会比较小;缺点是分流模型在 SDK 内实现的话,接入方的接入成本会比较高,实验时平台仅仅下发实验的元数据,并且要求所有的实验使用同一套分流模型,进行统一的迭代。
我个人更偏好第一个接入方案,接入方保持轻量化设计,分流交由平台全面接管,保持一定的灵活性和可配置性。
3.1 服务端接入
很简单,使用平台提供的接入 SDK 或者调用接口获取实验配置
3.2 客户端接入
- 在页面加载时,调用 AB Test 平台提供的 open api 获取实验信息,将数据写入到一个全局对象内,例如 window 对象内,并写入本地存储。
- 通过读取 window 下的实验信息动态加载资源,最好都写为 loadable 的形式,避免一开始就将其他实验组的资源一起加载下来。
- 下次进入页面时默认读取本地存储内的数据。
- 设置一个过期时间,在数据过期之后重新获取实验数据。
4. 分流方案
4.1 流量过滤
4.1.1 实验的分流配置:实验配置时可以根据一些元数据进行分流配置
大多数实验是根据用户的 id 作为实验数据的分配单位,在一些特定的场景下需要在实验配置里面支持分流条件,例如指定用户性别,注册日期,地区等用户画像。也就是指定用户的过滤条件,一般包含有以下的算子:
- “=” 算子:等于比较符
- “!=” 算子:不等于比较符
- “>” 算子:大于比较符
- “<” 算子:小于比较符
- “in” 算子:包含比较符
- “not in” 算子:不包含比较符
最终这些过滤条件组合成一个 Map ,并且在分流时进行逐一判断,不满足则再走到兜底条件。
不过也存在需要根据设备 id 作为实验单位,但是我们目前大多数系统是不支持存储设备 id 的,所以先不考虑这个情况了。
4.1.2 流量分配:实验分流的均匀性和随机性
一般随机分配会使用哈希的方式进行处理之后再采用特定的方式决策出用户应该被分到哪个实验组。这样做的好处是可以根据用户 id 之类的反推用户命中了哪个实验组。
以下是一个经过验证的较为可靠的随机分配算法:
- 现在有一个 user,他有一个 user_id,这个 user_id 的值是一个数字;
- 每 run 一个实验,我们都有一个特定的 salt,把这个 user_id 和这个 salt 拼接起来成一个长字符串;
- 把 2 中得到的长字符串扔进一个哈希函数(可以是 MD5 或者 SHA1 ),这里用 MD5,然后生成一条哈希数据(Hashed data);
- 取 3 中得到的哈希数据的头六位字符,转换成一个十六进制整数;
- 拿 4 中得到的整数去除以最大的六位十六进制数字(0xffffff),注意用浮点数相除,会得到一个介于 0 和 1 之间的浮点数。
- 根据第 5 步得到的浮点数是否大于预设阈值,决定这个用户的分组。举个例子,如果我们想得到 50-50 的平均分配,那么我们会预先设定一个阈值 0.5,如果第 5 步得到的是 0.4,那么这个用户被分到控制组,因为它小于 0.5,如果第 5 步得到的是 0.6,这个用户被分配到试验组。
salt 值跟实验是一一对应的关系,所以在不同的实验之间,用户最终被分配到哪个实验组是互不相干的。
当然,都是假的 Random ,但算法在 95% 置信区间内,是符合大部分需求的。
4.1.3 实验分流的过程
在一些情况下,我们会同时设置流量过滤规则配置以及进行流量分配,甚至在某些场景下还需要配置实验组白名单
以上的三种因素会影响实验分流,实验分流的过程和主要步骤如下:
- 判断实验是否配置了白名单,若有配置则判断用户是否在白名单内,否则进入第二步。若配置了白名单并且匹配上,则进入第三步,否则返回没有命中该实验
- 根据用户设定流量占比,首先判断用户是不是落在流量区间内。若在则进入第三步,否则返回没有命中该实验
- 根据流量过滤规则判断用户是否被过滤,若被过滤,则返回没有命中该实验,否则返回相应分组信息
4.1.4 设立实验层:多个实验并行时
在多个实验同时进行时,需要考虑多个实验之间可能存在的相互影响。如果两个实验存在表现上的冲突,或者用户参与了实验 A 后会接着参加实验 B 会对实验 B 造成结果上的影响,这种情况要求两个实验的用户必须出于互斥关系。也就是实验 A 和实验 B 必须处于同一实验层,一个用户只能参与一个实验层中的一个实验。
关于实验层的方案,采用上文中实验分流的随机分配算法方案。一个实验层分配一个 salt 值,使用用户 id 与 salt 值进行拼接之后作为入参传入哈希算法内,得出一个 0 - 1 的数字,由这个数字作为用户命中实验层中哪个实验层以及实验层中的哪个实验的依据。
5. 实验配置
这部分可以很简单也可以很复杂
在平台上创建一个实验,需要提供以下功能的配置:
- 实验的元数据:appid、名称、key、描述、权限等
- 实验分组信息:实验组和对照组的 key、分流策略、下发参数、用户白名单
- 所属实验层、流量分配
- 状态:调试阶段、上线阶段
6. AB 测试的注意点
- 样本数量:流量样本的数量不能过少 很显然,样本数量过少会加大某些极端数据的权重,导致实验不准确。若 App 的 uv 或者 pv 本来就不多的情况下,就需要加长实验时长,带来额外的时间成本。 同时,很多经验告诉我们,实验使用的流量应该根据情况决定大小。过大的流量会导致相当一部分用户处在糟糕的使用体验上,特别是一些重大的改版。一般情况下会先小流量进行实验,之后根据情况逐步加大实验流量。
- 样本质量:分流的样本是否有效 一个常用的验证方法是:AA 测试
需要考虑的点
- 平台获取用户数据的方式 在初级阶段我们只需要支持通过接入方调用获取 userid 从而计算出实验结果。当复杂实验来临时,需要考虑配置特定用户人群时,如何获取用户的详细信息呢