AB 分析模块:自定义分析、下钻与高级分析
实验分析模块不是一张固定报表,而是一套受控的语义层:把人群、指标、维度、窗口和统计方法变成可组合、可复现、可审计的对象。本文横向拆解公开竞品的分析工作台,并给出一套类似 Libra AB Insight 的产品与架构设计。
SRM p=0.42
指标 18 · 人群 4
结论与证据
固定样本 · 频率派 · 双侧 α=0.0595% CI +1.10% ~ +3.72%
指标组:首页体验
点击任意指标查看口径与证据| 指标 | B / A | 相对变化 | 95% CI | p | 判定 |
|---|---|---|---|---|---|
| 7 日人均有效停留核心指标 · sum/uv | 13.15 / 12.84 | +2.41% | +1.10 ~ +3.72 | 0.002 | 显著 |
| 次日留存uv/au · 自然日 | 41.8% / 41.2% | +1.46% | -0.20 ~ +3.10 | 0.084 | 不显著 |
| 人均点击pv/uv | 8.71 / 8.42 | +3.44% | +0.80 ~ +6.10 | 0.011 | 显著 |
| 内容举报率护栏 · uv/au | 0.41% / 0.42% | -2.38% | -8.10 ~ +3.90 | 0.440 | 不显著 |
| 首屏加载 P95护栏 · 分位数 | 1.44s / 1.42s | +1.41% | -1.20 ~ +4.00 | 0.120 | 不显著 |
| 人均有效阅读时长自定义 · sum/uv | 6.45 / 6.10 | +5.74% | +1.90 ~ +9.60 | 0.020 | 显著 |
人群:新一线新用户
规则圈选 · 日更 · 版本 v3下钻:从结论到可行动切片
每一层都保留实验对照与样本量查看用户不改变聚合口径
{
"experiment": "EXP-2481",
"metric": "stay_7d_per_uv",
"group_by": ["channel"],
"filters": {"audience": "new-tier1-newuser-v3"},
"compare": "B_vs_A",
"stats": {"ci": 0.95, "method": "delta"}
}
高级分析:把假设变成可检查的选项
默认严谨,逐项解释代价用实验前 14 天同指标做协变量,降低个体差异。当前方差缩减 28%,结论方向不变。
允许中途查看而不膨胀一类错误。当前 D6,alpha 已消耗 0.031;若现在停止,应报告 always-valid CI。
用因果森林估计 CATE,回答「对谁更有效」。子群结论必须过 FDR,且不能直接外推到全量。
5 个指标 × 4 个人群 = 20 次检验。BH-FDR q=0.05 后仍有 3 个显著;未校正的 7 个标为「探索」。
产品 / 设计:0 → 3 → 4 → 7,先看十个判断,再看自定义分析与人群,最后看页面解剖。数据 / 统计:4 → 5 → 6,重点看因果边界、下钻护栏与方法选择。架构 / 工程:2 → 8,重点看对象模型、查询契约与存储选型。只想汇报:0 与 10.4,两页就够。
0. 先看结论:十个设计判断#
分析模块卖的是口径,不是图表
图表可以被复制,口径不能。指标的分母、去重键、归因窗口、排除规则一旦漂移,所有漂亮的置信区间都失去意义。
结论先行,但证据必须同屏
首屏给结论,同时给样本量、置信区间、方法与数据截止时间。只给「+2.4%」而不给区间的产品,会把统计问题变成文案问题。
自定义的边界是语义层
让用户组合指标、人群、维度、窗口与方法,而不是把 SQL 输入框丢给业务。自由 SQL 可以存在,但必须走沙箱、血缘与成本配额。
人群分「进组前」与「进组后」
进组前是分配问题,进组后是分析问题。前者改变随机化与外部有效性,后者容易引入 post-treatment bias。UI 必须在用户选错之前解释代价。
下钻是受控探索,不是无限 group by
每下一层都要保留对照、样本量、置信区间与多重比较状态。没有这些,下钻只是把噪声切得更细。
高级方法默认严谨
CUPED、序贯、FDR 应该默认开启并解释;Uplift、CATE 应该默认标注「探索性」。把论文菜单直接暴露给业务,是平台最昂贵的偷懒。
指标要有 owner、版本与血缘
指标不是字段的别名。一个可用的指标定义至少包含:事件、聚合、分母、过滤、时间窗、归因、去重键、负责人、上线状态。
性能就是产品能力
下钻超过 2 秒,用户就会退回 Excel;人群预览超过 10 秒,运营就不会用。查询延迟直接决定分析深度。
信任来自可见的失败
SRM 异常、护栏恶化、样本不足、数据延迟、口径变更,都要在结论旁边显式出现。隐藏失败比失败本身更伤信任。
分析要沉淀为决策资产
保存视图、评论、决策记录、复盘模板,让一次分析可被复用、被挑战、被审计。否则平台只是「一次性报表工厂」。
Libra 是字节跳动的内部实验平台,DataTester 是其对外商业化版本。两者同源,但不能把 DataTester 的公开文档当成 Libra 内部版的全部。本文把材料分成三类:官方 官方文档/论文/演讲;推断 由公开材料反推;建议 我们的产品设计判断。内部版的 CUPED/ITR、LLM 分析、图聚类等能力,公开材料只能证明「存在实践」,不能证明「对外产品已具备」。
1. 拆解:Libra 的 AB Insight 做对了什么#
先澄清一个命名问题:用户口中的「AB Insight」在公开材料里找不到对应的正式产品名。可查证的是 Libra(字节内部平台)与 DataTester(对外商业化版本)的 Experiment Report 与 Advanced Analysis。本文用「AB Insight」指代这套分析工作台,不指某一个具体菜单。字节在 2012 年引入 A/B 体系,2016 年产品化,2021 年通过火山引擎对外开放;官方在 AICon 2025 的口径是累计 340 万+ 次实验、同时运行 7 万+ 来源。这套规模决定了它的分析模块不可能是一张固定报表:它必须把「看结论」拆成一组可复用的分析面,并让不同角色在同一套口径上协作。
从公开的 DataTester 文档可以还原出六个稳定的分析面。它们不是六个菜单,而是六种决策问题:
| 分析面 | 用户真正的问题 | 公开实现要点 | 值得抄的部分 |
|---|---|---|---|
| 实验总览 | 这版能不能上? | 核心指标、必看指标、置信区间、MDE、日级趋势、概率分布、箱线图;支持时间/维度筛选 | 结论与证据同屏;MDE 用来解释「不显著」 |
| 指标分析 | 哪个指标动了?动了多少? | 指标组/指标视图;事件、留存、漏斗三类;相对/绝对差异、p 值、CI;指标级下钻 | 指标组按业务问题组织,不按数据表组织 |
| 人群分析 | 对谁有效?谁被伤害? | 用户分群(规则/文件)、自定义筛选模板、差异分析与分组对比、客群实验 | 人群是分析的一等对象,不是临时 filter |
| 下钻 | 为什么动?动在哪? | 维度拆分、时间趋势、用户明细、TopN;即席 OLAP | 每层保留对照与样本量;用户级下钻脱敏 |
| 高级分析 | 效应可信吗?对谁最大? | 差异分析、Cohort、Uplift/敏感人群、ANOVA、Monte Carlo | 方法以「问题」命名,不以「算法」命名 |
| 诊断 | 数据是不是错了? | SRM/分流诊断、数据延迟、指标口径、告警 | 把失败状态做成产品的一等公民 |
报告页的阅读顺序也值得抄:左侧指标导航按「关注指标组」组织,默认展开核心指标所在组;表格先给相对差异、置信区间、指标值,显著性用底色标出;只有切到单指标视图,才展开进组人数、日级趋势、概率分布与箱线图 来源。这个「组 → 单指标 → 证据图」的阶梯,把 PM、DA、运营三类读者分开了:PM 看第一屏拍板,DA 看第二屏复核,运营看筛选后的切片执行。
两个容易被忽略的细节,恰恰是设计精髓。其一,日级趋势是「截至当日已进组全部用户」的累计口径逐日切片,所以区间随时间收窄是设计使然,不是「越跑越显著」的证据;想看新进组人群的质量变化,必须用 cohort 分析。其二,概率分布是模型视角,箱线图是原始数据视角,同屏并列是为了交叉验证:如果正态曲线说「差不多」而箱线图的长尾明显不同,真正该信的是后者。代价是口径变多:日级不含今天、留存按首次进组归因、漏斗把实验曝光当作第一步之前的过滤事件 来源——每一条都能让两个人在同一张图上吵起来。DataTester 的兜底方式是把限制写进 UI:不能画就不给入口(例如属性分组后禁用分布图、CVR 不提供箱线图)来源。这比写在文档里有效,但也削掉了探索空间。
1.1 客群实验:把「人群 × 策略」做成双因素设计#
DataTester 的「客群实验」是一个很值得研究的设计:它不是「先开实验,再按人群切一刀」,而是在实验配置阶段就声明两个客群(如 test / test 1),报告页同时给出三个层次的结论 来源:
- 每个实验版本下,各客群的获胜概率;
- 每个客群下,各实验版本的获胜概率;
- 双因素方差分析(ANOVA)表:客群(行因子)× 策略(列因子),输出交互效应、主效应、简单主效应,以及 SS、df、MS、F、p、F critical。
获胜概率用 Monte Carlo 近似:对每个组拟合正态分布,重复抽样 10 万次,统计「谁最大」的频率 来源。这套设计的产品价值在于:它把「策略对不同人群是否不同」从分析师的临时探索,变成了实验发起时就可以声明的研究问题。
但它也有明确的代价:
- 样本量按客群 × 版本切分,交互效应的功效远低于主效应;小客群很容易「看起来有差异」。
- ANOVA 假设方差齐性与近似正态,对重尾、比率型指标并不稳健;产品需要提示或提供 bootstrap。
- 获胜概率不是 p 值,不能按频率派显著性解释;多客群、多版本比较仍需多重比较校正。
- 客群必须在进组前定义,否则就是 post-treatment 分层,不能做因果解释。
建议 如果我们要做类似能力,不要把「客群实验」做成一个独立的实验类型,而应把它做成分析配置:实验仍然只有一套随机化,客群作为「预注册的分析维度」挂在实验上;报告默认展示交互效应的功效与 FDR 校正结果。
1.2 敏感人群洞察:Uplift 的产品化样本#
DataTester 的「敏感人群洞察」是公开文档里少见地把 Uplift 做成完整工作流的产品 来源:
- 任务粒度是「一个指标、一个实验组、一个对照组」;
- 挖掘方向分正向/负向(找提升最大的人,或找下降最小的人);
- 用户属性作为特征,模型输出 ITE(Individual Treatment Effect),按 ITE 分 10 个 bins;
- 报告给出 TOP 敏感人群、特征重要性、TOP 3 特征的二维交叉子群,以及子群的人数占比、绝对/相对差异、相对差异贡献、p 值;
- 支持下载人群明细(treatment、uid、ite、bins、业务 ID),用于后续定向运营。
这套产品的聪明之处,是把「因果模型」翻译成了运营能用的三个东西:一群人、一个方向、一个可执行的名单。但它也暴露了 Uplift 的典型风险:
- 推荐入组人数 > 2 万、维度 > 4 个,否则模型不稳定 来源;
- 子群是「TOP 特征交叉」选出来的,存在选择偏倚;报告里的 p 值没有做多重比较校正;
- ITE 是模型预测,不是个体真实因果效应;下载名单用于全量投放前,应该做 holdout 验证;
- 「负向挖掘」找到的人群,可能只是回归到均值,不等于策略真的伤害了他们。
建议 产品上必须同时给「模型置信度 / 子群样本量 / 是否经过 FDR / 是否有 holdout 验证」四个状态;否则 Uplift 会变成「用机器学习包装的细分」。更稳妥的做法是把 Uplift 放在「探索」层,把验证放在一个新的 confirmatory 实验里。
1.3 用户分群:先 hash 再过滤,这个顺序很关键#
DataTester 的用户分群支持两种创建方式:规则圈选与文件上传;规则支持「做过 / 没做过 / 依次做过 / 用户是 / 用户不是」,支持 AND/OR 与嵌套,支持日更或手动更新;分群可以作为实验的受众规则,也可以作为 Feature 的定向人群 来源。
更重要的一句话藏在文档里:分流时,非白名单用户先做 hash 分桶,再做人群过滤 来源。这意味着:
- 人群规则影响的是「谁有资格进入分析」,而不是「谁被分到哪个组」;
- 只要人群定义与实验分配独立,按人群切子群不会破坏随机性;
- 但如果人群定义使用了实验期行为(例如「点击过新卡片的人」),它就成了 post-treatment 变量,按它切子群会产生 collider/selection bias。
推断 这个顺序是字节系产品在因果设计上最值得学的一处:它把「定向」和「分析」解耦,让同一个分群既能用于投放,也能用于分析,但不会悄悄改变随机化。很多自建平台把人群过滤放在分桶之前,结果实验组和对照组的入组概率随人群变化,SRM 和结论一起失效。
1.4 公开材料能看到什么、看不到什么#
| 能力 | 公开证据 | 判断 |
|---|---|---|
| 报告总览、指标组、趋势、分布、箱线图 | DataTester 官方文档 | 官方 对外版具备 |
| 自定义筛选模板(实验级 10 个、应用级 50 个) | 官方文档 | 官方 可复用、可共享 |
| 差异分析 / 分组对比 / 客群实验 / ANOVA | 官方文档 | 官方 已产品化 |
| Uplift / 敏感人群 / 人群下载 | 官方文档 | 官方 已产品化,但统计校正有限 |
| Cohort / 漏斗 / 热图 | 官方文档 | 官方 分析面完整 |
| CUPED / ITR | 2024 内部演讲、论文 | 推断 内部实践强,对外文档未提 |
| LLM 实验分析 / 归因 | 2024 AICon 演讲 | 推断 有内部落地,产品化程度未知 |
| 图聚类 / DQ 估计量 | 论文、演讲 | 推断 服务特定场景,不是通用分析模块 |
这张表最重要的不是「谁有谁没有」,而是提醒我们:对外文档的完整度不等于内部能力的完整度,反之亦然。做竞品分析时,必须把「产品能力」「工程能力」「统计能力」分开评估;否则很容易把一次演讲里的方法,当成采购后立刻可用的功能。
1.5 横向看:五种分析范式#
把 Libra/DataTester 放回市场里,会发现「分析模块」并没有统一形态。公开文档与产品定位大致可以分成五种范式,每种范式的强项与盲区几乎互补:
| 范式 | 代表产品 | 分析入口 | 自定义能力 | 人群/下钻 | 高级统计 | 主要盲区 |
|---|---|---|---|---|---|---|
| 报表型 | Optimizely、VWO、AB Tasty、Convert | 实验结果页 | 指标 + 受众筛选,少量自定义 | 分段筛选为主,探索有限 | 内置 Stats Engine / Bayesian / 序贯 | 灵活探索弱;离开预设报表就回到 SQL |
| 探索型 | Amplitude、PostHog、Mixpanel | 事件分析 / 漏斗 / 留存 | 事件、属性、公式、 cohort | 强:任意事件、路径、cohort | 有实验统计,但深度与治理弱于专业平台 | 治理弱;指标口径容易散落 |
| 仓库原生 | Eppo、GrowthBook | 实验分析 + 数仓指标 | SQL/指标即代码,认证指标 | 强:维度、切片、cohort | CUPED、序贯、贝叶斯、多重比较 | 延迟与成本取决于数仓;需要数据工程能力 |
| 统计工作台 | Statsig | 实验 + 指标 + Pulse | 自定义指标、指标源 | 中:维度、holdout、分层 | 强:CUPED、序贯、贝叶斯、SRM | 产品分析深度不如探索型;上下文弱 |
| 人群/增长型 | DataTester、神策 | 实验报告 + 人群 + 营销 | 事件指标、人群包、Uplift | 强:人群圈选、差异分析、名单下载 | 中:频率派为主,Uplift 有产品化 | 容易把「人群运营」当成「因果结论」 |
推断 这张表是「公开文档 + 产品定位」的归纳,不是逐项功能验收。比如「仓库原生」的延迟取决于客户数仓,不能一概而论;「探索型」的实验统计也在补课。真正稳定的差异是数据放在哪里、口径由谁定义、分析面向谁。
三个结论:
- 报表型强在结论,弱在探索;探索型相反。 前者适合 PM 快速拍板,后者适合分析师找假设;把两者做成同一个页面,往往两边都不满意。
- 仓库原生强在口径,弱在交互。 指标留在数仓、SQL 可审计,代价是每次下钻都可能等数仓;它最适合「指标治理成熟、分析频率不高」的组织。
- 统计工作台强在方法,弱在业务上下文。 CUPED、序贯、贝叶斯做得再细,如果用户不知道「这个指标对应哪个业务动作」,方法只会增加解释成本。
所以产品设计的第一步不是列功能,而是选主范式:我们到底要服务「拍板」「找假设」还是「治理口径」?选完之后,再用另外两种范式补短板。五种都想要,结果通常是五种都不像。
2025–2026 的所有权变化也要计入选型:Statsig 2025 年被 OpenAI 收购、2026 年由 Amplitude 接手品牌与客户;Eppo 自 2025 年起以 Eppo by Datadog 运营;VWO 与 AB Tasty 于 2026 年合并为 Wingify,但官方明确两边产品目前仍各自运行 来源 来源 来源。这意味着你看到的路线图,可能已经换了一个主人;选型时要问「收购后的产品归属、数据迁移与合同主体」,而不只是功能清单。
1.6 中国平台的三种分工#
把镜头拉远,中国大厂的分析模块大致有三种分工,各自解决不同的问题 来源 来源 来源:
| 分工 | 代表 | 分析模块的重心 | 代价 | 适合 |
|---|---|---|---|---|
| 运营工作台 | 字节 DataTester | 报告、模板、人群、Uplift、名单下载 | 统计深度让位于可用性;高级方法默认值不透明 | 业务方自助、运营驱动 |
| 统计底座 | 腾讯/美团 | CUPED、FDR、SRM、HTE、AA 验证、方法库 | 使用门槛高;需要 DS 解释 | 实验密集、决策风险高 |
| 数仓共生 | 阿里通天塔、得物 | 指标语义层、实时/离线链路、即席 OLAP | 强依赖数据团队;交互受预计算粒度限制 | 已有成熟数仓、指标治理 |
得物的三级查询是一个很务实的产品契约:ClickHouse 存预计算指标,承接大多数页面数字;StarRocks 承接复杂分析与明细聚合,秒级到分钟级;StarRocks 跑不动的查询自动降级到 ODPS,10 分钟到 1 小时;查询过程做并发限制与 Redis 缓存,避免拖垮 OLAP 集群 来源。这等于把「哪些秒回、哪些要等」写进了产品,而不是让用户在一个转圈页面里猜。
推断 三种分工没有高下,只有匹配:业务方自助强的组织,先学运营工作台;实验密度高、决策风险大的组织,先学统计底座;数仓成熟、指标统一的组织,先学数仓共生。最怕的是三种都想要,最后做成一个「有 Uplift 按钮、但没有指标 owner」的平台。
1.7 如果只能抄五件事#
- 指标组按业务问题组织,而不是按事件表组织;默认展示核心指标组,其他折叠。
- 筛选模板:把「一线城市 + 版本 ≥ 14 + 新用户」这种反复使用的口径保存成模板,实验级与应用级分层复用。
- 差异分析:属性过滤 + 用户分群 + 多组对比,让「对谁有效」成为标准动作,而不是分析师写 SQL。
- 人群下载:把分析结果变成可执行的名单,但必须带 ITE、bins、treatment 与业务 ID,方便运营验证。
- 诊断工具:把「为什么没命中/为什么数据不对」做成可查询的日志,而不是让用户猜。
2. 分析对象模型:让一次分析可复现#
大部分分析平台的数据模型只建模「实验」和「指标」,然后把人群、维度、时间窗、统计方法塞进查询参数。结果是:同一张报表,昨天和今天可能不是同一个问题;同一个人分享链接,另一个人打开看到的是另一套口径。
更稳的做法是把「一次分析」本身建模成对象。最小对象集是七个:
这七个对象里,最容易被漏掉的是 Method 和 Result。没有 Method,用户无法知道这个区间是固定样本还是序贯、是原始方差还是 CUPED、有没有做 FDR;没有 Result,用户无法复现「上周五看到的那张图」,也无法在指标定义变更后判断结论是否还成立。
任何分析请求都必须携带六个版本号:experiment_version、metric_version、cohort_version、dimension_snapshot、method_version、data_cutoff。少一个,结果就不可复现;多一个,存储成本可控。把六个版本号拼成的哈希写进结果表,就是「口径指纹」。报表页可以把它折叠在「证据」里,但当两个数字打架时,它是唯一能仲裁的东西。
2.1 信息架构:五个分析面,一条证据链#
分析页不是五个并列的 tab,而是一条从「要不要信」到「为什么」的链:
这条链的顺序不能反。先看人群再看指标,会把「找人群」变成「找显著」;先看高级分析再看总览,会把方法当成结论。产品上可以用 tab 呈现,但默认落地页必须是结论,且每个 tab 的顶部保留「当前实验 / 当前指标 / 当前人群 / 数据截止」的上下文条。
2.2 分析画布:六个槽位,三种保存#
把「自定义分析」做成一个画布,而不是一堆筛选器。画布只有六个槽位:
对象
哪个实验、哪个版本、哪个对比组。对象决定随机化单元与曝光口径,后续所有计算都继承它。
指标
一个核心指标 + 一组必看指标 + 若干探索指标。指标来自注册表,不能现场拼字段。
人群
全体、预定义分群、规则圈选或导入名单。必须显示人群版本、快照时间与预估人数。
维度
用于拆分或过滤的属性。维度有层级、有时间语义(进组时 / 当前),不能混用。
窗口
事件时间、进组时间、观察窗、归因窗。四个轴必须分别显示,不能只写「近 7 天」。
方法
估计量、区间、CUPED、序贯、多重比较、最小样本。默认值即产品观点。
同一个画布可以保存成三种资产:
- 视图(View):个人或团队的默认布局与筛选,轻量、可改。
- 模板(Template):跨实验复用的口径组合,例如「一线城市 + 版本 ≥ 14 + 新用户」。DataTester 的自定义筛选模板就是这一层,实验级最多 10 个、应用级最多 50 个 来源。
- 决策记录(Decision Record):不可变快照 + 结论 + owner + 评论 + 后续动作。它不属于「视图」,而属于组织资产。
三者混在一起,是分析平台最常见的信息架构错误:用户以为自己在保存视图,其实在修改团队口径;或者以为自己在分享结论,其实分享的是一个会随数据更新的链接。
3. 自定义分析:从「选指标」到「定义分析」#
「自定义分析」通常被理解成「让用户自己选指标和筛选条件」。这只是一层。完整的能力应该分四级,每级对应不同的治理成本:
| 层级 | 用户可以自定义什么 | 典型交互 | 治理要求 | 适合谁 |
|---|---|---|---|---|
| L1 过滤 | 时间、维度值、对比组 | 筛选 chips | 口径不变,只变切片 | 所有业务用户 |
| L2 人群 | 规则圈选、导入名单、分群复用 | 人群构建器 | 版本、快照、权限、样本量 | 运营、PM |
| L3 指标 | 事件、算子、分母、过滤、组合公式 | 指标构建器 | owner、版本、血缘、置信度支持 | 数据/分析团队 |
| L4 分析 | 维度组合、窗口、估计量、多重比较 | 分析画布 / DSL | 方法白名单、成本配额、审计 | DS、数据工程 |
多数平台只做到 L1-L2,然后把 L3-L4 留给 SQL。这看起来灵活,实际上把治理成本转嫁给了分析师:口径散落在 notebook 里,结论无法复现,指标无法跨实验复用。更好的做法是:L3 用注册表 + 构建器,L4 用受控 DSL,SQL 只作为逃生舱。
3.1 指标构建器:14 种算子,三个原子#
DataTester 的事件指标把「计算方式」产品化成了 14 种算子 来源。拆开看,它们其实是三个原子(count / sum / distinct)和四个分母(进组人数 AU、触发人数 UV、次数 PV、活跃天数 SUM(DAU))的组合:
| 算子 | 公式 | 回答的问题 | 是否支持置信度 |
|---|---|---|---|
| 人均次数 | PV / AU | 进组的人平均触发几次 | 是 |
| 转化率 | UV / AU | 进组的人里有多少人触发过 | 是 |
| 人均求和 | SUM / AU | 进组的人平均贡献多少金额/时长 | 是 |
| 人均日均 | SUM / SUM(DAU) | 活跃日均贡献 | 是 |
| 日均次数 | PV / SUM(DAU) | 每人每天平均几次 | 是 |
| 每次平均 | SUM / PV | 单次事件平均金额 | 是 |
| 人均触发人数 | PV / UV | 触发者平均触发几次 | 是 |
| 每次人均 | SUM / UV | 触发者平均贡献 | 是 |
| 总次数 | PV | 总量 | 否 |
| 总人数 | UV | 去重人数 | 否 |
| 求和 | SUM | 金额/时长总量 | 否 |
| 按属性去重 | COUNT(DISTINCT prop) | 例如按 session_id 去重 | 否 |
| 最新值人均 | SUM(最新值) / AU | 积分、等级等快照型指标 | 视实现 |
| 最早值人均 | SUM(首非空值) / AU | 首单金额、首充金额 | 视实现 |
「是否支持置信度」这一列比算子本身更重要。DataTester 明确说,PV、UV、SUM、按属性去重四类单指标不能计算置信水平;组合指标也只对特定分子/分母类型开放 来源。这不是产品缺陷,而是统计引擎的真实边界:方差必须从「每个用户一个值」的样本里估计,纯总量没有用户级分布。
建议 产品上不要把这些指标藏起来,而要显式标成「不可检验」。用户看到「总量 12.4 万,不可检验」比看到「总量 12.4 万,p=—」更不容易误读。更进一步,报告里应默认把「可检验指标」和「仅描述指标」分成两组,避免用户把不可检验的总量当成结论。
组合指标(CTR、CVR、PV/SUM)支持括号与四则运算,但同样有白名单 来源。比率指标最容易出错的地方是方差:设每人贡献 (y_i, x_i),比率 r = ȳ / x̄,Delta Method 的一阶近似是:
Var(r) ≈ (1 / (n · x̄²)) · [ Var(y) − 2r · Cov(y, x) + r² · Var(x) ]分子分母相关时丢掉协方差项,会系统性低估方差;如果随机化单元是用户、分母是 session,必须先在用户级把分子分母各自求和,再套公式;如果是 cluster 随机化,要先在 cluster 级聚合。这些不是实现细节,而是「为什么两个平台对同一个指标给出不同 p 值」的常见原因。
3.2 指标治理:被引用之后不能改口径#
DataTester 的规则很硬:指标一旦被实验关注,只能改名称和描述,不能改口径,也不能删除 来源。这是一个正确的默认值:指标是实验结论的「法律条文」,不能在判决之后改法条。
但仅有「不能改」不够。一个完整的指标治理至少要有:
- owner:谁对口径负责,出问题找谁;
- 版本:每次变更生成新版本,旧实验继续引用旧版本;
- 血缘:这个指标依赖哪些事件、属性、维表、上游指标;
- 认证:哪些指标经过数据质量与统计校验,可以用于决策;
- 下线状态:原表下线、事件废弃时,指标要自动标灰并通知引用方;
- 迁移工具:新建指标后,如何把历史实验的引用迁过去,而不是让用户手工重跑。
Eppo 把「认证」与「可计算」分开:认证指标只读,且 funnel 类型不可认证 来源。这个设计值得借鉴:认证不是「算得对」,而是「可以被用于决策」。两者之间隔着数据质量、口径评审与 owner 签字。
3.3 筛选模板:口径复用的最小单位#
DataTester 的自定义筛选模板支持把一组筛选条件保存下来,在实验内或应用内复用;实验级最多 10 个、应用级最多 50 个 来源。这个功能看起来小,但它解决的是分析平台最普遍的问题:同一个人每次看报表都要重新点一遍相同的筛选;不同的人对「高价值用户」有不同定义。
模板的产品设计要注意三点:
- 模板必须带 owner、描述、创建时间与使用次数。没有 owner 的模板,半年后就是「祖传口径」。
- 模板只保存筛选条件,不保存结论。结论应该进决策记录,而不是模板。
- 模板要有作用域:个人 → 实验 → 应用 → 组织。作用域越大,审批越重。DataTester 用「实验级 / 应用级」两级,是一个务实的起点。
3.4 自由 SQL:要有,但不能是主入口#
DataTester 提供 SQL 自定义查询,范围限定在近一年,前端展示 1000 行、下载上限 100 万行 来源。这些限制不是产品小气,而是把「扫描分区数、返回行数、内存、超时」四个维度写成了可执行的闸门。
自由 SQL 的正确位置是「逃生舱」,不是「主入口」:
- 必须走沙箱:只读、限库、限表、限分区、限并发;
- 必须写回分析对象:SQL 查询的结果要能保存成受控指标或一次性分析,而不是散落在聊天窗口;
- 必须显示成本:扫描量、预计耗时、结果行数,在提交前给用户看;
- 必须审计:谁查了哪些用户明细、导出了多少行、是否包含敏感字段。
建议 把「自定义 SQL」放在高级分析的最后,而不是指标页的第一个按钮。默认路径应该是「选注册指标 → 选人群 → 选维度 → 看结果」,只有当用户明确需要新指标时才进入 SQL。
3.5 过滤器挂在哪一层,决定结论是不是同一个问题#
竞品拆解里最有价值的一条,不是「谁支持自定义指标」,而是过滤器挂在哪一层。同一个「只看 iOS」的筛选,挂错层会得到三个不同的数 来源 来源:
| 挂载层 | 改了什么 | 随机化还在吗 | 典型入口 | 风险 |
|---|---|---|---|---|
| 分配层 / 人群层 | 改分母:谁进入比较 | 在(只要用进组前变量) | 实验受众、Segment、Variants Performed By | 人群太小、覆盖率下降 |
| 指标事件层 | 只改分子:哪些事件算指标 | 在,但分子分母不是同一批人 | 指标事件的 Where / 属性过滤 | 比率指标分母不变,口径错位 |
| 指标定义层 | 改语义:指标怎么定义 | 取决于定义 | 指标构建器、metric slice | 口径漂移,历史不可比 |
| 分析切片层 | 改分组/下钻 | 在,但比较次数膨胀 | 维度拆解、子群分析 | 多重比较、选择偏倚 |
Amplitude 的文档明确警告:给指标事件加国家过滤,分母仍然是全部曝光用户;正确做法是把过滤放到「Variants Performed By」 来源。GrowthBook 则把「用户属性」叫 dimension、「指标属性」叫 slice,并举例:同一用户跨国消费,dimension 会把全部消费算给首次国家,slice 只算该国部分 来源。两者都在说同一件事:「筛选」不是一个动作,而是四个不同的语义。
这也解释了为什么 Eppo 明确不对 segment 与 ad-hoc filter 计算 CUPED 来源:CUPED 的协变量与比较次数会随切片变化,平台宁愿不算,也不愿给一个看起来精确的错数。产品上应该把「这个筛选是否改变分母 / 是否参与校正 / 是否影响 CUPED」做成实时提示,而不是写在帮助文档里。
4. 圈定人群:最难的不是「圈」,而是「圈完之后」#
「圈定指定人群,看这批人的实验指标」听起来是一个筛选功能。实际上它同时踩在三个系统的交界处:标签/画像系统(这批人是谁)、分流系统(他们怎么进组)、统计引擎(这批人的差异是不是真的)。任何一处口径不一致,结论都会失真。
4.1 人群的五种来源#
| 来源 | 怎么定义 | 更新方式 | ID 口径 | 最适合 | 主要风险 |
|---|---|---|---|---|---|
| 规则圈选 | 事件做过/没做过/依次做过 + 用户属性 + 时间窗 | 日更或手动 | 平台 uid / device_id | 运营定向、子群分析 | 规则随时间漂移;事件回补导致人群变化 |
| 文件上传 | CSV 名单(uid、ssid、device_id) | 静态快照 | 上传文件指定 | 大客户名单、线下人群、holdout | ID 映射丢失;名单过期;隐私合规 |
| 标签/画像 | 标签平台或 CDP 的预计算标签 | 标签平台调度 | 标签平台 uid | 高价值、生命周期、兴趣偏好 | 标签定义不可见;更新延迟;跨平台 ID 不一致 |
| 行为序列 | 按事件顺序/次数/天数定义 | 日更 | 平台 uid | 流失预警、路径人群 | 序列窗口与实验期重叠导致后处理 |
| 实验命中人群 | 某实验某版本的进组用户 | 实时/日更 | 实验 uid | 父子实验、组合策略、holdout | 父实验变更导致基准人群变化 |
DataTester 的用户分群支持规则圈选与文件上传,规则覆盖「做过 / 没做过 / 依次做过 / 用户是 / 用户不是」,支持 AND/OR 与嵌套;日更在每天 6 点计算前一天数据、8 点前完成,纯静态时间窗只能手动更新;单条规则的时间窗最长 365 天 来源。这些限制看起来是工程细节,实际上决定了人群能不能用于长周期实验。
4.2 规则模型:一棵树,而不是一行 SQL#
一个可维护的人群规则应该是一棵树:
{
"cohort_id": "c_new_tier1_v3",
"version": 3,
"snapshot_at": "2026-10-20T06:00:00+08:00",
"refresh": "daily",
"root": {
"op": "AND",
"children": [
{ "type": "user_attr", "field": "is_new_user", "op": "=", "value": true },
{ "type": "user_attr", "field": "city_tier", "op": "in", "value": ["T1", "new_T1"] },
{
"op": "OR",
"children": [
{ "type": "event", "event": "app_launch", "agg": "count", "window": "7d", "op": ">=", "value": 3 },
{ "type": "event", "event": "pay_success", "agg": "sum", "prop": "amount", "window": "30d", "op": ">=", "value": 100 }
]
}
]
}
}这棵树要能编译成三种执行计划:SQL(明细扫描)、Bitmap(集合交并差)、标签查询(调用外部标签服务)。三种计划的结果必须一致,否则同一个分群在实验配置页和报告页会显示不同人数。
B 站的公开实践是把北极星、标签画像、AB 实验人群包都建在 ClickHouse 的 Roaring Bitmap 上 来源。好处是人群圈选、标签、行为分析共用一套编码与属性字典;代价是实验平台对上游依赖很重,字典服务或 ClickHouse 抖动会同时影响配置与人群包。腾讯微信的 BSI(Bit-Sliced Index)则把曝光、指标、维度统一编码成「分析单元 ID + 值」,让同一用户在所有 BSI 中位置一致,天然完成 Join 来源。两种路线都说明:人群不是一张名单,而是一种可复用的集合编码。
4.3 关键设计:先 hash 再过滤#
DataTester 文档里有一句非常关键的话:分流时,非白名单用户先做 hash 分桶,再做人群过滤 来源。更准确地说,是「层桶判定 → 人群过滤 → 实验桶/版本命中」:人群夹在层与实验之间,既不影响层内随机化,也不影响版本分配 来源。这意味着人群规则影响的是「谁有资格进入实验」,而不是「谁被分到哪个组」。
这个顺序带来四个后果:
- 处理分配仍然随机(在人群条件可测且实验前固定的前提下),人群内比较有效。
- 报告里的「进组人数」是过滤后的人数,不是桶内人数;圈了 10 万、报告只有 3 万是正常的,流量被浪费在人群外。
- 日更人群会让同一用户在实验期间进出人群;「进组不出组」要求一旦进组就保持版本,但用户被人群规则踢出后是否还算进组,公开文档没写,属于未知。
- 如果人群规则用了实验后的行为(例如「近 7 天未购买」),人群本身就被处理影响了,这是后处理偏倚,随机化救不了。
建议 产品上必须把「人群作用位置」做成一个显式选择,而不是藏在高级设置里:
很多自建平台把这两个概念混成一个「人群」字段,结果运营想定向、分析师想分层,用的是同一个入口。正确的做法是:实验人群在创建实验时锁定,分析人群在报告页随时可换,但换了之后必须重新做样本量与多重比较检查。
4.4 四个象限:什么时候人群分析是可信的#
把「人群定义时点」和「是否随机化」交叉,可以得到四个象限:
| 进组前定义(pre-treatment) | 进组后定义(post-treatment) | |
|---|---|---|
| 随机化分配 | ✅ 确证性子群:可以做交互检验、分层报告 | ⚠️ 选择偏倚:只能做探索,不能做因果结论 |
| 非随机化 / 观察性 | ⚠️ 观察性比较:需要倾向得分、DiD、敏感性分析 | ❌ 基本不可解释:处理与选择同时作用 |
如果人群变量 B 在「处理 T → 结果 Y」的路径上(T→B→Y),条件化 B 估到的是直接效应,不是总效应;如果 B 同时受 T 和 Y 影响(T→B←Y),条件化 B 会打开一条非因果路径,这就是 collider/selection bias。此时即使 T 原本随机,B=1 的子群里也不再有交换性。最危险的是右下角,但业务上最常见的是右上角。比如:
- 「圈出实验期点击过新卡片的用户,看他们的 7 日留存」——点击是处理的下游,点击组和未点击组的差异混合了处理效应与自选择。
- 「圈出实验期停留超过 60 秒的用户,看转化率」——停留受处理影响,且与转化互为因果。
- 「圈出完成下单的用户,看客单价」——这是条件于结果(collider),不是实验结论。
- 「圈出近 7 天未活跃的用户,看召回效果」——如果实验本身影响活跃,人群被处理污染。
建议 产品上给人群规则加一个「时点校验」:凡是规则中引用的事件/属性时间窗与实验期重叠,就弹出提示「该人群可能受实验影响,结果将标记为探索性」。这不是阻止用户,而是让用户知道自己在做什么。
4.5 多重比较:20 次切片,64% 至少一个假阳性#
这是最需要产品化、却最常被忽略的一层。按独立检验粗算:
- 5 个指标 × 4 个人群 = 20 次检验,至少一次
p<0.05的概率约 64%; - 10 个指标 × 10 个人群 = 100 次检验,概率约 99.4%;
- 如果再叠加 5 个变体,检验次数轻松上百。
还有一个常被忽略的陷阱:一个子群显著、另一个不显著,不能推出「两个子群的效应有差异」。正确做法是预注册少量子群,看处理 × 子群的交互项,而不是在每个子群里各跑一次检验 来源。这不是平台算错,而是「看得越多,越容易看到显著」。更麻烦的是事后定义:先看结果,再圈一个「高价值、低活跃、近 30 天没下单」的人群,等于把选择藏进了分析;校正只能覆盖登记过的检验,覆盖不了用户脑子里那条还没说出口的假设。
产品化的正确顺序是:
- 预注册:创建实验时声明主指标、预期方向、目标 MDE、分析窗口、预定义子群;任何修改生成新版本并标
post-hoc。 - 家族定义:主指标拿较宽的 α,次要指标用 BH 控 FDR,护栏用 Holm 控 FWER,子群先做交互检验而不是逐格检验。
- 默认校正:页面同时显示 raw p 与 adjusted p,默认按 adjusted 排序;当 adjusted 跨 0 而 raw 显著时,文案必须写「校正后不显著」,不能写「有趋势」。
- 探索降级:没有预注册的子群,结论只能写成「下一轮实验的假设」,不能写成「对某人群有效」。
- 复验:确证要靠新的实验——把人群放进分流,让「人群」成为随机化因子,而不是事后切片。
推断 DataTester 的差异分析与敏感人群文档没有说明多重比较校正口径。不能据此断言产品没有校正,但产品设计必须假设用户不会自己校正。GrowthBook 的做法可以作为参考:校正家族是 goals × variations × dimensions,维度切片单独校正 来源;它的结果页还会直接插入 SRM 与多重曝光警告 来源。
4.6 样本量:子群越小,结论越贵#
子群分析的第一道门槛不是显著性,而是样本量是否撑得起你想要的 MDE。一个粗略的直觉:
n per arm ≈ 16 · σ² / Δ² (均值指标,α=0.05,power=80%)
n per arm ≈ 16 · p(1−p) / Δ² (比例指标)当子群只有几千人时,能检测到的效应往往比业务关心的阈值大一个数量级;此时「不显著」几乎不提供信息,「显著」则更容易是噪声。DataTester 的敏感人群文档建议进组人数大于 2 万、分析维度大于 4 个,并明确说样本不足时模型会不稳定 来源。这不是保守,而是经验阈值。
一条可落地的红线(建议,不是平台规则):每组 <100 人不读效应,只查埋点/bug;100–500 人只报方向与 CI;500–1,000 人可做探索性检验,必须标「未校正」;≥1,000 人且每格 ≥5 个事件,才做正式检验,并仍需 SRM + 多重比较。Uplift/敏感人群按官方建议 >2 万人、>4 维 来源。
产品上应该给每个子群自动算三件事:
- 当前样本量 / 目标样本量;
- 当前可检测的 MDE;
- 置信区间宽度。
如果 MDE 大于业务目标提升,页面应该直接写「证据不足」,而不是「不显著」。这两句话对决策的含义完全不同:前者是「再等等/再扩样本」,后者是「大概率没效果」。
4.7 人群分析的八条准入检查#
时点
人群规则的时间窗是否完全落在实验开始之前?如果与实验期重叠,是否已标记为 post-treatment?
随机化
人群是在分流前还是分流后生效?分流后过滤是否保持了处理分配的随机性?
版本
人群是否有版本号与快照时间?报告是否显示「这批人是什么时候算的」?
样本
每个子群的样本量、MDE、CI 宽度是否足够?是否低于产品规定的最小样本?
多重比较
本次分析一共做了多少次检验?家族如何定义?adjusted p 是多少?
SRM
子群内的实际分配比例是否与设计一致?分维度 SRM 是否通过?
外部有效性
子群效应能否外推到全量?是否存在 SUTVA/溢出/组成变化?
行动
结论是「可以定向投放」还是「需要新实验复验」?是否已经写进决策记录?
4.8 数据模型与隐私#
人群服务的核心表至少要有:
| 表 | 关键字段 | 作用 |
|---|---|---|
cohort_def |
cohort_id, version, rule_json, owner, created_at, status | 规则定义与版本 |
cohort_snapshot |
cohort_id, version, snapshot_at, uid_hash, segment_id | 某次计算的成员快照 |
cohort_stats |
cohort_id, version, estimated_reach, overlap_json, refreshed_at | 人数、重叠、刷新状态 |
cohort_audit |
cohort_id, action, actor, reason, ts | 创建、修改、导出、删除的审计 |
experiment_cohort_binding |
experiment_id, cohort_version, stage(assignment/analysis), applied_at | 明确人群在哪一步生效;stage=analysis 且规则含实验期事件时应拒绝或强制标探索 |
隐私上,人群包是最容易出事的资产:它可能包含敏感标签(未成年人、金融状况、健康状况)、可识别 ID、跨实验行为。至少要做到:
- 敏感标签分级:高敏标签不进入人群构建器,或必须审批;
- 导出审批:用户明细导出走审批流,默认脱敏、默认采样、默认限额;
- 行级权限:只有被授权的人能看到某个人群包的成员列表,而不是只有聚合人数;
- 用途绑定:人群包绑定用途(分析/投放/导出),跨用途需要重新授权;
- 留存期限:静态人群包设置过期时间,避免「两年前的名单」被反复使用。
5. 下钻:从「知道」到「知道为什么」#
下钻是分析模块最容易被低估的部分。很多平台把它实现成「加一个 group by」,结果用户点开一个维度,看到 200 个值、每个值都没有样本量、显著性颜色乱跳,最后关掉页面。真正的下钻不是「拆得更细」,而是在保持对照与统计有效性的前提下,把结论定位到一个可行动的切片。
5.1 下钻的五个层级#
| 层级 | 用户的问题 | 典型交互 | 查询形态 | 必须保留的护栏 |
|---|---|---|---|---|
| L1 指标 | 哪个指标动了? | 指标表、指标卡 | 多指标聚合 | 指标版本、样本量、CI |
| L2 维度 | 动在哪个渠道/城市/机型? | 维度切换、排序、TopN | GROUP BY dimension |
每切片 N、CI、多重比较状态 |
| L3 维度值 | 这个渠道里,哪个城市在动? | 点击柱状图、面包屑 | 带 filter 的 GROUP BY |
上一层人数、当前层人数、占比 |
| L4 人群 | 是某一类人吗? | 人群叠加、交集、对比 | cohort join + group by | 人群时点、版本、重叠 |
| L5 用户/事件 | 具体是谁?发生了什么? | 用户列表、行为流、事件详情 | 明细查询 | 脱敏、采样、权限、审计 |
DataTester 的用户详情页提供了 L5 的样本:可以按 UUID/SSID 查用户,查看基础信息、设备、画像、按时间排序的行为流,支持按 App/设备/事件/属性过滤、重要事件高亮、CSV 下载(最长 30 天)来源。这是一个正确的方向:从聚合到个体,但个体视图是「诊断工具」,不是「结论工具」。用户列表不能用来证明效应,只能用来解释异常、复现问题、构造假设。
5.2 交互规范:下钻不是跳页#
一个可用的下钻交互,至少要满足八条:
- 面包屑可回退:
全部用户 / 渠道=应用商店 / 城市=一线,每一级可点击,可清除。 - 对照锁定:无论下钻到哪一层,A/B 对照关系不变;不能出现「这一层只剩实验组」。
- 样本量常驻:每一层显示当前切片 N、基准 N、占比;N 低于阈值时灰显或折叠。
- 统计状态常驻:CI、p、校正状态、是否探索性,跟着切片走,而不是只在顶层显示。
- URL 可分享:当前实验、指标、人群、维度路径、时间窗、方法全部编码进 URL;分享给同事打开是同一个问题。
- 返回不丢上下文:从用户列表返回,仍停留在原来的切片,而不是回到顶层。
- 跨图联动可控:点击趋势图某一天、分布图某个区间,应该变成「时间/数值过滤」,而不是悄悄换指标。
- 「解释这个数」入口:每个数字旁边有口径、样本、查询耗时、数据截止时间,而不是只有 tooltip。
建议 把下钻做成「行内展开 + 右侧抽屉」的组合:维度拆解在指标行下方展开,用户明细在右侧抽屉打开。这样既保留上下文,又不需要在页面之间来回跳。
5.3 维度层级与高基数#
维度不是一堆字符串,而是有层级、有语义的对象:
- 地理:国家 → 省 → 城市 → 区县;
- 渠道:一级渠道 → 二级渠道 → 投放计划;
- 版本:App 大版本 → 小版本 → 构建号;
- 用户:新/老 → 活跃分层 → 生命周期阶段;
- 设备:平台 → 机型 → 屏幕尺寸。
产品上要区分两种下钻:
- 层级下钻(hierarchical):沿预定义层级逐级展开,适合地理、渠道、版本;每级自动带上父级过滤。
- 任意拆分(ad hoc):用户任选维度组合,适合探索;必须限制维度数量与组合爆炸。
高基数维度是下钻的性能杀手。一个机型维度可能有 10 万值,一个 URL 维度可能上百万。可行的策略是:
- TopN + 其他:默认展示 Top 20,其余聚合为「其他」,并明确标注;
- 搜索 + 选择:不默认全量渲染,用户搜索后再查;
- 最小样本阈值:低于阈值(如 100 人/组)的值折叠或灰显;
- 预聚合:高频维度做 cube,低频维度走明细;
- 近似:UV 可用 HyperLogLog/Bitmap 近似,但要在 UI 标注「近似值」。
DataTester 有一条很诚实的限制:属性分组之后,不支持切换 preAA 数据、查看数据分布和箱线图 来源。这大概率是因为分组查询走预聚合/cube 路径,原始用户分布不在 cube 里。这就是「预聚合换性能」的真实代价:产品文档比架构图更诚实。与其假装什么都能下钻,不如在 UI 上明确「这个视图在当前粒度不可用」,并给一个替代入口。
5.4 用户级下钻:能看到人,但不能带走人#
从聚合到用户,是分析模块最敏感的一步。产品上要默认「三不」:
- 不默认展示全量:先给样本(如 100 条),需要更多再申请;
- 不默认展示原始 ID:脱敏为
u_8f3a•••,需要原始 ID 走审批; - 不默认允许导出:导出是独立权限,带水印、限额、审计。
DataTester 的报告支持下载进组用户 ID(上限 500 万)来源,用户详情支持行为流 CSV 下载(最长 30 天)来源。这些能力对分析很重要,但必须与权限、审计、脱敏一起设计。否则「下钻」会变成「拖库」。
5.5 查询实现:预聚合、即席与混合#
下钻的性能取决于三个选择:
| 方案 | 怎么工作 | 优点 | 缺点 | 适合 |
|---|---|---|---|---|
| 全预聚合 | 提前算好所有维度组合的 cube | 亚秒级、稳定 | 维度组合爆炸、无法回答临时问题 | 固定报表、核心指标 |
| 全即席 | 每次查询扫明细/宽表 | 灵活、口径统一 | 慢、贵、并发差 | 探索、长尾维度 |
| 混合 | 高频 cube + 低频即席 + 结果缓存 | 平衡 | 实现复杂、口径需对齐 | 大多数生产平台 |
一个务实的做法是「三级查询」:
- L1 缓存/预计算:固定报表、核心指标、常用切片,命中直接返回;
- L2 同步即席:单指标 + 单维度 + 有限时间窗,走 ClickHouse/Doris,目标 P95 < 2 秒;
- L3 异步任务:多指标 × 多维度 × 长窗口、用户明细导出,进队列,给进度与取消。
腾讯微信的公开论文给了一个极端的工程样本:Spark 例行预计算 + ClickHouse 即席下钻,BSI 运算经 JNI 调 SIMD;预计算负责 scorecard 与 CUPED,即席负责下钻 来源。这不是每个团队都能复制的,但它说明了一个原则:预计算与即席不是二选一,而是按查询模式分工。
缓存 key 必须包含所有影响结果的版本:hash(experiment_version, metric_version, cohort_version, dim_set, time_range, granularity, filter_hash, engine_version)。少一项,就会出现「改了定义但报表没变」的幽灵。
5.6 性能预算:下钻的速度决定分析的深度#
| 动作 | 目标 P50 | 目标 P95 | 超时策略 |
|---|---|---|---|
| 首屏结论 | < 800ms | < 1.5s | 骨架屏 + 上次快照 |
| 指标切换 | < 500ms | < 1s | 预取相邻指标 |
| 维度切换 | < 800ms | < 2s | 缓存 + 取消旧请求 |
| 二级下钻 | < 1.2s | < 2.5s | 异步 + 进度 |
| 用户列表 | < 1s | < 3s | 采样 + 分页 |
| 导出 | 立即受理 | 异步 | 队列 + 通知 + 限额 |
这些数字不是拍脑袋:超过 2 秒,用户就会失去「连续探索」的感觉,退回「先想好问题再查」的模式;而分析的价值恰恰来自连续追问。性能预算应该写进 PRD,和功能一起验收。
5.7 六个下钻反模式#
- 把子群当结论:在 20 个切片里挑一个显著的,写成「对某人群有效」。→ 必须标探索性 + FDR。
- 下钻后对照组消失:某切片只剩实验组,仍然显示「提升」。→ 必须显示两组 N,缺一组就禁用结论。
- 维度值洪水:一次渲染 500 个机型,用户找不到重点。→ TopN + 搜索 + 最小样本。
- 口径漂移:下钻时换了指标定义/时间窗,用户不知道。→ 上下文条常驻 + 版本号。
- 缓存串租户:A 租户的查询结果被 B 租户命中。→ 缓存 key 带 tenant_id + 权限校验。
- 导出泄露:用户列表导出包含敏感字段/全量 ID。→ 脱敏、审批、水印、审计。
6. 高级分析:默认严谨,逐项解释#
高级分析的功能清单很容易做:CUPED、Uplift、序贯、贝叶斯、DiD、合成控制,每个名字都能变成一个菜单项。难的是另一件事:当用户点下这个菜单项时,平台是否替他承担了假设检查、多重比较、失败解释和决策责任。
6.1 产品化的四层接口#
入口即契约
选方法前先问:随机化单元是什么、指标是比例/均值/比率/分位数、有没有可信的 pre-period、有没有 interference。不满足条件,方法不出现在可选列表里,而不是选完再报错。
默认值即观点
CUPED 默认开、SRM 默认拦、多重比较默认按家族校正、序贯默认只用于监控。这些默认值直接决定用户看到的数字。
结果即解释
每个数字带口径、窗口、样本量、CI、校正后的 p;每个失败态给出下一步动作,而不是一句「无显著差异」。
成本可见
CI 会变宽多少、样本要膨胀多少、实验会慢几天,在选方法时就预估;不要等上线后才发现「高级方法」的代价。
6.2 方法菜单:每个方法回答什么问题#
| 方法 | 业务问题 | 关键假设 | 产品如何暴露 | 什么时候不该用 |
|---|---|---|---|---|
| CUPED / 方差缩减 | 同样流量下更早看见小效应 | pre 期协变量未被处理污染、与结果线性相关、同随机化单元 | 默认开;结果页并列「调整前/后」;显示实际方差缩减;新用户/分位数灰显 | 新用户无 pre 数据;pre 期被上一实验污染;分位数直接套用 |
| CATE / HTE | 对谁效果更大,能不能做定向 | 预注册子群;causal forest 需 honest splitting | 先给交互检验 p,不逐格标星;默认收缩 + 区间;标「探索性」 | 整体不显著却扫 20 个子群;子群只有几百人 |
| Uplift | 给谁发券、推内容,增量最大 | 随机 T/C;特征在处理前;无 interference | 独立任务向导;输出 TOP 敏感人群、特征重要度、ITE 分箱下载;要求样本外验证 | 进组 < 2 万;无随机对照;用 post-treatment 行为做特征 |
| 序贯 / always-valid | 天天看报告,想早停又不想膨胀假阳性 | alpha spending 或 mSPRT;看点/参数揭盲前固定 | 监控区间与「宣布胜利」分开;CI 变宽时解释「为随时可停付费」;早停提示效应高估 | 事后改看点;拿早停效应量做收益预测 |
| 贝叶斯 | 小样本、决策者要概率和损失 | 先验 + 似然;同随机化单元的 i.i.d. 或已聚合 | 先验卡片写清来源/尺度;CTW 与期望损失双读数;先验敏感性三档 | 没有历史先验却拍强先验;把贝叶斯当 peeking 免死金牌 |
| 多重比较 | 多指标、多变体、多切片下控制假阳性 | 检验家族在揭盲前定义 | 自动登记家族;显示「本页 N 次检验」;raw p 与 adjusted p 并列 | 把探索性切片当确认性结论;家族事后扩大 |
| SRM | 分流、埋点、管道是不是坏了 | 卡方检验;低 α(0.001/0.0005) | 每次刷新自动跑;红条 + 隐藏 treatment effect;按端/版本/国家下钻 | 用重加权「修复」样本;只看 p 不看绝对偏差 |
| Cohort / Retention | 策略是否改变长期留存 | 按首次进组日分 cohort;观察窗成熟 | 热力图 + 按进组日拆分;未成熟 cohort 灰显 | 7 日留存只看 3 天;跨 cohort 直接比 |
| Funnel | 哪一步流失,策略改善了哪一层 | UV 口径;曝光作为第 0 步;转化窗口 | 漏斗图 + 每层转化率/流失;版本对比给 CI | 步骤可跳过/无序;逐层各做一次检验却不校正 |
| DiD | 无法随机化时,用 pre-trend 构造反事实 | 平行趋势、无同期冲击、处理外生、多期 pre | 强制画 pre-trend 与 placebo;输出 ATT 而非 ATE | 平行趋势不成立;只有 1 期 pre |
| Synthetic Control | 单个城市/市场的长期效应 | donor 池足够、pre 期拟合好、无同期政策 | 权重表 + 拟合图 + placebo 分布 | donor 太少或被污染 |
| MAB | 多版本动态分配流量,最大化累计收益 | Thompson/UCB;自适应分配破坏 i.i.d. | 与 A/B 分开的实验类型;显示「优化」而非「因果」;不提供 p 值 | 需要无偏 ATE;看长期效应;护栏指标 |
这张表最重要的不是「支持多少方法」,而是「什么时候不该用」。一个方法如果只能在满足假设时使用,产品就必须在入口处做检查,而不是在结果页写一行免责声明。
6.3 CUPED:默认开,但要说清代价#
CUPED 的逻辑很简单:用实验前的协变量 X 解释实验期的 Y,把「本来就会不同」的部分减掉:
Y_adj = Y − θ · (X − X̄)
θ = Cov(Y, X) / Var(X)
方差缩减 ≈ ρ²产品上最容易犯的错,是只给一个「CUPED 已开启」的开关,不给用户看:
- 用了哪段 pre 期?pre 期是否被上一个实验污染?
- 协变量与当前指标的相关性是多少?实际方差缩减了多少?
- 新用户没有 pre 数据,是否被排除?排除后样本量变化多少?
- 分位数/比率指标是否直接套用了均值 CUPED?
建议 结果页并列显示「原始」与「CUPED」两套数字,并给出方差缩减比例;当 CUPED 改变结论方向时,强制提示「结论对协变量调整敏感」,而不是只展示调整后的漂亮区间。Eppo 的文档把 CUPED 的假设、协变量选择与实现讲得比较清楚 来源,可以作为产品文案的参考。
6.4 Uplift / CATE:从「找人群」到「验证人群」#
Uplift 的产品价值不在模型,而在交付:一群人、一个方向、一个可执行的名单。DataTester 的敏感人群洞察把这件事做成了完整工作流 来源:
- 任务粒度是「一个指标、一个实验组、一个对照组」;
- 挖掘方向分正向/负向;
- 输出 TOP 敏感人群、特征重要性、TOP 3 特征的二维交叉子群;
- 支持下载人群明细(treatment、uid、ite、bins、业务 ID)。
但它也暴露了 Uplift 的典型风险:
- 推荐入组人数 > 2 万、维度 > 4 个,否则模型不稳定;
- 子群是「TOP 特征交叉」选出来的,存在选择偏倚;
- 公开文档没有说明子群 p 值是否做多重比较校正,产品上应按「未校正」处理;
- ITE 是模型预测,不是个体真实因果效应;
- 下载名单用于全量投放前,应该做 holdout 验证。
建议 产品上把 Uplift 放进「探索」层,把验证放进一个新的 confirmatory 实验:用 Uplift 选出人群 → 设计一个只看这批人的 A/B → 用 holdout 验证增量 → 再决定是否全量。这个闭环比「模型 AUC 很高」更有说服力。
6.5 序贯与贝叶斯:让「随时看」不再等于「假阳性」#
实验平台最常见的用户行为是「每天打开报告看一眼」。在固定样本频率派框架下,这会让一类错误膨胀;序贯检验/always-valid 就是为这个场景设计的。产品上要区分两件事:
- 监控:每天看趋势、护栏、SRM,不宣布胜负;
- 决策:达到预定义样本/时间后,用固定样本或序贯的正式区间做结论。
如果平台支持「随时可停」,就必须同时支持:
- alpha spending 或 confidence sequence;
- 预定义看点与参数锁定;
- 早停时的效应量高估提示;
- 多指标/多版本的额外校正。
贝叶斯则是另一条路:给决策者「获胜概率/期望损失」,而不是 p 值。它的产品难点在先验:没有历史数据却拍一个强先验,比不做贝叶斯更危险。Eppo 对贝叶斯与频率派方法的对比写得比较克制 来源,可以作为术语与文案的参考。
6.6 多重比较:先定义家族,再谈显著性#
多重比较不是「把 p 值乘一个数」那么简单。产品必须先帮用户定义「家族」:
- 一个实验里的所有变体 × 所有指标,是一个家族;
- 一个指标下的所有维度切片,是另一个家族;
- 护栏指标应该单独一个家族,用更严的 FWER;
- 子群应该先做交互检验,而不是逐格检验。
常见方法:
- Bonferroni:
α/m,保守但简单; - Holm:逐步法,比 Bonferroni 有更高功效;
- BH:控制 FDR,适合探索性指标多、但可以接受少量假阳性的场景。
建议 默认策略:主指标 preferential α,次要指标 BH,护栏 Holm,子群先交互。界面同时显示 raw p 与 adjusted p,默认按 adjusted 排序;当 adjusted 跨 0 而 raw 显著时,文案必须写「校正后不显著」,不能写「有趋势」。
6.7 为什么「自定义人群 + 高级方法」最容易产生假阳性#
三个乘数叠在一起:
- 人群定义的自由度:年龄、城市、活跃度、价格敏感、生命周期……可以切出无数个子群;
- 指标的自由度:5 个指标 × 4 个人群 = 20 次检验,至少一次假阳性的概率约 64%;
- 方法的自由度:CUPED 开/关、贝叶斯先验、序贯看点、异常值处理,每一种都能改变结论。
更麻烦的是事后定义:先看结果,再圈一个「高价值、低活跃、近 30 天没下单」的人群,等于把选择藏进了分析。校正只能覆盖登记过的检验,覆盖不了用户脑子里那条还没说出口的假设。
LLM 会把这条乘法器再放大一次:让模型扫描所有切片、挑出「最值得讲」的三个,再写一段原因,等于把数据挖掘自动化。每一句听起来合理的解释,背后都可能是一个未登记的检验。
6.8 方法选择决策表#
| 实验场景 | 样本量 | 指标类型 | 有 pre-period | 有 interference | 首选 | 不要用 |
|---|---|---|---|---|---|---|
| 用户级 A/B,常规迭代 | 充足 | 比例/均值 | 有 | 无 | CUPED + 固定样本/序贯监控 + Holm/BH + SRM 门禁 | 无 pre 硬开 CUPED;多指标不校正 |
| 用户级 A/B,小流量 | 不足 | 比例 | 无 | 无 | 贝叶斯弱先验 + 预注册 + 延长实验;先算 MDE | 扫子群找显著;强先验 |
| 多版本/多指标 | 充足 | 混合 | 有 | 无 | 主指标 preferential α,次要 BH,序贯只做监控 | 每个变体各做一次 5% 检验 |
| 子群/个性化 | 视子群而定 | 均值/比例 | 有 | 无 | 预注册子群 + 交互检验;样本足够才上 causal forest | 整体不显著后扫 20 个子群 |
| 长期留存/LTV | 充足 | 留存/金额 | 有 | 可能 | Cohort + Holdout;看成熟窗口 | 用首日/3 日数据下结论 |
| 无法随机化(城市/市场) | 少 | 均值 | 有多期 | 可能 | DiD(平行趋势成立)或 Synthetic Control | 平行趋势不成立还硬做 DiD |
| 双边市场/社交网络 | 充足 | 均值/比例 | 有 | 有 | Cluster randomization 或 Switchback | 用户级 A/B + 普通方差 |
| 排序/推荐 | 中等 | 偏好/点击 | 无 | 同用户内 | Interleaving 预筛,再接 A/B 确认 | 直接用 interleaving 做 ship 决策 |
| 短活动/高机会成本 | 中等 | 单目标 | 无 | 无 | MAB 做流量优化 | 用 MAB 要无偏 ATE 或护栏结论 |
6.9 LLM 在分析模块里的可信边界#
LLM 在实验分析里能做三层,可信度依次下降:
- 叙述层:把已经算好的结果翻译成业务语言。安全,前提是数字只能来自结果对象。
- 诊断层:提示 SRM、MDE 不足、cohort 未成熟、样本低于门槛。较安全,因为规则可审计。
- 归因层:解释「为什么涨」。不安全。实验识别的是效应,不是机制;机制要靠埋点、日志、访谈和后续实验去验证。
产品规则可以写得很硬:
- 数字白名单:只允许引用结果对象里的字段;每个数字带 cell 链接;没有计算就写「未计算」,不许估。
- 拒绝条件:SRM 未过、样本低于门槛、CI 跨 0、校正后不显著时,不允许生成「获胜原因」。
- 归因措辞:只能写「可能机制(待验证)」,并列出还需要什么证据;不能写「因为 X 所以 Y」。
- LLM 提议的切片就是新的检验:必须登记、校正,或放到 holdout 上验证;否则就是自动化 data dredging。
- 评估与审计:用历史实验的已知结论做回归测试;记录模型、提示、上下文、版本;上线决策必须有人签字。
字节在 AICon 2024/2025 的公开演讲里提到,用 LLM 做实验分析提效、实验咨询与分析智能体 来源 来源。这是方向,不是交付证据。对产品团队的含义是:LLM 应该先做「叙述 + 诊断」,不要把「归因」当成默认能力;否则它会用最流畅的语言,放大最脆弱的统计结论。
7. 页面设计:一张分析页的解剖#
分析页不是「数据展示页」,而是「决策证据页」。四类用户不是四种并列视图,而是同一条证据链上的四个检查点:
| 角色 | JTBD | 首屏必须回答 | 最怕的失败 |
|---|---|---|---|
| PM | 决定是否上线 | 这版能不能上?大概多多少?有没有踩护栏? | 把「不显著」当「无效果」;只看相对提升 |
| DS | 为效应背书 | 效应可信吗?证据够吗?哪个子群在动? | 只看 p 值;切片多重比较;口径被改过不知道 |
| 数据工程 | 保障口径与性能 | 这个数怎么算?何时更新?为什么慢或为空? | 同名不同义;漏斗改动回溯影响所有实验 |
| 管理者 | 组合决策 | 哪些该上、哪些该停、整体风险如何? | 单实验视角;没有决策记录;赢家诅咒 |
7.1 首屏:只回答「要不要动」#
指标
人群
下钻
高级
诊断
状态
owner
数据截止
指标 v3
主指标 +3.2%(CI 1.1~5.4)
N=82,140 / 82,003 · 护栏 4/4
指标 · 基准 · 绝对差 · 相对差 · CI · 状态
行内展开:趋势 / 分布 / 箱线 / 维度拆解
面包屑 · 每层 N · CI
用户样本(脱敏)
查询耗时 / 缓存
方法卡
版本历史
评论 / 决策记录
首屏的权重顺序是:结论 > 护栏 > 核心指标 > 证据入口 > 诊断。图表回答「怎么变」,首屏要回答「做不做」。DataTester 把结论放在实验概览区,并用颜色标显著方向 来源;但「建议」应该由实验 owner 写,系统只给证据。这个分工很重要:平台不能替组织做决策,但必须让决策所需的信息在 5 秒内可见。
7.2 关键组件:每个组件都在回答一个反驳#
| 组件 | 要回答的反驳 | 设计要点 | 代价 / 边界 |
|---|---|---|---|
| 结论卡 | 凭什么这么说? | 一句话结论 + 主指标 + 绝对/相对效应 + CI + N + 证据等级 | 一句话必然压缩信息,必须可展开到证据 |
| 指标表 | 还有哪个指标在动? | 一行一指标;核心/必看/探索分组;冻结首列;N/基准/绝对差/相对差/CI/p/MDE | 列多,小屏不可用,需卡片降级 |
| CI 条 | 效应最小可能多少? | 0 线、95% 区间、两端数值、N;轴不截断 | 非统计用户会读成「保证范围」 |
| 显著性标记 | 真显著还是错觉? | 颜色 + 图标 + 文字(显著正向/负向/不显著/不可检验) | 颜色失效即信息失效 |
| 趋势/分布 | 何时开始变、是否极端值拉动? | 累计曲线 + 区间带;标注日级不含今天;箱线显示重叠面积 | CVR 不支持箱线;小时/分钟无箱线 |
| 维度拆解 | 对谁有效、对谁有害? | 每切片 N/CI/方向;标「探索性/未校正」;限制切片数 | 切片越多假阳性越多 |
| 人群构建器 | 这批人怎么来的、有多新? | 规则/文件、预估人数、更新频率、口径预览 | 静态群手动更新;属性取最新值 |
| 查询/空错态 | 它在跑吗?下一步做什么? | 2 秒内骨架;长任务分阶段进度/取消/保留上次结果;空态给原因 + 入口 | 异步任务可能 10 分钟–2 小时 |
| 证据抽屉 | 这个数怎么算的? | 指标定义、分母、窗口、版本、owner、查询指纹 | 信息密度高,默认折叠 |
DataTester 有一个值得警惕的细节:PV、UV、SUM、去重数这类指标不支持置信水平计算 来源。它们可以出现在表里,但必须标「不可检验」,否则用户会把「没有 CI」当成「没有差异」。
7.3 信任设计:让数字可被质疑#
- 口径卡,而不是 tooltip:指标配置里本来就有「指标描述」字段,要求写清含义、计算逻辑、用途 来源。报告页应把它升级为可引用的定义卡:分母、时间窗、归因、排除规则、版本、owner。
- 样本量拆三层:进组、曝光、有效样本。只给一个 N,SRM 无法判断。DataTester 的进组数当天实时、次日起 T-1、以 0 点为界 来源。
- SRM 与护栏:DataTester 公开报告文档没有 SRM 状态(证据缺口)。GrowthBook 在结果页直接插入 SRM 与多重曝光警告,SRM p<0.001,并写明「不应相信结果」来源。建议做成硬 gate:异常时置顶诊断、隐藏效应、只留样本与排查入口。
- 探索性标记:差异分析用 Monte Carlo 给「获胜概率」来源,敏感人群是 Uplift 挖掘 来源;这些是探索,不是确认。UI 要标「探索性、未校正、需独立复现」。
- 多重比较提示:页面显示「本页 24 指标 × 6 切片」;提供 BH/Holm 或 adjusted p。GrowthBook 的校正家族是 goals × variations × dimensions,维度切片单独校正 来源。
- 变更历史:漏斗任何修改都会更新所有使用它的实验报告,且不缓存 来源——这是典型的静默变更。建议版本化 + 「报告已重算」横幅 + 变更 diff。
- 评论与批注:公开文档未见(证据缺口)。建议锚定到指标/切片,@owner、resolve、写 decision log;评审用不可变快照,而不是实时页。
7.4 空态、加载态与错误态#
分析页的失败,大多不是「算错」,而是「用户不知道发生了什么」。三种状态要写清楚:
| 状态 | 不要这样写 | 应该这样写 | 下一步 |
|---|---|---|---|
| 空态:无数据 | 「暂无数据」 | 「该人群在所选时间窗内没有曝光;可能原因:人群圈选过窄 / 实验未开始 / 埋点延迟」 | 放宽时间窗 / 查看分流诊断 / 联系 owner |
| 空态:样本不足 | 「不显著」 | 「当前每组 1,240 人,只能检测 ≥ 8.2% 的效应;业务目标是 2%」 | 延长实验 / 扩大流量 / 降低 MDE 预期 |
| 加载:长查询 | 转圈 | 「正在扫描 3 个分区,预计 18 秒」+ 取消 + 保留上次结果 | 等待 / 取消 / 查看缓存版本 |
| 错误:查询失败 | 「系统错误」 | 「查询超时(>30s);已缩小到近 7 天,可重试或导出异步任务」 | 重试 / 缩小范围 / 异步 |
| 错误:口径变更 | 「数据已更新」 | 「指标 v4 于 10-20 变更:分母从 UV 改为 AU;本报告已重算,历史结论可能不可比」 | 查看 diff / 用旧版本重跑 |
7.5 可访问性与响应式#
- 键盘:指标表用 grid 模式,roving tabindex,方向键移动,Enter 展开,Esc 关闭 来源。DataTester 的交互是 hover 出解读、点击出统计卡 来源;hover-only 必须补 focus/click 等价物。
- 色彩不是唯一编码:DataTester 用绿/红/黑编码显著性 来源,WCAG 1.4.1 要求颜色不能是唯一手段 来源。加箭头、图标、文字,灰度打印仍可辨。
- 对比与焦点:文本 4.5:1、UI 3:1、焦点可见;触控目标至少 24×24(WCAG 2.2)。
- 表格小屏降级:≥1280 全列;768–1279 隐藏绝对差/MDE,保留相对差 + CI;<768 一行一卡(指标名、效应、CI、状态),点开底部抽屉;首列 sticky,横向滚动给阴影提示。
- 图表替代:提供「表格视图」与文字摘要;异步完成用 aria-live 播报,不要只靠 toast。
- 移动端:只保留「结论 + 核心指标 + 护栏 + 审批」;下钻与高级分析引导到桌面,而不是硬塞进小屏。
7.6 六条可用性验收标准#
- 5 秒结论:80% 目标用户不滚动即可说出「上/不上/证据不足 + 主指标方向 + 是否过护栏」。
- 三重编码:任一显著性标记在灰度与色盲模拟下仍可区分;颜色、图标、文字同时存在。
- 键盘闭环:从实验列表到展开统计卡 ≤ 6 次 Tab/方向键;无 hover-only 信息;焦点始终可见。
- 口径可追溯:任一数字 2 次点击内看到定义、分母、时间窗、版本、最后更新;口径变更后出现「已重算」提示。
- 状态可解释:查询 > 2 秒有阶段进度与取消;失败保留上次结果并给原因与重试;空态给下一步入口。
- 切片不静默:任何筛选/分组后同时显示 N 与基准 N;探索性结果带「未校正」标记;页面显示「指标数 × 切片数」。
8. 技术实现:语义层、查询与统计#
分析模块的工程难点不是「把 SQL 跑快」,而是让同一个业务问题,在实验组与对照组、今天与上周、整体与下钻之间,被编译成同一套可复现的查询。
8.1 逻辑架构:六个平面#
这六层的失败模式各不相同:元数据错会串组,指标错会口径漂移,人群错会人口漂移,维度错会把「当前属性」当成「进组时属性」,缓存错会串租户,治理缺失会让错数无法追溯。架构图的价值不是好看,而是让每一层都有明确的 owner 与可观测指标。
8.2 指标 DSL:七个槽位#
一个实验指标 DSL 至少要有七个槽位:事件、聚合算子、分母、过滤、时间窗、归因窗口、去重键。
{
"metric_id": "gmv_per_entrant_7d",
"version": 4,
"entity": "user_id",
"numerator": {
"agg": "sum",
"event": "pay_success",
"property": "amount",
"filter": [{ "property": "currency", "op": "=", "value": "CNY" }],
"dedup": { "key": "order_id" }
},
"denominator": { "type": "entrants" },
"window": { "anchor": "exposure", "length": "7d" },
"attribution": { "event_time": "server_received_at" },
"owner": "growth-data",
"certified": true,
"stat_support": ["delta_method", "bootstrap"]
}DataTester 把前三个槽位产品化成了 14 种「计算方式」来源。拆开看,14 种其实是 3 个原子(count / sum / distinct)× 4 个分母(AU、UV、PV、SUM(DAU))× 时间语义。分母才是灵魂:同样是「支付转化」,UV/AU 问的是「进组的人里有多少人付过」,PV/UV 问的是「付过的人平均付几次」,两者不能互相解释。
置信度支持矩阵是 DSL 的一部分,不是 UI 的补丁。DataTester 明确列出,总量(PV)、总人数(UV)、求和(SUM)、按属性去重四类单指标不能计算置信度;组合指标也只对特定分子/分母类型开放 来源。推断:这不是产品偷懒,而是统计引擎的真实接口——方差必须从「每个用户一个值」的样本里估计,纯总量没有用户级分布。所以编译器必须先把任何指标降成「每人一行 (num, den)」,再由统计层聚合。
8.3 查询编译:从请求到充分统计量#
一个分析请求是一个五元组:experiment × metrics × cohort × dimensions × time。编译器做七件事:
- 取实验版本与 variant 映射;
- 展开指标为
(numerator, denominator, filter, window); - 下推人群(join 快照或 bitmap);
- 解析维度(字典表或
argMax取时点值); - 生成用户级 CTE;
- 生成聚合查询;
- 交给统计层。
编译后的伪 SQL 大致如下。注意三个细节:variant 只做列不做表、分母恒为 1 且用 LEFT JOIN、结果返回二阶矩而不是一个数。
WITH ent AS (
SELECT user_id, variant, min(exposure_time) AS t0
FROM exposure
WHERE exp_id = 'exp_1024' AND exp_version = 7
AND dt BETWEEN '2026-09-01' AND '2026-09-30'
AND user_id IN (
SELECT uid FROM cohort_snapshot
WHERE cohort_id = 'c_88' AND cohort_version = 20261018
)
GROUP BY user_id, variant
),
per_user AS (
SELECT e.user_id, e.variant, d.country,
sumIf(p.amount, p.event = 'pay_success'
AND p.event_time >= e.t0
AND p.event_time < e.t0 + INTERVAL 7 DAY) AS num,
toUInt8(1) AS den
FROM ent e
LEFT JOIN events p
ON p.user_id = e.user_id
AND p.dt BETWEEN '2026-09-01' AND '2026-10-07'
LEFT JOIN dim_user d ON d.user_id = e.user_id
GROUP BY e.user_id, e.variant, d.country
)
SELECT variant, country,
sum(num) AS num_sum,
sum(den) AS den_sum,
count() AS n,
sum(num * num) AS yy,
sum(den * den) AS xx,
sum(num * den) AS xy
FROM per_user
GROUP BY variant, country;最后三列是「二阶矩」,它们让统计层不必回表就能算方差与协方差。这是语义层与统计层之间最重要的接口契约:查询结果不是「一个数」,而是一组充分统计量。
保证两组同口径,靠四条硬规则:
- variant 只做列不做表;
- 分母固定为进组人数且每人计 1;
- 归因窗口锚定各自的进组时间
t0; - 所有过滤条件同时作用于分子与分母。
DataTester 的漏斗给了正面样本:漏斗不要求单独配置曝光,但计算时会把曝光事件当作第一步之前的过滤事件,且曝光自带实验版本 VID 来源。组的定义与指标同源,避免了 assignment 表 join 的丢失与串组。
8.4 存储选型:三种负载,不可能一个引擎全吃#
| 引擎 | 最擅长的「那一刀」 | 代价与边界 | 适合 / 不适合 |
|---|---|---|---|
| ClickHouse | 单表宽表 + 预聚合;Bitmap 精确 UV | 增量物化视图只处理新写入块,历史重算要另建链路;JOIN 需宽表/小表广播 | 曝光宽表、实时护栏、私有化单链路;不适合频繁更新维表与复杂多表即席 |
| Doris | 聚合/主键模型,物化视图透明改写,固定模板并发好 | 改写依赖优化器与 MV 设计;维度组合仍被预聚合锁死 | 报表模板稳定、租户多的 SaaS;不适合长尾即席 |
| StarRocks | 主键模型 + 异步物化视图,多表 JOIN 聚合 | 内存与运维成本高;MV 刷新有延迟窗口 | 星型模型、指标多而维度相对固定 |
| BigQuery / Snowflake | 存算分离,按扫描量计费,回填/审计/共享友好 | 交互延迟与成本随扫描量上升;物化视图能力受限 | 决策口径与历史回填;不适合亚秒拖拽 |
| Druid | 摄入即 roll-up + 近似算法,亚秒看板 | 不支持按主键低延迟更新,不擅长大表 JOIN | 实时健康度与 SRM 护栏;不适合财务对账与复杂归因 |
预聚合有三件套:Bitmap 做 UV(交并差快,但高基数会膨胀,且回答不了「这些人是谁」);BSI 做金额求和与分位数(需 bucket 编码,精度换空间);物化视图做固定维度组合(查询改写依赖优化器)。一条容易犯的错:不要把比率的比值存进 cube,只存分子和分母,查询时再除;否则跨天、跨维度合并时权重就错了。
维度组合是 2^N,全预聚合必然爆炸。现实做法是「高频维度做 cube + 任意维度现算明细」。DataTester 有一条很诚实的限制:属性分组之后,不支持切换 preAA 数据、查看数据分布和箱线图 来源。推断:分组查询走的是预聚合/cube 路径,原始用户分布不在 cube 里,所以分布类视图只能关闭。这就是「预聚合换性能」的真实代价。
8.5 API 与数据模型#
一个最小可用的分析 API 可以只有六个端点:
| 方法 | 路径 | 作用 | 关键参数 |
|---|---|---|---|
| POST | /v1/analyses |
创建分析(保存画布) | experiment_id, metric_set, cohort, dimensions, window, method |
| POST | /v1/analyses/{id}/run |
执行分析 | mode=sync/async, cache=auto |
| GET | /v1/analyses/{id}/result |
取结果 | run_id, include=warnings,evidence |
| POST | /v1/analyses/{id}/drill |
下钻 | path[], filters{}, limit |
| GET | /v1/cohorts/{id} |
人群元数据/预估人数 | version |
| POST | /v1/exports |
导出(异步) | analysis_id, format, row_limit, reason |
核心表至少要有:
| 表 | 关键字段 | 作用 |
|---|---|---|
exp_assignment |
exp_id, version, uid, variant, bucket, assigned_at | 分流事实 |
exp_exposure |
exp_id, version, uid, variant, exposure_at, context | 曝光事实(归因锚点) |
metric_def |
metric_id, version, dsl_json, owner, status, certified | 指标定义 |
cohort_snapshot |
cohort_id, version, snapshot_at, uid_hash | 人群快照 |
analysis_run |
run_id, analysis_id, query_hash, data_cutoff, status | 运行记录 |
analysis_result |
run_id, cell_key, num, den, n, yy, xx, xy, warnings | 充分统计量 |
analysis_audit |
run_id, actor, action, reason, ts | 审计 |
8.6 性能、成本与可观测性#
按复杂度分四级:
- L1 已预计算的固定报表:缓存命中,亚秒;
- L2 单指标单维度:秒级,同步;
- L3 多指标多维度/长窗口:十秒到分钟,异步任务;
- L4 自定义 SQL 与导出:队列 + 配额 + 审批。
只有 L1/L2 值得优化,L3/L4 应该「排队并告知」,而不是让所有人一起拖垮集群。
缓存 key 必须包含所有影响结果的版本:hash(experiment_version, metric_version, cohort_version, dim_set, time_range, granularity, filter_hash, engine_version)。少一项就会出现「改了定义但报表没变」的幽灵。
可观测性要回答的不是「查询慢不慢」,而是「数字为什么变了」。至少四类信号:
- 查询日志:query_id、SQL 指纹、扫描行数、缓存命中、租户;
- 慢查询:按模板聚合,而不是按单条 SQL;
- 口径异常:分母为 0、UV 大于进组人数、比率大于 1、某维度值单日突增;
- 结果 diff:同 query 重跑、新旧指标版本、实时与离线对账。
建议 把编译后 SQL 的哈希作为「口径指纹」写进结果表,报表页可展示。这样任何数字都能回答「它是用哪版定义、哪版人群算的」。权限上,指标的可见性与行的可见性要分开;共享缓存和导出文件是最容易被忽略的越权泄漏点。
8.7 三个阶段:MVP、规模化、智能化#
MVP 的目标不是快,而是「每个数字都能手工复算」。此时最重要的交付物是 DSL 和一张指标契约表,而不是引擎。智能化的底线是:自然语言只能生成 DSL,不能直写 SQL——否则前面所有的版本、权限、口径指纹全部失效。
9. PRD:P0/P1/P2 与验收#
9.1 范围与不做什么#
做:一个实验分析工作台,支持结论、指标、人群、下钻、高级分析五个面;支持自定义指标、人群圈选、筛选模板、维度下钻、CUPED/序贯/多重比较;提供 API 与审计。
不做(至少第一年):不做通用 BI;不做全量 SQL 编辑器;不做自动投放;不做跨实验的因果网络;不做无审批的用户明细导出。
9.2 需求优先级#
9.3 验收标准#
- 可复现:任取一个结论,输入六个版本号,能在 1 次重跑中复现同一数字(误差在浮点范围内)。
- 可解释:任一数字 2 次点击内看到指标定义、分母、时间窗、版本、owner、数据截止。
- 可拦截:SRM 异常时,效应数字被隐藏,只保留诊断与样本;护栏恶化时,结论卡强制降级。
- 可探索:维度下钻 P95 < 2.5 秒;用户样本 P95 < 3 秒;超过 30 秒自动转异步。
- 可校正:页面显示「本次分析 N 次检验」;adjusted p 与 raw p 并列;探索性结果带标记。
- 可协作:分享链接打开是同一实验、指标、人群、维度路径、时间窗、方法;评论可 @owner。
- 可审计:谁在什么时间、用什么理由、导出了多少行、包含哪些字段,全部可查。
- 可访问:键盘可完成「进报告 → 切指标 → 展开证据 → 下钻 → 返回」;颜色不是唯一编码。
9.4 成功指标#
| 指标 | 定义 | 目标(上线 6 个月) |
|---|---|---|
| Time to insight | 从打开报告到做出决策的中位时长 | 降低 40% |
| 分析复用率 | 使用模板/保存视图/分享链接的分析占比 | > 50% |
| 查询 P95 | L2 同步查询的 95 分位 | < 2.5s |
| SRM 覆盖率 | 有 SRM 状态的核心实验占比 | 100% |
| 校正覆盖率 | 多指标/多切片分析中开启校正的占比 | > 80% |
| 决策记录完成率 | 有结论、owner、后续动作的实验占比 | > 60% |
| 口径争议数 | 因口径不一致导致的工单/争议 | 每月 < 5 |
9.5 落地节奏#
- 0–90 天:P0 契约 + 结论卡 + 指标表 + 人群构建器 + SRM/护栏;先接 1 个业务线、20 个核心指标。
- 90–180 天:下钻 + 模板 + CUPED/序贯/多重比较 + Cohort/漏斗;接 3 个业务线。
- 180–365 天:差异分析 + Uplift + 决策记录 + API;建立指标认证与 owner 制度。
- 365 天以后:组合视图、自动下钻、LLM 叙述/诊断;把「分析质量」纳入平台 KPI。
9.6 风险与缓解#
| 风险 | 表现 | 缓解 |
|---|---|---|
| 口径治理跟不上 | 同名指标多个版本,结论互相打架 | 指标认证 + owner + 版本锁定 + 口径指纹 |
| 性能拖垮采用 | 下钻 10 秒,用户回到 Excel | 分级查询 + 预聚合 + 缓存 + 异步 |
| 统计复杂度吓退业务 | 用户只看 p 值或只看颜色 | 默认结论 + 渐进披露 + 解释文案 |
| 高级分析滥用 | 子群越切越多,假阳性泛滥 | 预注册 + FDR + 探索性标记 + 复验 |
| 隐私/合规 | 用户明细导出泄露 | 脱敏 + 审批 + 行级权限 + 审计 |
| 组织不信任 | 「平台数字和数仓对不上」 | 对账任务 + 结果 diff + 公开口径 |
10. 反模式与决策清单#
10.1 十二个反模式#
| 反模式 | 症状 | 根因 | 修复 |
|---|---|---|---|
| 图表墙 | 首屏 20 张图,没人知道看哪张 | 以「功能多」代替「决策支持」 | 结论卡 + 三层指标 + 渐进披露 |
| p 值自动售货机 | 切 20 个切片,挑一个显著的 | 没有多重比较与探索性标记 | 预注册 + FDR + 降级文案 |
| 人群即切片 | 把 post-treatment 人群当因果结论 | 没有时点校验 | 两种作用位置 + 时点警告 + 复验 |
| 指标即字段 | 同名指标多个口径 | 没有注册表/版本/owner | 指标契约 + 认证 + 血缘 |
| 下钻即 group by | 200 个维度值、没有 N/CI | 把查询能力当分析能力 | TopN + 最小样本 + 每层护栏 |
| 缓存幽灵 | 改了定义,报表没变 | 缓存 key 缺版本 | 全版本 key + 主动失效 |
| 导出即拖库 | 用户明细随便下载 | 权限与审计缺失 | 脱敏 + 审批 + 限额 + 水印 |
| 实时崇拜 | 所有指标都要秒级 | 没区分摄入/指标/决策实时 | 分级:实时护栏 + T+1 决策 |
| 高级方法堆菜单 | 18 个方法,没人会用 | 以算法数量代替产品化 | 入口契约 + 默认值 + 解释 + 成本 |
| LLM 归因 | 流畅地解释「为什么涨」 | 把叙述能力当因果能力 | 数字白名单 + 拒绝条件 + 待验证措辞 |
| 静默变更 | 漏斗改了,所有实验报告变了 | 没有版本与通知 | 版本化 + 重算横幅 + diff |
| 数据湖直连 | 分析师各写各的 SQL | 没有语义层 | 注册指标 + 受控 DSL + 沙箱 SQL |
10.2 自建 vs 采购:分析模块的决策清单#
指标口径是否是我们的核心竞争力?
如果指标定义与业务强耦合、外部产品无法表达,语义层必须自建;否则优先复用。
数据能否出仓?
不能出仓就选 warehouse-native 或私有化;能出仓再考虑 SaaS 的体验与统计能力。
人群与标签是否已存在?
已有 CDP/标签平台时,分析模块应做「消费方」,不要再造一套人群服务。
是否需要自定义统计方法?
需要 CUPED/HTE/序贯等深度定制时,自建统计层;否则用产品默认值 + API。
下钻性能能否达标?
高基数、多维度、秒级,是自建最容易低估的部分;先做 POC 再承诺。
合规与审计是否硬要求?
强监管场景优先私有化/物理隔离;共享 OLAP + 缓存会放大越权风险。
10.3 问供应商的十个问题#
- 你们的指标定义是否版本化?被实验引用后还能改口径吗?
- 人群是在分流前还是分流后生效?能否分别配置?
- 子群分析是否默认做多重比较?用的什么方法?家族怎么定义?
- SRM 是自动检测还是手工配置?异常时会不会隐藏效应?
- CUPED 用哪段 pre 期?新用户怎么处理?分位数指标支持吗?
- 序贯检验支持中途查看吗?alpha spending 参数能否锁定?
- 下钻的 P95 是多少?高基数维度怎么处理?缓存 key 包含哪些版本?
- 用户明细导出有哪些权限、脱敏、审计与限额?
- 指标口径变更后,历史报告会不会重算?如何通知?
- 是否提供 API/DSL,让我把分析嵌进自己的 workflow?
10.4 一句话收束#
分析模块的终局,不是「什么都能查」,而是「查到的每个数都能被解释、被复现、被质疑,并且最终能变成一个更好的决策」。Libra/DataTester 值得学的,不是某一个图表,而是它把统计假设、数据口径、能力边界三件事同时放进了界面;代价是重、慢、学习曲线陡,收益是同一个结论能被 PM、DS、运营用同一种语言复述。
如果只能记住一句话:先建契约,再建画布;先保因果,再谈智能。
11. 参考来源#
本页优先使用官方文档、论文与工程博客;厂商营销材料只用于确认产品存在,不作为能力证据。标注「推断」「建议」的内容是我们的产品判断,不代表任何厂商的官方设计。
11.1 一手产品文档#
- BytePlus DataTester, Experimental Report Overview:链接
- BytePlus DataTester, How to Interpret the Experiment Report:链接
- BytePlus DataTester, Metrics Analysis: Event Metrics & Retention Metrics:链接
- BytePlus DataTester, Create Event Metric:链接
- BytePlus DataTester, Create Warehouse Metric:链接
- BytePlus DataTester, User Cohorts:链接
- BytePlus DataTester, User Details:链接
- BytePlus DataTester, Report Page Custom Filter Template:链接
- BytePlus DataTester, Advanced Analysis: Difference Analysis and Group Comparison:链接
- BytePlus DataTester, Advanced Analysis: Cohort Analysis:链接
- BytePlus DataTester, Metric Analysis: Funnel Metric Analysis:链接
- BytePlus DataTester, Report Interpretation: Customer Group Experiment:链接
- BytePlus DataTester, Sensitive Population Insights:链接
- BytePlus DataTester, SQL Custom Query:链接
11.2 统计、方法与工程#
Eppo, CUPED:链接
Eppo, Analysis Methods:链接
Eppo, Sample Ratio Mismatch:链接
Eppo, Multiple Testing:链接
Eppo, Certified Metrics:链接
GrowthBook, Sequential Testing:链接
GrowthBook, Multiple Corrections:链接
GrowthBook, Experiment Results:链接
Statsig, CUPED:链接
Wager & Athey, Estimation and Inference of Heterogeneous Treatment Effects using Random Forests:链接
Deng et al., Applying the Delta Method in Metric Analytics(KDD 2018):链接
Netflix, It's About Time: Practical Considerations for Measuring Long-Term Treatment Effects:链接
Instacart, Geo-based A/B Testing and Difference-in-Difference Analysis:链接
ByteDance, DQ Estimator for Two-sided Markets:链接
腾讯微信实验平台, VLDB 2024 论文:链接
Statsig, Interpreting Results / Custom Queries:链接
Statsig, Differential Impact Detection:链接
Eppo, Segments:链接
Eppo, Copy SQL:链接
Eppo, Property Analysis:链接
GrowthBook, Dimensions:链接
GrowthBook, Metrics:链接
Amplitude, Advanced Metric Use Cases:链接
Amplitude, Sequential Testing:链接
Optimizely, Experiment Results Page:链接
VWO, Campaign Report Components:链接
AB Tasty, Data Explorer:链接
Convert, Experiment Report:链接
PostHog, Experiments / CUPED:链接
11.3 中国平台公开材料#
- 字节跳动 AICon 2025 演讲者简介(Libra/DataTester):链接
- 《AI 时代实验平台演进之路》InfoQ 报道:链接
- 字节 AICon 2024《LLM 在 A/B 实验平台的应用探索》:链接
- 字节 CUPED/ITR 内部实践报道(IT168,2024-10):链接
- 淘天通天塔 Fluss 实践(阿里云开发者社区,2025-07):链接
- 美团 BETA 分析引擎(2024-09):链接
- 美团可信实验白皮书(2025-05):链接
- B 站北极星与 ClickHouse RBM:链接
- 知乎 AB2.0 从 ClickHouse 预计算迁 Doris 的公开分享:链接
11.4 交互、可访问性与设计#
- W3C, ARIA Authoring Practices: Grid Pattern:链接
- W3C, WCAG 2.2: Use of Color:链接
- W3C, WCAG 2.2: Reflow:链接
- Nielsen Norman Group, Progressive Disclosure:链接
11.5 引擎与存储#
- ClickHouse, Incremental Materialized Views:链接
- ClickHouse, Bitmap Functions:链接
- Apache Doris, Materialized View Overview:链接
- StarRocks, Asynchronous Materialized Views:链接
- BigQuery, Materialized Views:链接
- Snowflake, Materialized Views:链接
- Apache Druid, Design:链接
本页是《AB 测试平台全网竞品与方案调研》2026-10 版的独立专题,基于 8 路并行调研、20 份 DataTester 官方文档、公开论文与工程博客整理。界面演示中的数据全部虚构,仅用于说明信息架构与交互,不代表任何厂商的真实产品。厂商功能、默认参数与价格以其最新文档为准;涉及内部平台的部分已标注「推断」,不应作为采购或架构决策的唯一依据。