Skip to Content
产品功能A/B 实验

A/B 实验(Experiments)

A/B 实验让”红色按钮还是蓝色按钮转化更高”这类问题用数据回答:在 Console 定义实验与变体权重, SDK 侧用一致性 hash 把用户稳定分流到变体,上报曝光(Exposure)转化(Conversion), Argus 实时聚合各变体的去重转化率并给出统计显著性——运行中默认以序贯 always-valid 检验为主结论, 从机制上防止”边跑边看、看到 p 小于 0.05 就停”的偷看(peeking)谬误。

实验没有独立后端服务:定义与分流在 config 服务(与 Feature Flag 共享分桶引擎)、结果统计在 observability-core、采集在 ingestion(POST /v1/experiment)。能力地图见 docs/07-design/service-experiment.md; 统计口径真相源是 docs/02-product/03-baseline-metrics-dictionary.md Part B。

核心概念

实验、变体与状态

  • 实验(Experiment):一个 key(如 btn_color)+ 若干变体(Variant)
  • 变体权重(weight):非负整数,按权重比例分配流量(如 control=50 / treatment=50); 权重 0 = 不参与分配
  • 状态机draft(草稿)→ running(运行中)→ stopped(已停止),可从 stopped 重置回 draft。只有 running 状态参与分流——停止实验后所有用户自动回落对照 / 默认体验。

一致性 hash 分流

分桶是确定性纯函数services/config/internal/assign/assign.go):

bucket = FNV-1a_32( experiment_key + ":" + user_id ) mod 总权重 按变体 position 升序累加权重区间,bucket 落入哪个区间即命中该变体
  • 稳定命中:同一 (user_id, experiment_key) 任何时间、任何端算出同一变体——用户不会 “这次红下次蓝”。
  • 实验间独立experiment_key 拌入 hash 输入,同一用户在不同实验中的分组互不相关, 避免”所有实验都砸中同一批小白鼠”。
  • 安全降级:实验非 running、无变体、正权重和为 0、或 user_id 为空时不分配 (调用方按对照 / 默认兜底),绝不随机命中。

曝光与转化

  • 曝光(exposure):用户被实际分到并”见到”某变体。分析的分母是去重曝光用户数 unique_exposed
  • 转化(conversion):用户达成目标(可带 metric 名与数值 value)。分子是 去重转化用户数 unique_converted;转化率 = unique_converted / unique_exposed按用户去重——同一用户转化 3 次只算 1。
  • 只有产生过曝光的用户才计入实验;iOS / Android SDK 的转化上报会归因到本会话已曝光的变体, 未曝光先转化的调用会被丢弃。“转化时间必须晚于首次曝光”的服务端强校验为规划中。

显著性:序贯为主、固定样本揭盲为辅

结果面板对每个非对照变体给出两族判定(对照 baseline 默认取 key 排序的首个变体):

判定是什么什么时候可信
序贯 always-valid(mSPRT)always_valid_p_value / sequential_significant运行中随时看都有效——任意时刻查看都控制假阳性率,是运行中实验的主结论
固定样本 z 检验两比例 z 检验(合并标准误)+ 多变体 Holm-Bonferroni 校正后的 p_value_adjusted / significant_95只在达到预定样本量后单次揭盲才有效;运行中反复读它并据此早停会把假阳性率从 5% 抬到 20% 以上

小样本保护:期望成功 / 失败数不足(np < 5 经验法则)时标记 low_sample,此时正态近似不可靠, 不要判赢家——“不显著”也不等于”无差异”。

防偷看(peeking):不要用固定样本 p 值做”看起来快显著了,再等两天”式的决策——那正是 假阳性膨胀的来源。运行中一律读序贯判定;固定样本判定留到达到计划样本量后一次性揭盲。

接入

平台矩阵

平台取变体自动曝光手动曝光 / 转化上报快速开始
iOSArgus.getVariant(key)(需 enableAutoExperiments + userId✅(getVariant 即曝光,会话内去重)trackExposure / trackConversion/quickstart/ios/
AndroidArgus.getVariant(key)(同上)trackExposure / trackConversion/quickstart/android/
WebArgus.config.getVariant(key, def)(需 remoteConfig: true—(规划中)—(规划中,可直调 REST)/quickstart/web/
FlutterArgus.configGetVariant(key, def)(同上)/quickstart/flutter/
React NativeArgus.config.getVariant(key, def)(同上)/quickstart/react-native/

分流要求事件带 user_id(init 传 userId 或调用 identify),否则不参与实验。

最小接入片段

var config = ArgusConfig(/* dsn ... */) config.enableAutoExperiments = true // init 后台拉取实验分配;需设置 userId // 取变体并自动上报曝光(会话内去重);nil = 未分配,按对照兜底 if Argus.getVariant("btn_color") == "treatment" { showRedButton() } // 用户达成目标时上报转化(归因到本会话已曝光的变体) Argus.trackConversion("btn_color", metric: "purchase", value: 29.9) // 也可完全手动:自有分配逻辑时只做上报 Argus.trackExposure("btn_color", variant: "treatment")

Console 使用

进入 Console 左侧导航 Experiments 页(先在左上角选择项目):

  1. 新建实验:填实验 key(如 btn_color)与描述;key 重复返回 409。
  2. 管理变体:展开实验,添加变体(key 如 control / treatment、非负整数权重、排序); 启动前至少添加 2 个变体;权重 0 的变体不参与分配。
  3. 状态操作:草稿 → 启动(进入 running,开始分流)→ 停止(全部回落对照)→ 可重置草稿后调整再启动。
  4. 结果面板(展开实验可见,近 14 天,可刷新):每个变体一行——
    • 曝光用户(及曝光次数)、转化用户(及转化次数)、转化率(按用户去重)、转化值
    • 提升 / 显著性:相对对照的 lift 百分比 + 判定徽章——✓ 显著·序贯(可安全下结论)、 运行中未显著⚠ 样本不足(勿判赢家);固定样本 p 值放在悬浮提示(tooltip)中并附 偷看警示。

样本量 / MDE(最小可检测效应)设计器、SRM(样本比例失衡)自动校验、护栏指标自动止损、 贝叶斯统计为规划中能力;当前请在实验设计时自行预估样本量,并对流量分配异常保持警惕。

SDK API 速查

能力iOSAndroidWeb / RNFlutter
取变体(自动曝光)Argus.getVariant(key)Argus.getVariant(key)
取变体(仅取值)Argus.configGetVariant(key, def)Argus.configGetVariant(key, def)Argus.config.getVariant(key, def)Argus.configGetVariant(key, def)
上报曝光Argus.trackExposure(key, variant:)Argus.trackExposure(key, variant)
上报转化Argus.trackConversion(key, metric:value:)Argus.trackConversion(key, metric, value)

MCP 工具

接入 Argus MCP Server 后,AI 能按正确统计口径解读实验 (源码:experiment_list.ts / experiment_results.ts):

工具用途关键参数
experiment.list列出项目的实验:key、状态(draft / running / stopped)、描述、变体 keyproject_id
experiment.results各变体曝光 / 转化 / 去重转化率 + 双轨显著性(固定样本 z 检验与序贯 mSPRT),变体按转化率降序project_idexperiment_keydays(1–90,默认 14)、baseline(指定对照,缺省取 key 排序首个变体)

工具描述内置了防 peeking 指引:对运行中实验,AI 会以 sequential_significant 为结论依据, 不会用固定样本 p 值诱导”再观察几天”。

配额与计费

  • 1 条曝光或转化事件 = 1 个计费事件(event),计入项目事件量配额。
  • 详见 套餐、配额与计费

FAQ

为什么运行中的实验一直显示”运行中未显著”? 序贯检验为了保证”随时看都有效”,判定天然比固定样本保守——这是特性不是缺陷。样本继续积累后 若真有差异会转为 ✓ 显著·序贯;也可等达到计划样本量后读固定样本判定(单次揭盲)。

同一个用户会不会一会儿 A 组一会儿 B 组? 不会。分桶是 hash(experiment_key + user_id) 的确定性函数,跨端、跨时间稳定。但前提是 user_id 稳定——匿名用户(无 user_id)不参与分配。

对照组是哪个变体? 结果统计默认取变体 key 排序的首个为 baseline(建议把对照命名为 control,天然排前); MCP experiment.results 可用 baseline 参数显式指定。

改变体权重会打乱已有分组吗? 权重决定 hash 桶区间的切分,调整权重会导致部分用户的命中区间移动。建议实验运行中不要调权重; 要扩量请在设计时就用目标比例,或停止实验后另起新实验 key。

两个变体的曝光量差得离谱(如 9000 vs 11000)怎么办? 这大概率是分流 / 采集 / 上报 bug(SRM,样本比例失衡),此时整个实验数据不可信,不要下结论。 自动 SRM 校验为规划中,当前请人工核对各端曝光上报是否对称。