# AB 分析模块：自定义分析、下钻与高级分析

> 实验分析模块不是一张固定报表，而是一套受控的语义层：把人群、指标、维度、窗口和统计方法变成可组合、可复现、可审计的对象。本文横向拆解公开竞品的分析工作台，并给出一套类似 Libra AB Insight 的产品与架构设计。

<!--ANALYSIS-DEMO-->

<div class="ab-callout ab-callout--insight">
  <div class="t">三种读法</div>
  <p><strong>产品 / 设计</strong>：0 → 3 → 4 → 7，先看十个判断，再看自定义分析与人群，最后看页面解剖。<strong>数据 / 统计</strong>：4 → 5 → 6，重点看因果边界、下钻护栏与方法选择。<strong>架构 / 工程</strong>：2 → 8，重点看对象模型、查询契约与存储选型。<strong>只想汇报</strong>：0 与 10.4，两页就够。</p>
</div>

## 0. 先看结论：十个设计判断

<div class="ab-thesis">分析模块的竞争力，不在于能画多少张图，而在于<strong>同一个问题被两个人问，能得到同一个答案</strong>；以及这个答案能不能被追溯到指标版本、人群版本、数据截止时间和统计方法。</div>

<div class="ab-stat-row">
  <div class="ab-stat"><span class="n">5</span><span class="l">个分析面：总览、指标、人群、下钻、高级分析</span><span class="s">SURFACES</span></div>
  <div class="ab-stat"><span class="n">14</span><span class="l">种指标算子，覆盖 PV/UV/AU、比率、人均、去重与组合指标</span><span class="s">OPERATORS</span></div>
  <div class="ab-stat"><span class="n">3</span><span class="l">道默认护栏：SRM、必看指标、多重比较提示</span><span class="s">GUARDRAILS</span></div>
</div>

<div class="ab-principles">
  <div class="ab-principle"><h3>分析模块卖的是口径，不是图表</h3><p>图表可以被复制，口径不能。指标的分母、去重键、归因窗口、排除规则一旦漂移，所有漂亮的置信区间都失去意义。</p></div>
  <div class="ab-principle"><h3>结论先行，但证据必须同屏</h3><p>首屏给结论，同时给样本量、置信区间、方法与数据截止时间。只给「+2.4%」而不给区间的产品，会把统计问题变成文案问题。</p></div>
  <div class="ab-principle"><h3>自定义的边界是语义层</h3><p>让用户组合指标、人群、维度、窗口与方法，而不是把 SQL 输入框丢给业务。自由 SQL 可以存在，但必须走沙箱、血缘与成本配额。</p></div>
  <div class="ab-principle"><h3>人群分「进组前」与「进组后」</h3><p>进组前是分配问题，进组后是分析问题。前者改变随机化与外部有效性，后者容易引入 post-treatment bias。UI 必须在用户选错之前解释代价。</p></div>
  <div class="ab-principle"><h3>下钻是受控探索，不是无限 group by</h3><p>每下一层都要保留对照、样本量、置信区间与多重比较状态。没有这些，下钻只是把噪声切得更细。</p></div>
  <div class="ab-principle"><h3>高级方法默认严谨</h3><p>CUPED、序贯、FDR 应该默认开启并解释；Uplift、CATE 应该默认标注「探索性」。把论文菜单直接暴露给业务，是平台最昂贵的偷懒。</p></div>
  <div class="ab-principle"><h3>指标要有 owner、版本与血缘</h3><p>指标不是字段的别名。一个可用的指标定义至少包含：事件、聚合、分母、过滤、时间窗、归因、去重键、负责人、上线状态。</p></div>
  <div class="ab-principle"><h3>性能就是产品能力</h3><p>下钻超过 2 秒，用户就会退回 Excel；人群预览超过 10 秒，运营就不会用。查询延迟直接决定分析深度。</p></div>
  <div class="ab-principle"><h3>信任来自可见的失败</h3><p>SRM 异常、护栏恶化、样本不足、数据延迟、口径变更，都要在结论旁边显式出现。隐藏失败比失败本身更伤信任。</p></div>
  <div class="ab-principle"><h3>分析要沉淀为决策资产</h3><p>保存视图、评论、决策记录、复盘模板，让一次分析可被复用、被挑战、被审计。否则平台只是「一次性报表工厂」。</p></div>
</div>

<div class="ab-callout ab-callout--insight">
  <div class="t">本文的证据边界</div>
  <p>Libra 是字节跳动的内部实验平台，DataTester 是其对外商业化版本。两者同源，但<strong>不能把 DataTester 的公开文档当成 Libra 内部版的全部</strong>。本文把材料分成三类：<span class="ev ev-official">官方</span> 官方文档/论文/演讲；<span class="ev ev-infer">推断</span> 由公开材料反推；<span class="ev ev-advice">建议</span> 我们的产品设计判断。内部版的 CUPED/ITR、LLM 分析、图聚类等能力，公开材料只能证明「存在实践」，不能证明「对外产品已具备」。</p>
</div>

## 1. 拆解：Libra 的 AB Insight 做对了什么

先澄清一个命名问题：用户口中的「AB Insight」在公开材料里找不到对应的正式产品名。可查证的是 Libra（字节内部平台）与 DataTester（对外商业化版本）的 Experiment Report 与 Advanced Analysis。本文用「AB Insight」指代这套分析工作台，不指某一个具体菜单。字节在 2012 年引入 A/B 体系，2016 年产品化，2021 年通过火山引擎对外开放；官方在 AICon 2025 的口径是累计 340 万+ 次实验、同时运行 7 万+ [来源](https://aicon.infoq.cn/2025/shanghai/speaker/9508)。这套规模决定了它的分析模块不可能是一张固定报表：它必须把「看结论」拆成一组可复用的分析面，并让不同角色在同一套口径上协作。

从公开的 DataTester 文档可以还原出六个稳定的分析面。它们不是六个菜单，而是六种**决策问题**：

<div class="table-wrap">

| 分析面 | 用户真正的问题 | 公开实现要点 | 值得抄的部分 |
|---|---|---|---|
| 实验总览 | 这版能不能上？ | 核心指标、必看指标、置信区间、MDE、日级趋势、概率分布、箱线图；支持时间/维度筛选 | 结论与证据同屏；MDE 用来解释「不显著」 |
| 指标分析 | 哪个指标动了？动了多少？ | 指标组/指标视图；事件、留存、漏斗三类；相对/绝对差异、p 值、CI；指标级下钻 | 指标组按业务问题组织，不按数据表组织 |
| 人群分析 | 对谁有效？谁被伤害？ | 用户分群（规则/文件）、自定义筛选模板、差异分析与分组对比、客群实验 | 人群是分析的一等对象，不是临时 filter |
| 下钻 | 为什么动？动在哪？ | 维度拆分、时间趋势、用户明细、TopN；即席 OLAP | 每层保留对照与样本量；用户级下钻脱敏 |
| 高级分析 | 效应可信吗？对谁最大？ | 差异分析、Cohort、Uplift/敏感人群、ANOVA、Monte Carlo | 方法以「问题」命名，不以「算法」命名 |
| 诊断 | 数据是不是错了？ | SRM/分流诊断、数据延迟、指标口径、告警 | 把失败状态做成产品的一等公民 |

</div>

报告页的阅读顺序也值得抄：左侧指标导航按「关注指标组」组织，默认展开核心指标所在组；表格先给相对差异、置信区间、指标值，显著性用底色标出；只有切到单指标视图，才展开进组人数、日级趋势、概率分布与箱线图 [来源](https://docs.byteplus.com/en/docs/DataTester/Experimental-Report-Overview)。这个「组 → 单指标 → 证据图」的阶梯，把 PM、DA、运营三类读者分开了：PM 看第一屏拍板，DA 看第二屏复核，运营看筛选后的切片执行。

两个容易被忽略的细节，恰恰是设计精髓。其一，日级趋势是「截至当日已进组全部用户」的累计口径逐日切片，所以区间随时间收窄是设计使然，不是「越跑越显著」的证据；想看新进组人群的质量变化，必须用 cohort 分析。其二，概率分布是模型视角，箱线图是原始数据视角，同屏并列是为了交叉验证：如果正态曲线说「差不多」而箱线图的长尾明显不同，真正该信的是后者。代价是口径变多：日级不含今天、留存按首次进组归因、漏斗把实验曝光当作第一步之前的过滤事件 [来源](https://docs.byteplus.com/en/docs/DataTester/Metric-Analysis-Funnel-Metric-Analysis)——每一条都能让两个人在同一张图上吵起来。DataTester 的兜底方式是把限制写进 UI：不能画就不给入口（例如属性分组后禁用分布图、CVR 不提供箱线图）[来源](https://docs.byteplus.com/en/docs/DataTester/Metrics-Analysis-Event-Metrics-Retention-Metrics)。这比写在文档里有效，但也削掉了探索空间。

### 1.1 客群实验：把「人群 × 策略」做成双因素设计

DataTester 的「客群实验」是一个很值得研究的设计：它不是「先开实验，再按人群切一刀」，而是在实验配置阶段就声明两个客群（如 test / test 1），报告页同时给出三个层次的结论 [来源](https://docs.byteplus.com/en/docs/DataTester/Report-Interpretation-Customer-Group-Experiment)：

- **每个实验版本下，各客群的获胜概率**；
- **每个客群下，各实验版本的获胜概率**；
- **双因素方差分析（ANOVA）表**：客群（行因子）× 策略（列因子），输出交互效应、主效应、简单主效应，以及 SS、df、MS、F、p、F critical。

获胜概率用 Monte Carlo 近似：对每个组拟合正态分布，重复抽样 10 万次，统计「谁最大」的频率 [来源](https://docs.byteplus.com/en/docs/DataTester/Report-Interpretation-Customer-Group-Experiment)。这套设计的产品价值在于：它把「策略对不同人群是否不同」从分析师的临时探索，变成了实验发起时就可以声明的研究问题。

但它也有明确的代价：

1. **样本量按客群 × 版本切分**，交互效应的功效远低于主效应；小客群很容易「看起来有差异」。
2. **ANOVA 假设方差齐性与近似正态**，对重尾、比率型指标并不稳健；产品需要提示或提供 bootstrap。
3. **获胜概率不是 p 值**，不能按频率派显著性解释；多客群、多版本比较仍需多重比较校正。
4. **客群必须在进组前定义**，否则就是 post-treatment 分层，不能做因果解释。

<span class="ev ev-advice">建议</span> 如果我们要做类似能力，不要把「客群实验」做成一个独立的实验类型，而应把它做成**分析配置**：实验仍然只有一套随机化，客群作为「预注册的分析维度」挂在实验上；报告默认展示交互效应的功效与 FDR 校正结果。

### 1.2 敏感人群洞察：Uplift 的产品化样本

DataTester 的「敏感人群洞察」是公开文档里少见地把 Uplift 做成完整工作流的产品 [来源](https://docs.byteplus.com/en/docs/DataTester/Sensitive-Population-Insights)：

- 任务粒度是「一个指标、一个实验组、一个对照组」；
- 挖掘方向分正向/负向（找提升最大的人，或找下降最小的人）；
- 用户属性作为特征，模型输出 ITE（Individual Treatment Effect），按 ITE 分 10 个 bins；
- 报告给出 TOP 敏感人群、特征重要性、TOP 3 特征的二维交叉子群，以及子群的人数占比、绝对/相对差异、相对差异贡献、p 值；
- 支持下载人群明细（treatment、uid、ite、bins、业务 ID），用于后续定向运营。

这套产品的聪明之处，是把「因果模型」翻译成了运营能用的三个东西：**一群人、一个方向、一个可执行的名单**。但它也暴露了 Uplift 的典型风险：

- **推荐入组人数 > 2 万、维度 > 4 个**，否则模型不稳定 [来源](https://docs.byteplus.com/en/docs/DataTester/Sensitive-Population-Insights)；
- 子群是「TOP 特征交叉」选出来的，存在**选择偏倚**；报告里的 p 值没有做多重比较校正；
- ITE 是模型预测，不是个体真实因果效应；下载名单用于全量投放前，应该做 holdout 验证；
- 「负向挖掘」找到的人群，可能只是回归到均值，不等于策略真的伤害了他们。

<span class="ev ev-advice">建议</span> 产品上必须同时给「模型置信度 / 子群样本量 / 是否经过 FDR / 是否有 holdout 验证」四个状态；否则 Uplift 会变成「用机器学习包装的细分」。更稳妥的做法是把 Uplift 放在「探索」层，把验证放在一个新的 confirmatory 实验里。

### 1.3 用户分群：先 hash 再过滤，这个顺序很关键

DataTester 的用户分群支持两种创建方式：规则圈选与文件上传；规则支持「做过 / 没做过 / 依次做过 / 用户是 / 用户不是」，支持 AND/OR 与嵌套，支持日更或手动更新；分群可以作为实验的受众规则，也可以作为 Feature 的定向人群 [来源](https://docs.byteplus.com/en/docs/DataTester/User-Cohorts)。

更重要的一句话藏在文档里：分流时，非白名单用户**先做 hash 分桶，再做人群过滤** [来源](https://docs.byteplus.com/en/docs/DataTester/User-Cohorts)。这意味着：

- 人群规则影响的是「谁有资格进入分析」，而不是「谁被分到哪个组」；
- 只要人群定义与实验分配独立，按人群切子群不会破坏随机性；
- 但如果人群定义使用了实验期行为（例如「点击过新卡片的人」），它就成了 post-treatment 变量，按它切子群会产生 collider/selection bias。

<span class="ev ev-infer">推断</span> 这个顺序是字节系产品在因果设计上最值得学的一处：它把「定向」和「分析」解耦，让同一个分群既能用于投放，也能用于分析，但不会悄悄改变随机化。很多自建平台把人群过滤放在分桶之前，结果实验组和对照组的入组概率随人群变化，SRM 和结论一起失效。

### 1.4 公开材料能看到什么、看不到什么

<div class="table-wrap">

| 能力 | 公开证据 | 判断 |
|---|---|---|
| 报告总览、指标组、趋势、分布、箱线图 | DataTester 官方文档 | <span class="ev ev-official">官方</span> 对外版具备 |
| 自定义筛选模板（实验级 10 个、应用级 50 个） | 官方文档 | <span class="ev ev-official">官方</span> 可复用、可共享 |
| 差异分析 / 分组对比 / 客群实验 / ANOVA | 官方文档 | <span class="ev ev-official">官方</span> 已产品化 |
| Uplift / 敏感人群 / 人群下载 | 官方文档 | <span class="ev ev-official">官方</span> 已产品化，但统计校正有限 |
| Cohort / 漏斗 / 热图 | 官方文档 | <span class="ev ev-official">官方</span> 分析面完整 |
| CUPED / ITR | 2024 内部演讲、论文 | <span class="ev ev-infer">推断</span> 内部实践强，对外文档未提 |
| LLM 实验分析 / 归因 | 2024 AICon 演讲 | <span class="ev ev-infer">推断</span> 有内部落地，产品化程度未知 |
| 图聚类 / DQ 估计量 | 论文、演讲 | <span class="ev ev-infer">推断</span> 服务特定场景，不是通用分析模块 |

</div>

这张表最重要的不是「谁有谁没有」，而是提醒我们：**对外文档的完整度不等于内部能力的完整度，反之亦然**。做竞品分析时，必须把「产品能力」「工程能力」「统计能力」分开评估；否则很容易把一次演讲里的方法，当成采购后立刻可用的功能。

### 1.5 横向看：五种分析范式

把 Libra/DataTester 放回市场里，会发现「分析模块」并没有统一形态。公开文档与产品定位大致可以分成五种范式，每种范式的强项与盲区几乎互补：

<div class="table-wrap">

| 范式 | 代表产品 | 分析入口 | 自定义能力 | 人群/下钻 | 高级统计 | 主要盲区 |
|---|---|---|---|---|---|---|
| 报表型 | 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 有产品化 | 容易把「人群运营」当成「因果结论」 |

</div>

<span class="ev ev-infer">推断</span> 这张表是「公开文档 + 产品定位」的归纳，不是逐项功能验收。比如「仓库原生」的延迟取决于客户数仓，不能一概而论；「探索型」的实验统计也在补课。真正稳定的差异是**数据放在哪里、口径由谁定义、分析面向谁**。

三个结论：

1. **报表型强在结论，弱在探索；探索型相反。** 前者适合 PM 快速拍板，后者适合分析师找假设；把两者做成同一个页面，往往两边都不满意。
2. **仓库原生强在口径，弱在交互。** 指标留在数仓、SQL 可审计，代价是每次下钻都可能等数仓；它最适合「指标治理成熟、分析频率不高」的组织。
3. **统计工作台强在方法，弱在业务上下文。** CUPED、序贯、贝叶斯做得再细，如果用户不知道「这个指标对应哪个业务动作」，方法只会增加解释成本。

所以产品设计的第一步不是列功能，而是选主范式：我们到底要服务「拍板」「找假设」还是「治理口径」？选完之后，再用另外两种范式补短板。五种都想要，结果通常是五种都不像。

2025–2026 的所有权变化也要计入选型：Statsig 2025 年被 OpenAI 收购、2026 年由 Amplitude 接手品牌与客户；Eppo 自 2025 年起以 Eppo by Datadog 运营；VWO 与 AB Tasty 于 2026 年合并为 Wingify，但官方明确两边产品目前仍各自运行 [来源](https://statsig.com/blog/statsig-amplitude-phase-1) [来源](https://www.datadoghq.com/about/latest-news/press-releases/datadog-acquires-eppo-to-expand-its-ai/) [来源](https://vwo.com/blog/wingify-the-unified-digital-experience/)。这意味着你看到的路线图，可能已经换了一个主人；选型时要问「收购后的产品归属、数据迁移与合同主体」，而不只是功能清单。

### 1.6 中国平台的三种分工

把镜头拉远，中国大厂的分析模块大致有三种分工，各自解决不同的问题 [来源](https://tech.dewu.com/article?id=122) [来源](https://tech.meituan.com/2025/08/22/meituan-AB-Online-Controlled-Experiment-08.html) [来源](https://developer.aliyun.com/article/1672360)：

<div class="table-wrap">

| 分工 | 代表 | 分析模块的重心 | 代价 | 适合 |
|---|---|---|---|---|
| 运营工作台 | 字节 DataTester | 报告、模板、人群、Uplift、名单下载 | 统计深度让位于可用性；高级方法默认值不透明 | 业务方自助、运营驱动 |
| 统计底座 | 腾讯/美团 | CUPED、FDR、SRM、HTE、AA 验证、方法库 | 使用门槛高；需要 DS 解释 | 实验密集、决策风险高 |
| 数仓共生 | 阿里通天塔、得物 | 指标语义层、实时/离线链路、即席 OLAP | 强依赖数据团队；交互受预计算粒度限制 | 已有成熟数仓、指标治理 |

</div>

得物的三级查询是一个很务实的产品契约：ClickHouse 存预计算指标，承接大多数页面数字；StarRocks 承接复杂分析与明细聚合，秒级到分钟级；StarRocks 跑不动的查询自动降级到 ODPS，10 分钟到 1 小时；查询过程做并发限制与 Redis 缓存，避免拖垮 OLAP 集群 [来源](https://tech.dewu.com/article?id=122)。这等于把「哪些秒回、哪些要等」写进了产品，而不是让用户在一个转圈页面里猜。

<span class="ev ev-infer">推断</span> 三种分工没有高下，只有匹配：业务方自助强的组织，先学运营工作台；实验密度高、决策风险大的组织，先学统计底座；数仓成熟、指标统一的组织，先学数仓共生。最怕的是三种都想要，最后做成一个「有 Uplift 按钮、但没有指标 owner」的平台。

### 1.7 如果只能抄五件事

1. **指标组按业务问题组织**，而不是按事件表组织；默认展示核心指标组，其他折叠。
2. **筛选模板**：把「一线城市 + 版本 ≥ 14 + 新用户」这种反复使用的口径保存成模板，实验级与应用级分层复用。
3. **差异分析**：属性过滤 + 用户分群 + 多组对比，让「对谁有效」成为标准动作，而不是分析师写 SQL。
4. **人群下载**：把分析结果变成可执行的名单，但必须带 ITE、bins、treatment 与业务 ID，方便运营验证。
5. **诊断工具**：把「为什么没命中/为什么数据不对」做成可查询的日志，而不是让用户猜。

## 2. 分析对象模型：让一次分析可复现

大部分分析平台的数据模型只建模「实验」和「指标」，然后把人群、维度、时间窗、统计方法塞进查询参数。结果是：同一张报表，昨天和今天可能不是同一个问题；同一个人分享链接，另一个人打开看到的是另一套口径。

更稳的做法是把「一次分析」本身建模成对象。最小对象集是七个：

<div class="ab-model">
  <div class="ab-model-head"><span>ANALYSIS OBJECT MODEL / 最小对象集</span><span>v1.0</span></div>
  <div class="ab-model-body">
    <div class="ab-layers">
      <div class="ab-layer is-core"><span class="name">Experiment</span><span class="body"><span class="ab-node">experiment_id</span><span class="ab-node">version</span><span class="ab-node">variants</span><span class="ab-node">assignment_unit</span><span class="ab-node">exposure_rule</span><span class="ab-node">owner</span></span></div>
      <div class="ab-layer is-core"><span class="name">Analysis</span><span class="body"><span class="ab-node">analysis_id</span><span class="ab-node">question</span><span class="ab-node">metric_set</span><span class="ab-node">audience</span><span class="ab-node">dimensions</span><span class="ab-node">window</span><span class="ab-node">method</span></span></div>
      <div class="ab-layer"><span class="name">Metric</span><span class="body"><span class="ab-node">metric_id</span><span class="ab-node">version</span><span class="ab-node">numerator</span><span class="ab-node">denominator</span><span class="ab-node">filter</span><span class="ab-node">window</span><span class="ab-node">dedup_key</span><span class="ab-node">owner</span></span></div>
      <div class="ab-layer"><span class="name">Audience</span><span class="body"><span class="ab-node">cohort_id</span><span class="ab-node">version</span><span class="ab-node">rule_tree</span><span class="ab-node">snapshot_time</span><span class="ab-node">refresh</span><span class="ab-node">estimated_reach</span></span></div>
      <div class="ab-layer"><span class="name">Dimension</span><span class="body"><span class="ab-node">dimension_id</span><span class="ab-node">hierarchy</span><span class="ab-node">value_dict</span><span class="ab-node">time_semantics</span><span class="ab-node">cardinality</span></span></div>
      <div class="ab-layer"><span class="name">Method</span><span class="body"><span class="ab-node">estimator</span><span class="ab-node">ci</span><span class="ab-node">multiplicity</span><span class="ab-node">cuped</span><span class="ab-node">sequential</span><span class="ab-node">min_sample</span></span></div>
      <div class="ab-layer"><span class="name">Result</span><span class="body"><span class="ab-node">run_id</span><span class="ab-node">query_fingerprint</span><span class="ab-node">data_cutoff</span><span class="ab-node">warnings</span><span class="ab-node">snapshot</span></span></div>
    </div>
  </div>
</div>

这七个对象里，最容易被漏掉的是 **Method** 和 **Result**。没有 Method，用户无法知道这个区间是固定样本还是序贯、是原始方差还是 CUPED、有没有做 FDR；没有 Result，用户无法复现「上周五看到的那张图」，也无法在指标定义变更后判断结论是否还成立。

<div class="ab-callout ab-callout--technical">
  <div class="t">一个可执行的契约</div>
  <p>任何分析请求都必须携带六个版本号：<code>experiment_version</code>、<code>metric_version</code>、<code>cohort_version</code>、<code>dimension_snapshot</code>、<code>method_version</code>、<code>data_cutoff</code>。少一个，结果就不可复现；多一个，存储成本可控。把六个版本号拼成的哈希写进结果表，就是「口径指纹」。报表页可以把它折叠在「证据」里，但当两个数字打架时，它是唯一能仲裁的东西。</p>
</div>

### 2.1 信息架构：五个分析面，一条证据链

分析页不是五个并列的 tab，而是一条从「要不要信」到「为什么」的链：

<div class="ab-flow">
  <div class="ab-flow-step"><div class="k">01 / VERDICT</div><div class="v">结论</div><div class="d">能不能上？证据够不够？</div></div>
  <div class="ab-flow-step"><div class="k">02 / METRICS</div><div class="v">指标</div><div class="d">哪个动了？动了多少？</div></div>
  <div class="ab-flow-step"><div class="k">03 / AUDIENCE</div><div class="v">人群</div><div class="d">对谁有效？谁被伤害？</div></div>
  <div class="ab-flow-step"><div class="k">04 / DRILL</div><div class="v">下钻</div><div class="d">动在哪？为什么？</div></div>
  <div class="ab-flow-step"><div class="k">05 / METHOD</div><div class="v">高级分析</div><div class="d">可信吗？能不能行动？</div></div>
</div>

这条链的顺序不能反。先看人群再看指标，会把「找人群」变成「找显著」；先看高级分析再看总览，会把方法当成结论。产品上可以用 tab 呈现，但默认落地页必须是结论，且每个 tab 的顶部保留「当前实验 / 当前指标 / 当前人群 / 数据截止」的上下文条。

### 2.2 分析画布：六个槽位，三种保存

把「自定义分析」做成一个画布，而不是一堆筛选器。画布只有六个槽位：

<div class="ab-specs">
  <div class="ab-spec"><div class="k">SLOT 01</div><h3>对象</h3><p>哪个实验、哪个版本、哪个对比组。对象决定随机化单元与曝光口径，后续所有计算都继承它。</p></div>
  <div class="ab-spec"><div class="k">SLOT 02</div><h3>指标</h3><p>一个核心指标 + 一组必看指标 + 若干探索指标。指标来自注册表，不能现场拼字段。</p></div>
  <div class="ab-spec"><div class="k">SLOT 03</div><h3>人群</h3><p>全体、预定义分群、规则圈选或导入名单。必须显示人群版本、快照时间与预估人数。</p></div>
  <div class="ab-spec"><div class="k">SLOT 04</div><h3>维度</h3><p>用于拆分或过滤的属性。维度有层级、有时间语义（进组时 / 当前），不能混用。</p></div>
  <div class="ab-spec"><div class="k">SLOT 05</div><h3>窗口</h3><p>事件时间、进组时间、观察窗、归因窗。四个轴必须分别显示，不能只写「近 7 天」。</p></div>
  <div class="ab-spec"><div class="k">SLOT 06</div><h3>方法</h3><p>估计量、区间、CUPED、序贯、多重比较、最小样本。默认值即产品观点。</p></div>
</div>

同一个画布可以保存成三种资产：

1. **视图（View）**：个人或团队的默认布局与筛选，轻量、可改。
2. **模板（Template）**：跨实验复用的口径组合，例如「一线城市 + 版本 ≥ 14 + 新用户」。DataTester 的自定义筛选模板就是这一层，实验级最多 10 个、应用级最多 50 个 [来源](https://docs.byteplus.com/en/docs/DataTester/Report-Page-Custom-Filter-Template)。
3. **决策记录（Decision Record）**：不可变快照 + 结论 + owner + 评论 + 后续动作。它不属于「视图」，而属于组织资产。

三者混在一起，是分析平台最常见的信息架构错误：用户以为自己在保存视图，其实在修改团队口径；或者以为自己在分享结论，其实分享的是一个会随数据更新的链接。

## 3. 自定义分析：从「选指标」到「定义分析」

「自定义分析」通常被理解成「让用户自己选指标和筛选条件」。这只是一层。完整的能力应该分四级，每级对应不同的治理成本：

<div class="table-wrap">

| 层级 | 用户可以自定义什么 | 典型交互 | 治理要求 | 适合谁 |
|---|---|---|---|---|
| L1 过滤 | 时间、维度值、对比组 | 筛选 chips | 口径不变，只变切片 | 所有业务用户 |
| L2 人群 | 规则圈选、导入名单、分群复用 | 人群构建器 | 版本、快照、权限、样本量 | 运营、PM |
| L3 指标 | 事件、算子、分母、过滤、组合公式 | 指标构建器 | owner、版本、血缘、置信度支持 | 数据/分析团队 |
| L4 分析 | 维度组合、窗口、估计量、多重比较 | 分析画布 / DSL | 方法白名单、成本配额、审计 | DS、数据工程 |

</div>

多数平台只做到 L1-L2，然后把 L3-L4 留给 SQL。这看起来灵活，实际上把治理成本转嫁给了分析师：口径散落在 notebook 里，结论无法复现，指标无法跨实验复用。更好的做法是：**L3 用注册表 + 构建器，L4 用受控 DSL，SQL 只作为逃生舱**。

### 3.1 指标构建器：14 种算子，三个原子

DataTester 的事件指标把「计算方式」产品化成了 14 种算子 [来源](https://docs.byteplus.com/en/docs/DataTester/Create-Event-Metric)。拆开看，它们其实是三个原子（count / sum / distinct）和四个分母（进组人数 AU、触发人数 UV、次数 PV、活跃天数 SUM(DAU)）的组合：

<div class="table-wrap">

| 算子 | 公式 | 回答的问题 | 是否支持置信度 |
|---|---|---|---|
| 人均次数 | 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 | 首单金额、首充金额 | 视实现 |

</div>

「是否支持置信度」这一列比算子本身更重要。DataTester 明确说，PV、UV、SUM、按属性去重四类单指标不能计算置信水平；组合指标也只对特定分子/分母类型开放 [来源](https://docs.byteplus.com/en/docs/DataTester/Create-Event-Metric)。这不是产品缺陷，而是统计引擎的真实边界：**方差必须从「每个用户一个值」的样本里估计，纯总量没有用户级分布**。

<span class="ev ev-advice">建议</span> 产品上不要把这些指标藏起来，而要显式标成「不可检验」。用户看到「总量 12.4 万，不可检验」比看到「总量 12.4 万，p=—」更不容易误读。更进一步，报告里应默认把「可检验指标」和「仅描述指标」分成两组，避免用户把不可检验的总量当成结论。

组合指标（CTR、CVR、PV/SUM）支持括号与四则运算，但同样有白名单 [来源](https://docs.byteplus.com/en/docs/DataTester/Create-Event-Metric)。比率指标最容易出错的地方是方差：设每人贡献 `(y_i, x_i)`，比率 `r = ȳ / x̄`，Delta Method 的一阶近似是：

```text
Var(r) ≈ (1 / (n · x̄²)) · [ Var(y) − 2r · Cov(y, x) + r² · Var(x) ]
```

分子分母相关时丢掉协方差项，会系统性低估方差；如果随机化单元是用户、分母是 session，必须先在用户级把分子分母各自求和，再套公式；如果是 cluster 随机化，要先在 cluster 级聚合。这些不是实现细节，而是「为什么两个平台对同一个指标给出不同 p 值」的常见原因。

### 3.2 指标治理：被引用之后不能改口径

DataTester 的规则很硬：指标一旦被实验关注，只能改名称和描述，不能改口径，也不能删除 [来源](https://docs.byteplus.com/en/docs/DataTester/Create-Event-Metric)。这是一个正确的默认值：指标是实验结论的「法律条文」，不能在判决之后改法条。

但仅有「不能改」不够。一个完整的指标治理至少要有：

- **owner**：谁对口径负责，出问题找谁；
- **版本**：每次变更生成新版本，旧实验继续引用旧版本；
- **血缘**：这个指标依赖哪些事件、属性、维表、上游指标；
- **认证**：哪些指标经过数据质量与统计校验，可以用于决策；
- **下线状态**：原表下线、事件废弃时，指标要自动标灰并通知引用方；
- **迁移工具**：新建指标后，如何把历史实验的引用迁过去，而不是让用户手工重跑。

Eppo 把「认证」与「可计算」分开：认证指标只读，且 funnel 类型不可认证 [来源](https://docs.geteppo.com/data-management/certified-metrics/)。这个设计值得借鉴：认证不是「算得对」，而是「可以被用于决策」。两者之间隔着数据质量、口径评审与 owner 签字。

### 3.3 筛选模板：口径复用的最小单位

DataTester 的自定义筛选模板支持把一组筛选条件保存下来，在实验内或应用内复用；实验级最多 10 个、应用级最多 50 个 [来源](https://docs.byteplus.com/en/docs/DataTester/Report-Page-Custom-Filter-Template)。这个功能看起来小，但它解决的是分析平台最普遍的问题：**同一个人每次看报表都要重新点一遍相同的筛选；不同的人对「高价值用户」有不同定义**。

模板的产品设计要注意三点：

1. **模板必须带 owner、描述、创建时间与使用次数**。没有 owner 的模板，半年后就是「祖传口径」。
2. **模板只保存筛选条件，不保存结论**。结论应该进决策记录，而不是模板。
3. **模板要有作用域**：个人 → 实验 → 应用 → 组织。作用域越大，审批越重。DataTester 用「实验级 / 应用级」两级，是一个务实的起点。

### 3.4 自由 SQL：要有，但不能是主入口

DataTester 提供 SQL 自定义查询，范围限定在近一年，前端展示 1000 行、下载上限 100 万行 [来源](https://docs.byteplus.com/en/docs/DataTester/SQL-Custom-Query)。这些限制不是产品小气，而是把「扫描分区数、返回行数、内存、超时」四个维度写成了可执行的闸门。

自由 SQL 的正确位置是「逃生舱」，不是「主入口」：

- **必须走沙箱**：只读、限库、限表、限分区、限并发；
- **必须写回分析对象**：SQL 查询的结果要能保存成受控指标或一次性分析，而不是散落在聊天窗口；
- **必须显示成本**：扫描量、预计耗时、结果行数，在提交前给用户看；
- **必须审计**：谁查了哪些用户明细、导出了多少行、是否包含敏感字段。

<span class="ev ev-advice">建议</span> 把「自定义 SQL」放在高级分析的最后，而不是指标页的第一个按钮。默认路径应该是「选注册指标 → 选人群 → 选维度 → 看结果」，只有当用户明确需要新指标时才进入 SQL。

### 3.5 过滤器挂在哪一层，决定结论是不是同一个问题

竞品拆解里最有价值的一条，不是「谁支持自定义指标」，而是**过滤器挂在哪一层**。同一个「只看 iOS」的筛选，挂错层会得到三个不同的数 [来源](https://amplitude.com/docs/en/feature-experiment/advanced-techniques/advanced-metric-use-cases) [来源](https://docs.growthbook.io/app/metrics)：

<div class="table-wrap">

| 挂载层 | 改了什么 | 随机化还在吗 | 典型入口 | 风险 |
|---|---|---|---|---|
| 分配层 / 人群层 | 改分母：谁进入比较 | 在（只要用进组前变量） | 实验受众、Segment、Variants Performed By | 人群太小、覆盖率下降 |
| 指标事件层 | 只改分子：哪些事件算指标 | 在，但分子分母不是同一批人 | 指标事件的 Where / 属性过滤 | 比率指标分母不变，口径错位 |
| 指标定义层 | 改语义：指标怎么定义 | 取决于定义 | 指标构建器、metric slice | 口径漂移，历史不可比 |
| 分析切片层 | 改分组/下钻 | 在，但比较次数膨胀 | 维度拆解、子群分析 | 多重比较、选择偏倚 |

</div>

Amplitude 的文档明确警告：给指标事件加国家过滤，分母仍然是全部曝光用户；正确做法是把过滤放到「Variants Performed By」 [来源](https://amplitude.com/docs/en/feature-experiment/advanced-techniques/advanced-metric-use-cases)。GrowthBook 则把「用户属性」叫 dimension、「指标属性」叫 slice，并举例：同一用户跨国消费，dimension 会把全部消费算给首次国家，slice 只算该国部分 [来源](https://docs.growthbook.io/app/metrics)。两者都在说同一件事：**「筛选」不是一个动作，而是四个不同的语义**。

这也解释了为什么 Eppo 明确不对 segment 与 ad-hoc filter 计算 CUPED [来源](https://docs.geteppo.com/experiment-analysis/deep-dive/segments/)：CUPED 的协变量与比较次数会随切片变化，平台宁愿不算，也不愿给一个看起来精确的错数。产品上应该把「这个筛选是否改变分母 / 是否参与校正 / 是否影响 CUPED」做成实时提示，而不是写在帮助文档里。

## 4. 圈定人群：最难的不是「圈」，而是「圈完之后」

「圈定指定人群，看这批人的实验指标」听起来是一个筛选功能。实际上它同时踩在三个系统的交界处：**标签/画像系统**（这批人是谁）、**分流系统**（他们怎么进组）、**统计引擎**（这批人的差异是不是真的）。任何一处口径不一致，结论都会失真。

### 4.1 人群的五种来源

<div class="table-wrap">

| 来源 | 怎么定义 | 更新方式 | ID 口径 | 最适合 | 主要风险 |
|---|---|---|---|---|---|
| 规则圈选 | 事件做过/没做过/依次做过 + 用户属性 + 时间窗 | 日更或手动 | 平台 uid / device_id | 运营定向、子群分析 | 规则随时间漂移；事件回补导致人群变化 |
| 文件上传 | CSV 名单（uid、ssid、device_id） | 静态快照 | 上传文件指定 | 大客户名单、线下人群、holdout | ID 映射丢失；名单过期；隐私合规 |
| 标签/画像 | 标签平台或 CDP 的预计算标签 | 标签平台调度 | 标签平台 uid | 高价值、生命周期、兴趣偏好 | 标签定义不可见；更新延迟；跨平台 ID 不一致 |
| 行为序列 | 按事件顺序/次数/天数定义 | 日更 | 平台 uid | 流失预警、路径人群 | 序列窗口与实验期重叠导致后处理 |
| 实验命中人群 | 某实验某版本的进组用户 | 实时/日更 | 实验 uid | 父子实验、组合策略、holdout | 父实验变更导致基准人群变化 |

</div>

DataTester 的用户分群支持规则圈选与文件上传，规则覆盖「做过 / 没做过 / 依次做过 / 用户是 / 用户不是」，支持 AND/OR 与嵌套；日更在每天 6 点计算前一天数据、8 点前完成，纯静态时间窗只能手动更新；单条规则的时间窗最长 365 天 [来源](https://docs.byteplus.com/en/docs/DataTester/User-Cohorts)。这些限制看起来是工程细节，实际上决定了人群能不能用于长周期实验。

### 4.2 规则模型：一棵树，而不是一行 SQL

一个可维护的人群规则应该是一棵树：

```json
{
  "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 上 [来源](https://www.bilibili.com/read/cv21106590/)。好处是人群圈选、标签、行为分析共用一套编码与属性字典；代价是实验平台对上游依赖很重，字典服务或 ClickHouse 抖动会同时影响配置与人群包。腾讯微信的 BSI（Bit-Sliced Index）则把曝光、指标、维度统一编码成「分析单元 ID + 值」，让同一用户在所有 BSI 中位置一致，天然完成 Join [来源](https://arxiv.org/abs/2405.08411)。两种路线都说明：**人群不是一张名单，而是一种可复用的集合编码**。

### 4.3 关键设计：先 hash 再过滤

DataTester 文档里有一句非常关键的话：分流时，非白名单用户**先做 hash 分桶，再做人群过滤** [来源](https://docs.byteplus.com/en/docs/DataTester/User-Cohorts)。更准确地说，是「层桶判定 → 人群过滤 → 实验桶/版本命中」：人群夹在层与实验之间，既不影响层内随机化，也不影响版本分配 [来源](https://docs.byteplus.com/en/docs/DataTester/Basic-Concept)。这意味着人群规则影响的是「谁有资格进入实验」，而不是「谁被分到哪个组」。

这个顺序带来四个后果：

1. **处理分配仍然随机**（在人群条件可测且实验前固定的前提下），人群内比较有效。
2. **报告里的「进组人数」是过滤后的人数**，不是桶内人数；圈了 10 万、报告只有 3 万是正常的，流量被浪费在人群外。
3. **日更人群会让同一用户在实验期间进出人群**；「进组不出组」要求一旦进组就保持版本，但用户被人群规则踢出后是否还算进组，公开文档没写，属于未知。
4. **如果人群规则用了实验后的行为**（例如「近 7 天未购买」），人群本身就被处理影响了，这是后处理偏倚，随机化救不了。

<span class="ev ev-advice">建议</span> 产品上必须把「人群作用位置」做成一个显式选择，而不是藏在高级设置里：

<div class="ab-model">
  <div class="ab-model-head"><span>AUDIENCE MODE / 两种作用位置</span><span>必须在创建时锁定</span></div>
  <div class="ab-model-body">
    <div class="ab-layers">
      <div class="ab-layer is-core"><span class="name">实验人群 / 分流前</span><span class="body"><span class="ab-node">改变谁进入实验</span><span class="ab-node">影响 SRM 与外部有效性</span><span class="ab-node">创建后不可改</span><span class="ab-node">适合定向实验</span></span></div>
      <div class="ab-layer"><span class="name">分析人群 / 分流后</span><span class="body"><span class="ab-node">不改变随机化</span><span class="ab-node">只改变统计对象</span><span class="ab-node">必须标探索性</span><span class="ab-node">适合子群分析</span></span></div>
    </div>
  </div>
</div>

很多自建平台把这两个概念混成一个「人群」字段，结果运营想定向、分析师想分层，用的是同一个入口。正确的做法是：**实验人群在创建实验时锁定，分析人群在报告页随时可换，但换了之后必须重新做样本量与多重比较检查**。

### 4.4 四个象限：什么时候人群分析是可信的

把「人群定义时点」和「是否随机化」交叉，可以得到四个象限：

<div class="table-wrap">

| | 进组前定义（pre-treatment） | 进组后定义（post-treatment） |
|---|---|---|
| **随机化分配** | ✅ 确证性子群：可以做交互检验、分层报告 | ⚠️ 选择偏倚：只能做探索，不能做因果结论 |
| **非随机化 / 观察性** | ⚠️ 观察性比较：需要倾向得分、DiD、敏感性分析 | ❌ 基本不可解释：处理与选择同时作用 |

</div>

如果人群变量 B 在「处理 T → 结果 Y」的路径上（T→B→Y），条件化 B 估到的是直接效应，不是总效应；如果 B 同时受 T 和 Y 影响（T→B←Y），条件化 B 会打开一条非因果路径，这就是 collider/selection bias。此时即使 T 原本随机，B=1 的子群里也不再有交换性。最危险的是右下角，但业务上最常见的是右上角。比如：

- 「圈出实验期点击过新卡片的用户，看他们的 7 日留存」——点击是处理的下游，点击组和未点击组的差异混合了处理效应与自选择。
- 「圈出实验期停留超过 60 秒的用户，看转化率」——停留受处理影响，且与转化互为因果。
- 「圈出完成下单的用户，看客单价」——这是条件于结果（collider），不是实验结论。
- 「圈出近 7 天未活跃的用户，看召回效果」——如果实验本身影响活跃，人群被处理污染。

<span class="ev ev-advice">建议</span> 产品上给人群规则加一个「时点校验」：凡是规则中引用的事件/属性时间窗与实验期重叠，就弹出提示「该人群可能受实验影响，结果将标记为探索性」。这不是阻止用户，而是让用户知道自己在做什么。

### 4.5 多重比较：20 次切片，64% 至少一个假阳性

这是最需要产品化、却最常被忽略的一层。按独立检验粗算：

- 5 个指标 × 4 个人群 = 20 次检验，至少一次 `p<0.05` 的概率约 **64%**；
- 10 个指标 × 10 个人群 = 100 次检验，概率约 **99.4%**；
- 如果再叠加 5 个变体，检验次数轻松上百。

还有一个常被忽略的陷阱：**一个子群显著、另一个不显著，不能推出「两个子群的效应有差异」**。正确做法是预注册少量子群，看处理 × 子群的交互项，而不是在每个子群里各跑一次检验 [来源](https://doi.org/10.1198/000313006X152649)。这不是平台算错，而是「看得越多，越容易看到显著」。更麻烦的是事后定义：先看结果，再圈一个「高价值、低活跃、近 30 天没下单」的人群，等于把选择藏进了分析；校正只能覆盖登记过的检验，覆盖不了用户脑子里那条还没说出口的假设。

产品化的正确顺序是：

1. **预注册**：创建实验时声明主指标、预期方向、目标 MDE、分析窗口、预定义子群；任何修改生成新版本并标 `post-hoc`。
2. **家族定义**：主指标拿较宽的 α，次要指标用 BH 控 FDR，护栏用 Holm 控 FWER，子群先做交互检验而不是逐格检验。
3. **默认校正**：页面同时显示 raw p 与 adjusted p，默认按 adjusted 排序；当 adjusted 跨 0 而 raw 显著时，文案必须写「校正后不显著」，不能写「有趋势」。
4. **探索降级**：没有预注册的子群，结论只能写成「下一轮实验的假设」，不能写成「对某人群有效」。
5. **复验**：确证要靠新的实验——把人群放进分流，让「人群」成为随机化因子，而不是事后切片。

<span class="ev ev-infer">推断</span> DataTester 的差异分析与敏感人群文档没有说明多重比较校正口径。不能据此断言产品没有校正，但产品设计必须假设用户不会自己校正。GrowthBook 的做法可以作为参考：校正家族是 goals × variations × dimensions，维度切片单独校正 [来源](https://docs.growthbook.io/statistics/multiple-corrections)；它的结果页还会直接插入 SRM 与多重曝光警告 [来源](https://docs.growthbook.io/app/experiment-results)。

### 4.6 样本量：子群越小，结论越贵

子群分析的第一道门槛不是显著性，而是**样本量是否撑得起你想要的 MDE**。一个粗略的直觉：

```text
n per arm ≈ 16 · σ² / Δ²        （均值指标，α=0.05，power=80%）
n per arm ≈ 16 · p(1−p) / Δ²    （比例指标）
```

当子群只有几千人时，能检测到的效应往往比业务关心的阈值大一个数量级；此时「不显著」几乎不提供信息，「显著」则更容易是噪声。DataTester 的敏感人群文档建议进组人数大于 2 万、分析维度大于 4 个，并明确说样本不足时模型会不稳定 [来源](https://docs.byteplus.com/en/docs/DataTester/Sensitive-Population-Insights)。这不是保守，而是经验阈值。

一条可落地的红线（建议，不是平台规则）：每组 <100 人不读效应，只查埋点/bug；100–500 人只报方向与 CI；500–1,000 人可做探索性检验，必须标「未校正」；≥1,000 人且每格 ≥5 个事件，才做正式检验，并仍需 SRM + 多重比较。Uplift/敏感人群按官方建议 >2 万人、>4 维 [来源](https://docs.byteplus.com/en/docs/DataTester/Sensitive-Population-Insights)。

产品上应该给每个子群自动算三件事：

- **当前样本量 / 目标样本量**；
- **当前可检测的 MDE**；
- **置信区间宽度**。

如果 MDE 大于业务目标提升，页面应该直接写「证据不足」，而不是「不显著」。这两句话对决策的含义完全不同：前者是「再等等/再扩样本」，后者是「大概率没效果」。

### 4.7 人群分析的八条准入检查

<div class="ab-principles">
  <div class="ab-principle"><h3>时点</h3><p>人群规则的时间窗是否完全落在实验开始之前？如果与实验期重叠，是否已标记为 post-treatment？</p></div>
  <div class="ab-principle"><h3>随机化</h3><p>人群是在分流前还是分流后生效？分流后过滤是否保持了处理分配的随机性？</p></div>
  <div class="ab-principle"><h3>版本</h3><p>人群是否有版本号与快照时间？报告是否显示「这批人是什么时候算的」？</p></div>
  <div class="ab-principle"><h3>样本</h3><p>每个子群的样本量、MDE、CI 宽度是否足够？是否低于产品规定的最小样本？</p></div>
  <div class="ab-principle"><h3>多重比较</h3><p>本次分析一共做了多少次检验？家族如何定义？adjusted p 是多少？</p></div>
  <div class="ab-principle"><h3>SRM</h3><p>子群内的实际分配比例是否与设计一致？分维度 SRM 是否通过？</p></div>
  <div class="ab-principle"><h3>外部有效性</h3><p>子群效应能否外推到全量？是否存在 SUTVA/溢出/组成变化？</p></div>
  <div class="ab-principle"><h3>行动</h3><p>结论是「可以定向投放」还是「需要新实验复验」？是否已经写进决策记录？</p></div>
</div>

### 4.8 数据模型与隐私

人群服务的核心表至少要有：

<div class="table-wrap">

| 表 | 关键字段 | 作用 |
|---|---|---|
| `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 下钻的五个层级

<div class="table-wrap">

| 层级 | 用户的问题 | 典型交互 | 查询形态 | 必须保留的护栏 |
|---|---|---|---|---|
| L1 指标 | 哪个指标动了？ | 指标表、指标卡 | 多指标聚合 | 指标版本、样本量、CI |
| L2 维度 | 动在哪个渠道/城市/机型？ | 维度切换、排序、TopN | `GROUP BY dimension` | 每切片 N、CI、多重比较状态 |
| L3 维度值 | 这个渠道里，哪个城市在动？ | 点击柱状图、面包屑 | 带 filter 的 `GROUP BY` | 上一层人数、当前层人数、占比 |
| L4 人群 | 是某一类人吗？ | 人群叠加、交集、对比 | cohort join + group by | 人群时点、版本、重叠 |
| L5 用户/事件 | 具体是谁？发生了什么？ | 用户列表、行为流、事件详情 | 明细查询 | 脱敏、采样、权限、审计 |

</div>

DataTester 的用户详情页提供了 L5 的样本：可以按 UUID/SSID 查用户，查看基础信息、设备、画像、按时间排序的行为流，支持按 App/设备/事件/属性过滤、重要事件高亮、CSV 下载（最长 30 天）[来源](https://docs.byteplus.com/en/docs/DataTester/User-Details)。这是一个正确的方向：**从聚合到个体，但个体视图是「诊断工具」，不是「结论工具」**。用户列表不能用来证明效应，只能用来解释异常、复现问题、构造假设。

### 5.2 交互规范：下钻不是跳页

一个可用的下钻交互，至少要满足八条：

1. **面包屑可回退**：`全部用户 / 渠道=应用商店 / 城市=一线`，每一级可点击，可清除。
2. **对照锁定**：无论下钻到哪一层，A/B 对照关系不变；不能出现「这一层只剩实验组」。
3. **样本量常驻**：每一层显示当前切片 N、基准 N、占比；N 低于阈值时灰显或折叠。
4. **统计状态常驻**：CI、p、校正状态、是否探索性，跟着切片走，而不是只在顶层显示。
5. **URL 可分享**：当前实验、指标、人群、维度路径、时间窗、方法全部编码进 URL；分享给同事打开是同一个问题。
6. **返回不丢上下文**：从用户列表返回，仍停留在原来的切片，而不是回到顶层。
7. **跨图联动可控**：点击趋势图某一天、分布图某个区间，应该变成「时间/数值过滤」，而不是悄悄换指标。
8. **「解释这个数」入口**：每个数字旁边有口径、样本、查询耗时、数据截止时间，而不是只有 tooltip。

<span class="ev ev-advice">建议</span> 把下钻做成「行内展开 + 右侧抽屉」的组合：维度拆解在指标行下方展开，用户明细在右侧抽屉打开。这样既保留上下文，又不需要在页面之间来回跳。

### 5.3 维度层级与高基数

维度不是一堆字符串，而是有层级、有语义的对象：

- **地理**：国家 → 省 → 城市 → 区县；
- **渠道**：一级渠道 → 二级渠道 → 投放计划；
- **版本**：App 大版本 → 小版本 → 构建号；
- **用户**：新/老 → 活跃分层 → 生命周期阶段；
- **设备**：平台 → 机型 → 屏幕尺寸。

产品上要区分两种下钻：

- **层级下钻（hierarchical）**：沿预定义层级逐级展开，适合地理、渠道、版本；每级自动带上父级过滤。
- **任意拆分（ad hoc）**：用户任选维度组合，适合探索；必须限制维度数量与组合爆炸。

高基数维度是下钻的性能杀手。一个机型维度可能有 10 万值，一个 URL 维度可能上百万。可行的策略是：

- **TopN + 其他**：默认展示 Top 20，其余聚合为「其他」，并明确标注；
- **搜索 + 选择**：不默认全量渲染，用户搜索后再查；
- **最小样本阈值**：低于阈值（如 100 人/组）的值折叠或灰显；
- **预聚合**：高频维度做 cube，低频维度走明细；
- **近似**：UV 可用 HyperLogLog/Bitmap 近似，但要在 UI 标注「近似值」。

DataTester 有一条很诚实的限制：属性分组之后，不支持切换 preAA 数据、查看数据分布和箱线图 [来源](https://docs.byteplus.com/en/docs/DataTester/Metrics-Analysis-Event-Metrics-Retention-Metrics)。这大概率是因为分组查询走预聚合/cube 路径，原始用户分布不在 cube 里。**这就是「预聚合换性能」的真实代价**：产品文档比架构图更诚实。与其假装什么都能下钻，不如在 UI 上明确「这个视图在当前粒度不可用」，并给一个替代入口。

### 5.4 用户级下钻：能看到人，但不能带走人

从聚合到用户，是分析模块最敏感的一步。产品上要默认「三不」：

- **不默认展示全量**：先给样本（如 100 条），需要更多再申请；
- **不默认展示原始 ID**：脱敏为 `u_8f3a•••`，需要原始 ID 走审批；
- **不默认允许导出**：导出是独立权限，带水印、限额、审计。

DataTester 的报告支持下载进组用户 ID（上限 500 万）[来源](https://docs.byteplus.com/en/docs/DataTester/Experimental-Report-Overview)，用户详情支持行为流 CSV 下载（最长 30 天）[来源](https://docs.byteplus.com/en/docs/DataTester/User-Details)。这些能力对分析很重要，但必须与权限、审计、脱敏一起设计。否则「下钻」会变成「拖库」。

### 5.5 查询实现：预聚合、即席与混合

下钻的性能取决于三个选择：

<div class="table-wrap">

| 方案 | 怎么工作 | 优点 | 缺点 | 适合 |
|---|---|---|---|---|
| 全预聚合 | 提前算好所有维度组合的 cube | 亚秒级、稳定 | 维度组合爆炸、无法回答临时问题 | 固定报表、核心指标 |
| 全即席 | 每次查询扫明细/宽表 | 灵活、口径统一 | 慢、贵、并发差 | 探索、长尾维度 |
| 混合 | 高频 cube + 低频即席 + 结果缓存 | 平衡 | 实现复杂、口径需对齐 | 大多数生产平台 |

</div>

一个务实的做法是「三级查询」：

1. **L1 缓存/预计算**：固定报表、核心指标、常用切片，命中直接返回；
2. **L2 同步即席**：单指标 + 单维度 + 有限时间窗，走 ClickHouse/Doris，目标 P95 < 2 秒；
3. **L3 异步任务**：多指标 × 多维度 × 长窗口、用户明细导出，进队列，给进度与取消。

腾讯微信的公开论文给了一个极端的工程样本：Spark 例行预计算 + ClickHouse 即席下钻，BSI 运算经 JNI 调 SIMD；预计算负责 scorecard 与 CUPED，即席负责下钻 [来源](https://arxiv.org/abs/2405.08411)。这不是每个团队都能复制的，但它说明了一个原则：**预计算与即席不是二选一，而是按查询模式分工**。

缓存 key 必须包含所有影响结果的版本：`hash(experiment_version, metric_version, cohort_version, dim_set, time_range, granularity, filter_hash, engine_version)`。少一项，就会出现「改了定义但报表没变」的幽灵。

### 5.6 性能预算：下钻的速度决定分析的深度

<div class="table-wrap">

| 动作 | 目标 P50 | 目标 P95 | 超时策略 |
|---|---|---|---|
| 首屏结论 | < 800ms | < 1.5s | 骨架屏 + 上次快照 |
| 指标切换 | < 500ms | < 1s | 预取相邻指标 |
| 维度切换 | < 800ms | < 2s | 缓存 + 取消旧请求 |
| 二级下钻 | < 1.2s | < 2.5s | 异步 + 进度 |
| 用户列表 | < 1s | < 3s | 采样 + 分页 |
| 导出 | 立即受理 | 异步 | 队列 + 通知 + 限额 |

</div>

这些数字不是拍脑袋：超过 2 秒，用户就会失去「连续探索」的感觉，退回「先想好问题再查」的模式；而分析的价值恰恰来自连续追问。性能预算应该写进 PRD，和功能一起验收。

### 5.7 六个下钻反模式

1. **把子群当结论**：在 20 个切片里挑一个显著的，写成「对某人群有效」。→ 必须标探索性 + FDR。
2. **下钻后对照组消失**：某切片只剩实验组，仍然显示「提升」。→ 必须显示两组 N，缺一组就禁用结论。
3. **维度值洪水**：一次渲染 500 个机型，用户找不到重点。→ TopN + 搜索 + 最小样本。
4. **口径漂移**：下钻时换了指标定义/时间窗，用户不知道。→ 上下文条常驻 + 版本号。
5. **缓存串租户**：A 租户的查询结果被 B 租户命中。→ 缓存 key 带 tenant_id + 权限校验。
6. **导出泄露**：用户列表导出包含敏感字段/全量 ID。→ 脱敏、审批、水印、审计。

## 6. 高级分析：默认严谨，逐项解释

高级分析的功能清单很容易做：CUPED、Uplift、序贯、贝叶斯、DiD、合成控制，每个名字都能变成一个菜单项。难的是另一件事：当用户点下这个菜单项时，平台是否替他承担了**假设检查、多重比较、失败解释和决策责任**。

### 6.1 产品化的四层接口

<div class="ab-specs">
  <div class="ab-spec"><div class="k">LAYER 01</div><h3>入口即契约</h3><p>选方法前先问：随机化单元是什么、指标是比例/均值/比率/分位数、有没有可信的 pre-period、有没有 interference。不满足条件，方法不出现在可选列表里，而不是选完再报错。</p></div>
  <div class="ab-spec"><div class="k">LAYER 02</div><h3>默认值即观点</h3><p>CUPED 默认开、SRM 默认拦、多重比较默认按家族校正、序贯默认只用于监控。这些默认值直接决定用户看到的数字。</p></div>
  <div class="ab-spec"><div class="k">LAYER 03</div><h3>结果即解释</h3><p>每个数字带口径、窗口、样本量、CI、校正后的 p；每个失败态给出下一步动作，而不是一句「无显著差异」。</p></div>
  <div class="ab-spec"><div class="k">LAYER 04</div><h3>成本可见</h3><p>CI 会变宽多少、样本要膨胀多少、实验会慢几天，在选方法时就预估；不要等上线后才发现「高级方法」的代价。</p></div>
</div>

### 6.2 方法菜单：每个方法回答什么问题

<div class="table-wrap">

| 方法 | 业务问题 | 关键假设 | 产品如何暴露 | 什么时候不该用 |
|---|---|---|---|---|
| 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；看长期效应；护栏指标 |

</div>

这张表最重要的不是「支持多少方法」，而是「什么时候不该用」。一个方法如果只能在满足假设时使用，产品就必须在入口处做检查，而不是在结果页写一行免责声明。

### 6.3 CUPED：默认开，但要说清代价

CUPED 的逻辑很简单：用实验前的协变量 X 解释实验期的 Y，把「本来就会不同」的部分减掉：

```text
Y_adj = Y − θ · (X − X̄)
θ = Cov(Y, X) / Var(X)
方差缩减 ≈ ρ²
```

产品上最容易犯的错，是只给一个「CUPED 已开启」的开关，不给用户看：

- 用了哪段 pre 期？pre 期是否被上一个实验污染？
- 协变量与当前指标的相关性是多少？实际方差缩减了多少？
- 新用户没有 pre 数据，是否被排除？排除后样本量变化多少？
- 分位数/比率指标是否直接套用了均值 CUPED？

<span class="ev ev-advice">建议</span> 结果页并列显示「原始」与「CUPED」两套数字，并给出方差缩减比例；当 CUPED 改变结论方向时，强制提示「结论对协变量调整敏感」，而不是只展示调整后的漂亮区间。Eppo 的文档把 CUPED 的假设、协变量选择与实现讲得比较清楚 [来源](https://docs.geteppo.com/statistics/cuped/)，可以作为产品文案的参考。

### 6.4 Uplift / CATE：从「找人群」到「验证人群」

Uplift 的产品价值不在模型，而在交付：**一群人、一个方向、一个可执行的名单**。DataTester 的敏感人群洞察把这件事做成了完整工作流 [来源](https://docs.byteplus.com/en/docs/DataTester/Sensitive-Population-Insights)：

- 任务粒度是「一个指标、一个实验组、一个对照组」；
- 挖掘方向分正向/负向；
- 输出 TOP 敏感人群、特征重要性、TOP 3 特征的二维交叉子群；
- 支持下载人群明细（treatment、uid、ite、bins、业务 ID）。

但它也暴露了 Uplift 的典型风险：

- 推荐入组人数 > 2 万、维度 > 4 个，否则模型不稳定；
- 子群是「TOP 特征交叉」选出来的，存在选择偏倚；
- 公开文档没有说明子群 p 值是否做多重比较校正，产品上应按「未校正」处理；
- ITE 是模型预测，不是个体真实因果效应；
- 下载名单用于全量投放前，应该做 holdout 验证。

<span class="ev ev-advice">建议</span> 产品上把 Uplift 放进「探索」层，把验证放进一个新的 confirmatory 实验：用 Uplift 选出人群 → 设计一个只看这批人的 A/B → 用 holdout 验证增量 → 再决定是否全量。这个闭环比「模型 AUC 很高」更有说服力。

### 6.5 序贯与贝叶斯：让「随时看」不再等于「假阳性」

实验平台最常见的用户行为是「每天打开报告看一眼」。在固定样本频率派框架下，这会让一类错误膨胀；序贯检验/always-valid 就是为这个场景设计的。产品上要区分两件事：

- **监控**：每天看趋势、护栏、SRM，不宣布胜负；
- **决策**：达到预定义样本/时间后，用固定样本或序贯的正式区间做结论。

如果平台支持「随时可停」，就必须同时支持：

- alpha spending 或 confidence sequence；
- 预定义看点与参数锁定；
- 早停时的效应量高估提示；
- 多指标/多版本的额外校正。

贝叶斯则是另一条路：给决策者「获胜概率/期望损失」，而不是 p 值。它的产品难点在先验：没有历史数据却拍一个强先验，比不做贝叶斯更危险。Eppo 对贝叶斯与频率派方法的对比写得比较克制 [来源](https://docs.geteppo.com/statistics/confidence-intervals/analysis-methods/)，可以作为术语与文案的参考。

### 6.6 多重比较：先定义家族，再谈显著性

多重比较不是「把 p 值乘一个数」那么简单。产品必须先帮用户定义「家族」：

- 一个实验里的所有变体 × 所有指标，是一个家族；
- 一个指标下的所有维度切片，是另一个家族；
- 护栏指标应该单独一个家族，用更严的 FWER；
- 子群应该先做交互检验，而不是逐格检验。

常见方法：

- **Bonferroni**：`α/m`，保守但简单；
- **Holm**：逐步法，比 Bonferroni 有更高功效；
- **BH**：控制 FDR，适合探索性指标多、但可以接受少量假阳性的场景。

<span class="ev ev-advice">建议</span> 默认策略：主指标 preferential α，次要指标 BH，护栏 Holm，子群先交互。界面同时显示 raw p 与 adjusted p，默认按 adjusted 排序；当 adjusted 跨 0 而 raw 显著时，文案必须写「校正后不显著」，不能写「有趋势」。

### 6.7 为什么「自定义人群 + 高级方法」最容易产生假阳性

三个乘数叠在一起：

1. **人群定义的自由度**：年龄、城市、活跃度、价格敏感、生命周期……可以切出无数个子群；
2. **指标的自由度**：5 个指标 × 4 个人群 = 20 次检验，至少一次假阳性的概率约 64%；
3. **方法的自由度**：CUPED 开/关、贝叶斯先验、序贯看点、异常值处理，每一种都能改变结论。

更麻烦的是事后定义：先看结果，再圈一个「高价值、低活跃、近 30 天没下单」的人群，等于把选择藏进了分析。校正只能覆盖登记过的检验，覆盖不了用户脑子里那条还没说出口的假设。

LLM 会把这条乘法器再放大一次：让模型扫描所有切片、挑出「最值得讲」的三个，再写一段原因，等于把数据挖掘自动化。每一句听起来合理的解释，背后都可能是一个未登记的检验。

### 6.8 方法选择决策表

<div class="table-wrap">

| 实验场景 | 样本量 | 指标类型 | 有 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 或护栏结论 |

</div>

### 6.9 LLM 在分析模块里的可信边界

LLM 在实验分析里能做三层，可信度依次下降：

- **叙述层**：把已经算好的结果翻译成业务语言。安全，前提是数字只能来自结果对象。
- **诊断层**：提示 SRM、MDE 不足、cohort 未成熟、样本低于门槛。较安全，因为规则可审计。
- **归因层**：解释「为什么涨」。不安全。实验识别的是效应，不是机制；机制要靠埋点、日志、访谈和后续实验去验证。

产品规则可以写得很硬：

1. **数字白名单**：只允许引用结果对象里的字段；每个数字带 cell 链接；没有计算就写「未计算」，不许估。
2. **拒绝条件**：SRM 未过、样本低于门槛、CI 跨 0、校正后不显著时，不允许生成「获胜原因」。
3. **归因措辞**：只能写「可能机制（待验证）」，并列出还需要什么证据；不能写「因为 X 所以 Y」。
4. **LLM 提议的切片就是新的检验**：必须登记、校正，或放到 holdout 上验证；否则就是自动化 data dredging。
5. **评估与审计**：用历史实验的已知结论做回归测试；记录模型、提示、上下文、版本；上线决策必须有人签字。

字节在 AICon 2024/2025 的公开演讲里提到，用 LLM 做实验分析提效、实验咨询与分析智能体 [来源](https://aicon.infoq.cn/2024/beijing/speaker/8593) [来源](https://www.infoq.cn/article/judnchxzzbp34zbezfkx)。这是方向，不是交付证据。对产品团队的含义是：LLM 应该先做「叙述 + 诊断」，不要把「归因」当成默认能力；否则它会用最流畅的语言，放大最脆弱的统计结论。

## 7. 页面设计：一张分析页的解剖

分析页不是「数据展示页」，而是「决策证据页」。四类用户不是四种并列视图，而是同一条证据链上的四个检查点：

<div class="table-wrap">

| 角色 | JTBD | 首屏必须回答 | 最怕的失败 |
|---|---|---|---|
| PM | 决定是否上线 | 这版能不能上？大概多多少？有没有踩护栏？ | 把「不显著」当「无效果」；只看相对提升 |
| DS | 为效应背书 | 效应可信吗？证据够吗？哪个子群在动？ | 只看 p 值；切片多重比较；口径被改过不知道 |
| 数据工程 | 保障口径与性能 | 这个数怎么算？何时更新？为什么慢或为空？ | 同名不同义；漏斗改动回溯影响所有实验 |
| 管理者 | 组合决策 | 哪些该上、哪些该停、整体风险如何？ | 单实验视角；没有决策记录；赢家诅咒 |

</div>

### 7.1 首屏：只回答「要不要动」

<div class="ab-wire" aria-label="分析页线框">
  <div class="ab-wire-top"><i></i><i></i><i></i><span>ANALYSIS / WIREFRAME v1</span></div>
  <div class="ab-wire-grid">
    <div class="ab-wire-col">
      <div class="ab-wire-box"><b>NAV</b>结论<br>指标<br>人群<br>下钻<br>高级<br>诊断</div>
      <div class="ab-wire-box tall"><b>CONTEXT</b>实验名<br>状态<br>owner<br>数据截止<br>指标 v3</div>
    </div>
    <div class="ab-wire-col">
      <div class="ab-wire-box accent"><b>VERDICT</b>建议上线 / 证据不足<br>主指标 +3.2%（CI 1.1~5.4）<br>N=82,140 / 82,003 · 护栏 4/4</div>
      <div class="ab-wire-box"><b>GUARDRAIL STRIP</b>崩溃率 —｜支付失败 ↑0.02pp（未越界）｜退款率 —</div>
      <div class="ab-wire-box tall"><b>METRIC TABLE</b>核心 1｜必看 4｜探索 12<br>指标 · 基准 · 绝对差 · 相对差 · CI · 状态<br>行内展开：趋势 / 分布 / 箱线 / 维度拆解</div>
      <div class="ab-wire-box"><b>FILTER / COHORT</b>[新用户 ×] [iOS ×] [+ 筛选] [模板▾] N −12%</div>
      <div class="ab-wire-box"><b>DIAGNOSTICS</b>SRM p=0.42｜曝光/进组 98.7%｜10-21 06:12 重算</div>
    </div>
    <div class="ab-wire-col">
      <div class="ab-wire-box tall"><b>DRILL DRAWER</b>渠道 / 城市 / 机型<br>面包屑 · 每层 N · CI<br>用户样本（脱敏）<br>查询耗时 / 缓存</div>
      <div class="ab-wire-box"><b>EVIDENCE</b>口径卡<br>方法卡<br>版本历史<br>评论 / 决策记录</div>
    </div>
  </div>
  <div class="ab-wire-legend">左：导航与上下文｜中：结论、指标、筛选、诊断｜右：下钻抽屉与证据。首屏不放下钻明细，避免抢结论的注意力。</div>
</div>

首屏的权重顺序是：**结论 > 护栏 > 核心指标 > 证据入口 > 诊断**。图表回答「怎么变」，首屏要回答「做不做」。DataTester 把结论放在实验概览区，并用颜色标显著方向 [来源](https://docs.byteplus.com/en/docs/DataTester/How-to-Interpret-the-Experiment-Report)；但「建议」应该由实验 owner 写，系统只给证据。这个分工很重要：平台不能替组织做决策，但必须让决策所需的信息在 5 秒内可见。

### 7.2 关键组件：每个组件都在回答一个反驳

<div class="table-wrap">

| 组件 | 要回答的反驳 | 设计要点 | 代价 / 边界 |
|---|---|---|---|
| 结论卡 | 凭什么这么说？ | 一句话结论 + 主指标 + 绝对/相对效应 + CI + N + 证据等级 | 一句话必然压缩信息，必须可展开到证据 |
| 指标表 | 还有哪个指标在动？ | 一行一指标；核心/必看/探索分组；冻结首列；N/基准/绝对差/相对差/CI/p/MDE | 列多，小屏不可用，需卡片降级 |
| CI 条 | 效应最小可能多少？ | 0 线、95% 区间、两端数值、N；轴不截断 | 非统计用户会读成「保证范围」 |
| 显著性标记 | 真显著还是错觉？ | 颜色 + 图标 + 文字（显著正向/负向/不显著/不可检验） | 颜色失效即信息失效 |
| 趋势/分布 | 何时开始变、是否极端值拉动？ | 累计曲线 + 区间带；标注日级不含今天；箱线显示重叠面积 | CVR 不支持箱线；小时/分钟无箱线 |
| 维度拆解 | 对谁有效、对谁有害？ | 每切片 N/CI/方向；标「探索性/未校正」；限制切片数 | 切片越多假阳性越多 |
| 人群构建器 | 这批人怎么来的、有多新？ | 规则/文件、预估人数、更新频率、口径预览 | 静态群手动更新；属性取最新值 |
| 查询/空错态 | 它在跑吗？下一步做什么？ | 2 秒内骨架；长任务分阶段进度/取消/保留上次结果；空态给原因 + 入口 | 异步任务可能 10 分钟–2 小时 |
| 证据抽屉 | 这个数怎么算的？ | 指标定义、分母、窗口、版本、owner、查询指纹 | 信息密度高，默认折叠 |

</div>

DataTester 有一个值得警惕的细节：PV、UV、SUM、去重数这类指标不支持置信水平计算 [来源](https://docs.byteplus.com/en/docs/DataTester/Create-Event-Metric)。它们可以出现在表里，但必须标「不可检验」，否则用户会把「没有 CI」当成「没有差异」。

### 7.3 信任设计：让数字可被质疑

- **口径卡，而不是 tooltip**：指标配置里本来就有「指标描述」字段，要求写清含义、计算逻辑、用途 [来源](https://docs.byteplus.com/en/docs/DataTester/Create-Event-Metric)。报告页应把它升级为可引用的定义卡：分母、时间窗、归因、排除规则、版本、owner。
- **样本量拆三层**：进组、曝光、有效样本。只给一个 N，SRM 无法判断。DataTester 的进组数当天实时、次日起 T-1、以 0 点为界 [来源](https://docs.byteplus.com/en/docs/DataTester/Experimental-Report-Overview)。
- **SRM 与护栏**：DataTester 公开报告文档没有 SRM 状态（证据缺口）。GrowthBook 在结果页直接插入 SRM 与多重曝光警告，SRM p<0.001，并写明「不应相信结果」[来源](https://docs.growthbook.io/app/experiment-results)。建议做成硬 gate：异常时置顶诊断、隐藏效应、只留样本与排查入口。
- **探索性标记**：差异分析用 Monte Carlo 给「获胜概率」[来源](https://docs.byteplus.com/en/docs/DataTester/Advanced-Analysis-Difference-Analysis-and-Group-Comparison)，敏感人群是 Uplift 挖掘 [来源](https://docs.byteplus.com/en/docs/DataTester/Sensitive-Population-Insights)；这些是探索，不是确认。UI 要标「探索性、未校正、需独立复现」。
- **多重比较提示**：页面显示「本页 24 指标 × 6 切片」；提供 BH/Holm 或 adjusted p。GrowthBook 的校正家族是 goals × variations × dimensions，维度切片单独校正 [来源](https://docs.growthbook.io/statistics/multiple-corrections)。
- **变更历史**：漏斗任何修改都会更新所有使用它的实验报告，且不缓存 [来源](https://docs.byteplus.com/en/docs/DataTester/Metric-Analysis-Funnel-Metric-Analysis)——这是典型的静默变更。建议版本化 + 「报告已重算」横幅 + 变更 diff。
- **评论与批注**：公开文档未见（证据缺口）。建议锚定到指标/切片，@owner、resolve、写 decision log；评审用不可变快照，而不是实时页。

### 7.4 空态、加载态与错误态

分析页的失败，大多不是「算错」，而是「用户不知道发生了什么」。三种状态要写清楚：

<div class="table-wrap">

| 状态 | 不要这样写 | 应该这样写 | 下一步 |
|---|---|---|---|
| 空态：无数据 | 「暂无数据」 | 「该人群在所选时间窗内没有曝光；可能原因：人群圈选过窄 / 实验未开始 / 埋点延迟」 | 放宽时间窗 / 查看分流诊断 / 联系 owner |
| 空态：样本不足 | 「不显著」 | 「当前每组 1,240 人，只能检测 ≥ 8.2% 的效应；业务目标是 2%」 | 延长实验 / 扩大流量 / 降低 MDE 预期 |
| 加载：长查询 | 转圈 | 「正在扫描 3 个分区，预计 18 秒」+ 取消 + 保留上次结果 | 等待 / 取消 / 查看缓存版本 |
| 错误：查询失败 | 「系统错误」 | 「查询超时（>30s）；已缩小到近 7 天，可重试或导出异步任务」 | 重试 / 缩小范围 / 异步 |
| 错误：口径变更 | 「数据已更新」 | 「指标 v4 于 10-20 变更：分母从 UV 改为 AU；本报告已重算，历史结论可能不可比」 | 查看 diff / 用旧版本重跑 |

</div>

### 7.5 可访问性与响应式

- **键盘**：指标表用 grid 模式，roving tabindex，方向键移动，Enter 展开，Esc 关闭 [来源](https://www.w3.org/WAI/ARIA/apg/patterns/grid/)。DataTester 的交互是 hover 出解读、点击出统计卡 [来源](https://docs.byteplus.com/en/docs/DataTester/Experimental-Report-Overview)；hover-only 必须补 focus/click 等价物。
- **色彩不是唯一编码**：DataTester 用绿/红/黑编码显著性 [来源](https://docs.byteplus.com/en/docs/DataTester/How-to-Interpret-the-Experiment-Report)，WCAG 1.4.1 要求颜色不能是唯一手段 [来源](https://www.w3.org/WAI/WCAG22/Understanding/use-of-color.html)。加箭头、图标、文字，灰度打印仍可辨。
- **对比与焦点**：文本 4.5:1、UI 3:1、焦点可见；触控目标至少 24×24（WCAG 2.2）。
- **表格小屏降级**：≥1280 全列；768–1279 隐藏绝对差/MDE，保留相对差 + CI；<768 一行一卡（指标名、效应、CI、状态），点开底部抽屉；首列 sticky，横向滚动给阴影提示。
- **图表替代**：提供「表格视图」与文字摘要；异步完成用 aria-live 播报，不要只靠 toast。
- **移动端**：只保留「结论 + 核心指标 + 护栏 + 审批」；下钻与高级分析引导到桌面，而不是硬塞进小屏。

### 7.6 六条可用性验收标准

1. **5 秒结论**：80% 目标用户不滚动即可说出「上/不上/证据不足 + 主指标方向 + 是否过护栏」。
2. **三重编码**：任一显著性标记在灰度与色盲模拟下仍可区分；颜色、图标、文字同时存在。
3. **键盘闭环**：从实验列表到展开统计卡 ≤ 6 次 Tab/方向键；无 hover-only 信息；焦点始终可见。
4. **口径可追溯**：任一数字 2 次点击内看到定义、分母、时间窗、版本、最后更新；口径变更后出现「已重算」提示。
5. **状态可解释**：查询 > 2 秒有阶段进度与取消；失败保留上次结果并给原因与重试；空态给下一步入口。
6. **切片不静默**：任何筛选/分组后同时显示 N 与基准 N；探索性结果带「未校正」标记；页面显示「指标数 × 切片数」。

## 8. 技术实现：语义层、查询与统计

分析模块的工程难点不是「把 SQL 跑快」，而是让同一个业务问题，在实验组与对照组、今天与上周、整体与下钻之间，被编译成同一套可复现的查询。

### 8.1 逻辑架构：六个平面

<div class="ab-model">
  <div class="ab-model-head"><span>ANALYSIS ARCHITECTURE / 逻辑分层</span><span>控制面 / 分析面 / 数据面</span></div>
  <div class="ab-model-body">
    <div class="ab-layers">
      <div class="ab-layer"><span class="name">体验层</span><span class="body"><span class="ab-node">结论卡</span><span class="ab-node">指标表</span><span class="ab-node">人群构建器</span><span class="ab-node">下钻抽屉</span><span class="ab-node">高级分析</span><span class="ab-node">导出/API</span></span></div>
      <div class="ab-layer is-core"><span class="name">分析服务</span><span class="body"><span class="ab-node">分析编排</span><span class="ab-node">查询编译</span><span class="ab-node">统计引擎</span><span class="ab-node">结果缓存</span><span class="ab-node">权限/审计</span></span></div>
      <div class="ab-layer"><span class="name">语义层</span><span class="body"><span class="ab-node">实验元数据</span><span class="ab-node">指标注册表</span><span class="ab-node">人群服务</span><span class="ab-node">维度/属性服务</span><span class="ab-node">方法注册表</span></span></div>
      <div class="ab-layer"><span class="name">计算层</span><span class="body"><span class="ab-node">查询队列</span><span class="ab-node">预聚合任务</span><span class="ab-node">异步任务</span><span class="ab-node">资源组/配额</span></span></div>
      <div class="ab-layer"><span class="name">存储层</span><span class="body"><span class="ab-node">曝光宽表</span><span class="ab-node">指标明细</span><span class="ab-node">人群 Bitmap</span><span class="ab-node">结果快照</span><span class="ab-node">审计日志</span></span></div>
      <div class="ab-layer"><span class="name">治理层</span><span class="body"><span class="ab-node">指标认证</span><span class="ab-node">口径指纹</span><span class="ab-node">数据质量</span><span class="ab-node">成本核算</span><span class="ab-node">合规</span></span></div>
    </div>
  </div>
</div>

这六层的失败模式各不相同：元数据错会串组，指标错会口径漂移，人群错会人口漂移，维度错会把「当前属性」当成「进组时属性」，缓存错会串租户，治理缺失会让错数无法追溯。架构图的价值不是好看，而是让每一层都有明确的 owner 与可观测指标。

### 8.2 指标 DSL：七个槽位

一个实验指标 DSL 至少要有七个槽位：事件、聚合算子、分母、过滤、时间窗、归因窗口、去重键。

```json
{
  "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 种「计算方式」[来源](https://docs.byteplus.com/en/docs/DataTester/Create-Event-Metric)。拆开看，14 种其实是 3 个原子（count / sum / distinct）× 4 个分母（AU、UV、PV、SUM(DAU)）× 时间语义。**分母才是灵魂**：同样是「支付转化」，`UV/AU` 问的是「进组的人里有多少人付过」，`PV/UV` 问的是「付过的人平均付几次」，两者不能互相解释。

置信度支持矩阵是 DSL 的一部分，不是 UI 的补丁。DataTester 明确列出，总量（PV）、总人数（UV）、求和（SUM）、按属性去重四类单指标不能计算置信度；组合指标也只对特定分子/分母类型开放 [来源](https://docs.byteplus.com/en/docs/DataTester/Create-Event-Metric)。**推断**：这不是产品偷懒，而是统计引擎的真实接口——方差必须从「每个用户一个值」的样本里估计，纯总量没有用户级分布。所以编译器必须先把任何指标降成「每人一行 `(num, den)`」，再由统计层聚合。

### 8.3 查询编译：从请求到充分统计量

一个分析请求是一个五元组：`experiment × metrics × cohort × dimensions × time`。编译器做七件事：

1. 取实验版本与 variant 映射；
2. 展开指标为 `(numerator, denominator, filter, window)`；
3. 下推人群（join 快照或 bitmap）；
4. 解析维度（字典表或 `argMax` 取时点值）；
5. 生成用户级 CTE；
6. 生成聚合查询；
7. 交给统计层。

编译后的伪 SQL 大致如下。注意三个细节：**variant 只做列不做表**、**分母恒为 1 且用 LEFT JOIN**、**结果返回二阶矩而不是一个数**。

```sql
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 [来源](https://docs.byteplus.com/en/docs/DataTester/Metric-Analysis-Funnel-Metric-Analysis)。组的定义与指标同源，避免了 assignment 表 join 的丢失与串组。

### 8.4 存储选型：三种负载，不可能一个引擎全吃

<div class="table-wrap">

| 引擎 | 最擅长的「那一刀」 | 代价与边界 | 适合 / 不适合 |
|---|---|---|---|
| ClickHouse | 单表宽表 + 预聚合；Bitmap 精确 UV | 增量物化视图只处理新写入块，历史重算要另建链路；JOIN 需宽表/小表广播 | 曝光宽表、实时护栏、私有化单链路；不适合频繁更新维表与复杂多表即席 |
| Doris | 聚合/主键模型，物化视图透明改写，固定模板并发好 | 改写依赖优化器与 MV 设计；维度组合仍被预聚合锁死 | 报表模板稳定、租户多的 SaaS；不适合长尾即席 |
| StarRocks | 主键模型 + 异步物化视图，多表 JOIN 聚合 | 内存与运维成本高；MV 刷新有延迟窗口 | 星型模型、指标多而维度相对固定 |
| BigQuery / Snowflake | 存算分离，按扫描量计费，回填/审计/共享友好 | 交互延迟与成本随扫描量上升；物化视图能力受限 | 决策口径与历史回填；不适合亚秒拖拽 |
| Druid | 摄入即 roll-up + 近似算法，亚秒看板 | 不支持按主键低延迟更新，不擅长大表 JOIN | 实时健康度与 SRM 护栏；不适合财务对账与复杂归因 |

</div>

预聚合有三件套：Bitmap 做 UV（交并差快，但高基数会膨胀，且回答不了「这些人是谁」）；BSI 做金额求和与分位数（需 bucket 编码，精度换空间）；物化视图做固定维度组合（查询改写依赖优化器）。一条容易犯的错：**不要把比率的比值存进 cube**，只存分子和分母，查询时再除；否则跨天、跨维度合并时权重就错了。

维度组合是 2^N，全预聚合必然爆炸。现实做法是「高频维度做 cube + 任意维度现算明细」。DataTester 有一条很诚实的限制：属性分组之后，不支持切换 preAA 数据、查看数据分布和箱线图 [来源](https://docs.byteplus.com/en/docs/DataTester/Metrics-Analysis-Event-Metrics-Retention-Metrics)。**推断**：分组查询走的是预聚合/cube 路径，原始用户分布不在 cube 里，所以分布类视图只能关闭。这就是「预聚合换性能」的真实代价。

### 8.5 API 与数据模型

一个最小可用的分析 API 可以只有六个端点：

<div class="table-wrap">

| 方法 | 路径 | 作用 | 关键参数 |
|---|---|---|---|
| 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 |

</div>

核心表至少要有：

<div class="table-wrap">

| 表 | 关键字段 | 作用 |
|---|---|---|
| `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 | 审计 |

</div>

### 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 重跑、新旧指标版本、实时与离线对账。

<span class="ev ev-advice">建议</span> 把编译后 SQL 的哈希作为「口径指纹」写进结果表，报表页可展示。这样任何数字都能回答「它是用哪版定义、哪版人群算的」。权限上，指标的可见性与行的可见性要分开；共享缓存和导出文件是最容易被忽略的越权泄漏点。

### 8.7 三个阶段：MVP、规模化、智能化

<div class="ab-flow">
  <div class="ab-flow-step"><div class="k">MVP / 0–6 个月</div><div class="v">能复算</div><div class="d">Postgres 元数据 + 单机 ClickHouse + T+1 批处理；不做缓存</div></div>
  <div class="ab-flow-step"><div class="k">规模化 / 6–18 个月</div><div class="v">能并发</div><div class="d">拆编译/统计服务；队列、缓存、cube、租户资源组、审计</div></div>
  <div class="ab-flow-step"><div class="k">智能化 / 18 个月+</div><div class="v">能解释</div><div class="d">异常归因、自动下钻、Uplift/HTE、自然语言转 DSL</div></div>
</div>

MVP 的目标不是快，而是「每个数字都能手工复算」。此时最重要的交付物是 DSL 和一张指标契约表，而不是引擎。智能化的底线是：自然语言只能生成 DSL，不能直写 SQL——否则前面所有的版本、权限、口径指纹全部失效。

## 9. PRD：P0/P1/P2 与验收

### 9.1 范围与不做什么

**做**：一个实验分析工作台，支持结论、指标、人群、下钻、高级分析五个面；支持自定义指标、人群圈选、筛选模板、维度下钻、CUPED/序贯/多重比较；提供 API 与审计。

**不做**（至少第一年）：不做通用 BI；不做全量 SQL 编辑器；不做自动投放；不做跨实验的因果网络；不做无审批的用户明细导出。

### 9.2 需求优先级

<div class="ab-prd">
  <div class="ab-prd-row"><div class="p">P0 · 契约</div><div class="what"><b>分析对象与版本契约</b><span>Experiment / Analysis / Metric / Audience / Dimension / Method / Result 七个对象；六个版本号进请求；口径指纹入结果表。</span></div><div class="why">没有它，后面所有功能都不可复现。</div></div>
  <div class="ab-prd-row"><div class="p">P0 · 结论</div><div class="what"><b>结论卡 + 指标表 + 证据带</b><span>首屏给建议、主指标、绝对/相对效应、95% CI、N、护栏状态、数据截止时间；指标表支持核心/必看/探索分组。</span></div><div class="why">80% 的用户只看首屏；首屏不可信，平台就没有存在感。</div></div>
  <div class="ab-prd-row"><div class="p">P0 · 指标</div><div class="what"><b>指标注册表与构建器</b><span>14 种算子、组合指标、过滤、时间窗、去重键；不可检验指标显式标记；被引用后锁定口径。</span></div><div class="why">指标是分析的法律条文，不能现场拼。</div></div>
  <div class="ab-prd-row"><div class="p">P0 · 人群</div><div class="what"><b>人群构建器与两种作用位置</b><span>规则/文件；AND/OR 嵌套；预估人数；日更/手动；分流前 vs 分流后模式；时点校验。</span></div><div class="why">人群是分析的一等对象，也是因果风险的最高发区。</div></div>
  <div class="ab-prd-row"><div class="p">P0 · 下钻</div><div class="what"><b>维度下钻与用户样本</b><span>维度切换、面包屑、每层 N/CI、TopN + 其他、用户样本脱敏、导出审批。</span></div><div class="why">从「知道」到「知道为什么」的关键一步。</div></div>
  <div class="ab-prd-row"><div class="p">P0 · 护栏</div><div class="what"><b>SRM、护栏、口径卡、诊断</b><span>每次刷新自动 SRM；必看指标继承；数据截止/版本/owner；分流诊断入口。</span></div><div class="why">信任来自可见的失败；隐藏异常比异常本身更伤。</div></div>
  <div class="ab-prd-row"><div class="p">P0 · 工程</div><div class="what"><b>查询编排、缓存、权限、审计</b><span>同步/异步分级；缓存 key 含全部版本；租户隔离；行级权限；导出审计。</span></div><div class="why">没有这些，性能与合规会在规模化时同时爆雷。</div></div>
  <div class="ab-prd-row"><div class="p">P1 · 复用</div><div class="what"><b>筛选模板、保存视图、分享链接</b><span>实验级/应用级模板；owner/描述/使用次数；URL 编码全部上下文。</span></div><div class="why">口径复用的最小单位，也是团队协作的起点。</div></div>
  <div class="ab-prd-row"><div class="p">P1 · 统计</div><div class="what"><b>CUPED、序贯、多重比较默认化</b><span>调整前/后并列；alpha spending；BH/Holm；raw p 与 adjusted p 并列。</span></div><div class="why">高级方法不默认，就等于没有；默认不解释，就等于误导。</div></div>
  <div class="ab-prd-row"><div class="p">P1 · 分析</div><div class="what"><b>Cohort / 漏斗 / 差异分析</b><span>按进组日分 cohort；漏斗每层转化；属性过滤 + 分组对比；探索性标记。</span></div><div class="why">覆盖长期效应与「对谁有效」的高频问题。</div></div>
  <div class="ab-prd-row"><div class="p">P1 · 协作</div><div class="what"><b>评论、决策记录、导出/API</b><span>锚定指标/切片的评论；不可变快照；决策状态；CSV/API 导出。</span></div><div class="why">让分析沉淀为组织资产，而不是一次性报表。</div></div>
  <div class="ab-prd-row"><div class="p">P2 · 智能</div><div class="what"><b>Uplift/CATE + holdout 验证</b><span>独立任务向导；TOP 子群；ITE 分箱；样本外验证；与确证实验联动。</span></div><div class="why">高价值但高风险；没有验证闭环不上主路径。</div></div>
  <div class="ab-prd-row"><div class="p">P2 · 智能</div><div class="what"><b>LLM 叙述与诊断</b><span>只引用结果对象；拒绝条件；归因措辞限制；评估与审计。</span></div><div class="why">能提效，但会把统计脆弱性放大。</div></div>
  <div class="ab-prd-row"><div class="p">P2 · 组合</div><div class="what"><b>实验组合视图与自动下钻</b><span>跨实验台账；holdout 管理；异常自动定位；自然语言转 DSL。</span></div><div class="why">从单实验走向组合决策，需要新的信息架构。</div></div>
</div>

### 9.3 验收标准

1. **可复现**：任取一个结论，输入六个版本号，能在 1 次重跑中复现同一数字（误差在浮点范围内）。
2. **可解释**：任一数字 2 次点击内看到指标定义、分母、时间窗、版本、owner、数据截止。
3. **可拦截**：SRM 异常时，效应数字被隐藏，只保留诊断与样本；护栏恶化时，结论卡强制降级。
4. **可探索**：维度下钻 P95 < 2.5 秒；用户样本 P95 < 3 秒；超过 30 秒自动转异步。
5. **可校正**：页面显示「本次分析 N 次检验」；adjusted p 与 raw p 并列；探索性结果带标记。
6. **可协作**：分享链接打开是同一实验、指标、人群、维度路径、时间窗、方法；评论可 @owner。
7. **可审计**：谁在什么时间、用什么理由、导出了多少行、包含哪些字段，全部可查。
8. **可访问**：键盘可完成「进报告 → 切指标 → 展开证据 → 下钻 → 返回」；颜色不是唯一编码。

### 9.4 成功指标

<div class="table-wrap">

| 指标 | 定义 | 目标（上线 6 个月） |
|---|---|---|
| Time to insight | 从打开报告到做出决策的中位时长 | 降低 40% |
| 分析复用率 | 使用模板/保存视图/分享链接的分析占比 | > 50% |
| 查询 P95 | L2 同步查询的 95 分位 | < 2.5s |
| SRM 覆盖率 | 有 SRM 状态的核心实验占比 | 100% |
| 校正覆盖率 | 多指标/多切片分析中开启校正的占比 | > 80% |
| 决策记录完成率 | 有结论、owner、后续动作的实验占比 | > 60% |
| 口径争议数 | 因口径不一致导致的工单/争议 | 每月 < 5 |

</div>

### 9.5 落地节奏

- **0–90 天**：P0 契约 + 结论卡 + 指标表 + 人群构建器 + SRM/护栏；先接 1 个业务线、20 个核心指标。
- **90–180 天**：下钻 + 模板 + CUPED/序贯/多重比较 + Cohort/漏斗；接 3 个业务线。
- **180–365 天**：差异分析 + Uplift + 决策记录 + API；建立指标认证与 owner 制度。
- **365 天以后**：组合视图、自动下钻、LLM 叙述/诊断；把「分析质量」纳入平台 KPI。

### 9.6 风险与缓解

<div class="table-wrap">

| 风险 | 表现 | 缓解 |
|---|---|---|
| 口径治理跟不上 | 同名指标多个版本，结论互相打架 | 指标认证 + owner + 版本锁定 + 口径指纹 |
| 性能拖垮采用 | 下钻 10 秒，用户回到 Excel | 分级查询 + 预聚合 + 缓存 + 异步 |
| 统计复杂度吓退业务 | 用户只看 p 值或只看颜色 | 默认结论 + 渐进披露 + 解释文案 |
| 高级分析滥用 | 子群越切越多，假阳性泛滥 | 预注册 + FDR + 探索性标记 + 复验 |
| 隐私/合规 | 用户明细导出泄露 | 脱敏 + 审批 + 行级权限 + 审计 |
| 组织不信任 | 「平台数字和数仓对不上」 | 对账任务 + 结果 diff + 公开口径 |

</div>

## 10. 反模式与决策清单

### 10.1 十二个反模式

<div class="table-wrap">

| 反模式 | 症状 | 根因 | 修复 |
|---|---|---|---|
| 图表墙 | 首屏 20 张图，没人知道看哪张 | 以「功能多」代替「决策支持」 | 结论卡 + 三层指标 + 渐进披露 |
| p 值自动售货机 | 切 20 个切片，挑一个显著的 | 没有多重比较与探索性标记 | 预注册 + FDR + 降级文案 |
| 人群即切片 | 把 post-treatment 人群当因果结论 | 没有时点校验 | 两种作用位置 + 时点警告 + 复验 |
| 指标即字段 | 同名指标多个口径 | 没有注册表/版本/owner | 指标契约 + 认证 + 血缘 |
| 下钻即 group by | 200 个维度值、没有 N/CI | 把查询能力当分析能力 | TopN + 最小样本 + 每层护栏 |
| 缓存幽灵 | 改了定义，报表没变 | 缓存 key 缺版本 | 全版本 key + 主动失效 |
| 导出即拖库 | 用户明细随便下载 | 权限与审计缺失 | 脱敏 + 审批 + 限额 + 水印 |
| 实时崇拜 | 所有指标都要秒级 | 没区分摄入/指标/决策实时 | 分级：实时护栏 + T+1 决策 |
| 高级方法堆菜单 | 18 个方法，没人会用 | 以算法数量代替产品化 | 入口契约 + 默认值 + 解释 + 成本 |
| LLM 归因 | 流畅地解释「为什么涨」 | 把叙述能力当因果能力 | 数字白名单 + 拒绝条件 + 待验证措辞 |
| 静默变更 | 漏斗改了，所有实验报告变了 | 没有版本与通知 | 版本化 + 重算横幅 + diff |
| 数据湖直连 | 分析师各写各的 SQL | 没有语义层 | 注册指标 + 受控 DSL + 沙箱 SQL |

</div>

### 10.2 自建 vs 采购：分析模块的决策清单

<div class="ab-principles">
  <div class="ab-principle"><h3>指标口径是否是我们的核心竞争力？</h3><p>如果指标定义与业务强耦合、外部产品无法表达，语义层必须自建；否则优先复用。</p></div>
  <div class="ab-principle"><h3>数据能否出仓？</h3><p>不能出仓就选 warehouse-native 或私有化；能出仓再考虑 SaaS 的体验与统计能力。</p></div>
  <div class="ab-principle"><h3>人群与标签是否已存在？</h3><p>已有 CDP/标签平台时，分析模块应做「消费方」，不要再造一套人群服务。</p></div>
  <div class="ab-principle"><h3>是否需要自定义统计方法？</h3><p>需要 CUPED/HTE/序贯等深度定制时，自建统计层；否则用产品默认值 + API。</p></div>
  <div class="ab-principle"><h3>下钻性能能否达标？</h3><p>高基数、多维度、秒级，是自建最容易低估的部分；先做 POC 再承诺。</p></div>
  <div class="ab-principle"><h3>合规与审计是否硬要求？</h3><p>强监管场景优先私有化/物理隔离；共享 OLAP + 缓存会放大越权风险。</p></div>
</div>

### 10.3 问供应商的十个问题

1. 你们的指标定义是否版本化？被实验引用后还能改口径吗？
2. 人群是在分流前还是分流后生效？能否分别配置？
3. 子群分析是否默认做多重比较？用的什么方法？家族怎么定义？
4. SRM 是自动检测还是手工配置？异常时会不会隐藏效应？
5. CUPED 用哪段 pre 期？新用户怎么处理？分位数指标支持吗？
6. 序贯检验支持中途查看吗？alpha spending 参数能否锁定？
7. 下钻的 P95 是多少？高基数维度怎么处理？缓存 key 包含哪些版本？
8. 用户明细导出有哪些权限、脱敏、审计与限额？
9. 指标口径变更后，历史报告会不会重算？如何通知？
10. 是否提供 API/DSL，让我把分析嵌进自己的 workflow？

### 10.4 一句话收束

分析模块的终局，不是「什么都能查」，而是「查到的每个数都能被解释、被复现、被质疑，并且最终能变成一个更好的决策」。Libra/DataTester 值得学的，不是某一个图表，而是它把**统计假设、数据口径、能力边界**三件事同时放进了界面；代价是重、慢、学习曲线陡，收益是同一个结论能被 PM、DS、运营用同一种语言复述。

如果只能记住一句话：**先建契约，再建画布；先保因果，再谈智能。**

## 11. 参考来源

本页优先使用官方文档、论文与工程博客；厂商营销材料只用于确认产品存在，不作为能力证据。标注「推断」「建议」的内容是我们的产品判断，不代表任何厂商的官方设计。

### 11.1 一手产品文档

- BytePlus DataTester, *Experimental Report Overview*：[链接](https://docs.byteplus.com/en/docs/DataTester/Experimental-Report-Overview)
- BytePlus DataTester, *How to Interpret the Experiment Report*：[链接](https://docs.byteplus.com/en/docs/DataTester/How-to-Interpret-the-Experiment-Report)
- BytePlus DataTester, *Metrics Analysis: Event Metrics & Retention Metrics*：[链接](https://docs.byteplus.com/en/docs/DataTester/Metrics-Analysis-Event-Metrics-Retention-Metrics)
- BytePlus DataTester, *Create Event Metric*：[链接](https://docs.byteplus.com/en/docs/DataTester/Create-Event-Metric)
- BytePlus DataTester, *Create Warehouse Metric*：[链接](https://docs.byteplus.com/en/docs/DataTester/Create-Warehouse-Metric)
- BytePlus DataTester, *User Cohorts*：[链接](https://docs.byteplus.com/en/docs/DataTester/User-Cohorts)
- BytePlus DataTester, *User Details*：[链接](https://docs.byteplus.com/en/docs/DataTester/User-Details)
- BytePlus DataTester, *Report Page Custom Filter Template*：[链接](https://docs.byteplus.com/en/docs/DataTester/Report-Page-Custom-Filter-Template)
- BytePlus DataTester, *Advanced Analysis: Difference Analysis and Group Comparison*：[链接](https://docs.byteplus.com/en/docs/DataTester/Advanced-Analysis-Difference-Analysis-and-Group-Comparison)
- BytePlus DataTester, *Advanced Analysis: Cohort Analysis*：[链接](https://docs.byteplus.com/en/docs/DataTester/Advanced-Analysis-Cohort-Analysis)
- BytePlus DataTester, *Metric Analysis: Funnel Metric Analysis*：[链接](https://docs.byteplus.com/en/docs/DataTester/Metric-Analysis-Funnel-Metric-Analysis)
- BytePlus DataTester, *Report Interpretation: Customer Group Experiment*：[链接](https://docs.byteplus.com/en/docs/DataTester/Report-Interpretation-Customer-Group-Experiment)
- BytePlus DataTester, *Sensitive Population Insights*：[链接](https://docs.byteplus.com/en/docs/DataTester/Sensitive-Population-Insights)
- BytePlus DataTester, *SQL Custom Query*：[链接](https://docs.byteplus.com/en/docs/DataTester/SQL-Custom-Query)

### 11.2 统计、方法与工程

- Eppo, *CUPED*：[链接](https://docs.geteppo.com/statistics/cuped/)
- Eppo, *Analysis Methods*：[链接](https://docs.geteppo.com/statistics/confidence-intervals/analysis-methods/)
- Eppo, *Sample Ratio Mismatch*：[链接](https://docs.geteppo.com/statistics/sample-ratio-mismatch/)
- Eppo, *Multiple Testing*：[链接](https://docs.geteppo.com/statistics/multiple-testing/)
- Eppo, *Certified Metrics*：[链接](https://docs.geteppo.com/data-management/certified-metrics/)
- GrowthBook, *Sequential Testing*：[链接](https://docs.growthbook.io/statistics/sequential)
- GrowthBook, *Multiple Corrections*：[链接](https://docs.growthbook.io/statistics/multiple-corrections)
- GrowthBook, *Experiment Results*：[链接](https://docs.growthbook.io/app/experiment-results)
- Statsig, *CUPED*：[链接](https://docs.statsig.com/experiments/statistical-methods/methodologies/cuped)
- Wager & Athey, *Estimation and Inference of Heterogeneous Treatment Effects using Random Forests*：[链接](https://arxiv.org/abs/1510.04342)
- Deng et al., *Applying the Delta Method in Metric Analytics*（KDD 2018）：[链接](https://alexdeng.github.io/public/files/kdd2018-dm.pdf)
- Netflix, *It's About Time: Practical Considerations for Measuring Long-Term Treatment Effects*：[链接](https://arxiv.org/abs/1910.03878)
- Instacart, *Geo-based A/B Testing and Difference-in-Difference Analysis*：[链接](https://tech.instacart.com/geo-based-ab-testing-and-difference-in-difference-analysis-in-instacart-catalog-2ba05e744a3f)
- ByteDance, *DQ Estimator for Two-sided Markets*：[链接](https://arxiv.org/abs/2305.02542)
- 腾讯微信实验平台, *VLDB 2024 论文*：[链接](https://arxiv.org/abs/2405.08411)

- Statsig, *Interpreting Results / Custom Queries*：[链接](https://docs.statsig.com/experiments/interpreting-results/custom-queries)
- Statsig, *Differential Impact Detection*：[链接](https://docs.statsig.com/experiments/exploring-results/differential-impact-detection)
- Eppo, *Segments*：[链接](https://docs.geteppo.com/experiment-analysis/deep-dive/segments/)
- Eppo, *Copy SQL*：[链接](https://docs.geteppo.com/experiment-analysis/deep-dive/copy-sql/)
- Eppo, *Property Analysis*：[链接](https://docs.geteppo.com/experiment-analysis/deep-dive/property_analysis/)
- GrowthBook, *Dimensions*：[链接](https://docs.growthbook.io/app/dimensions)
- GrowthBook, *Metrics*：[链接](https://docs.growthbook.io/app/metrics)
- Amplitude, *Advanced Metric Use Cases*：[链接](https://amplitude.com/docs/en/feature-experiment/advanced-techniques/advanced-metric-use-cases)
- Amplitude, *Sequential Testing*：[链接](https://amplitude.com/docs/en/feature-experiment/under-the-hood/experiment-sequential-testing)
- Optimizely, *Experiment Results Page*：[链接](https://docs.optimizely.com/web-experimentation/docs/JDvF-optimizely-experiment-results-page)
- VWO, *Campaign Report Components*：[链接](https://help.vwo.com/hc/en-us/articles/36774774172313-Know-the-Components-of-Your-Campaign-Report)
- AB Tasty, *Data Explorer*：[链接](https://docs.abtasty.com/reporting-and-performances/data-explorer)
- Convert, *Experiment Report*：[链接](https://support.convert.com/hc/en-us/articles/204490289-experiment-report)
- PostHog, *Experiments / CUPED*：[链接](https://posthog.com/docs/experiments/cuped)

### 11.3 中国平台公开材料

- 字节跳动 AICon 2025 演讲者简介（Libra/DataTester）：[链接](https://aicon.infoq.cn/2025/shanghai/speaker/9508)
- 《AI 时代实验平台演进之路》InfoQ 报道：[链接](https://www.infoq.cn/article/judnchxzzbp34zbezfkx)
- 字节 AICon 2024《LLM 在 A/B 实验平台的应用探索》：[链接](https://aicon.infoq.cn/2024/beijing/speaker/8593)
- 字节 CUPED/ITR 内部实践报道（IT168，2024-10）：[链接](https://server.it168.com/a2024/1023/6866/000006866793.shtml)
- 淘天通天塔 Fluss 实践（阿里云开发者社区，2025-07）：[链接](https://developer.aliyun.com/article/1672360)
- 美团 BETA 分析引擎（2024-09）：[链接](https://tech.meituan.com/2024/09/09/New-Generation-Analysis-Engine-Driving-Data-Decisions.html)
- 美团可信实验白皮书（2025-05）：[链接](https://tech.meituan.com/2025/05/22/meituan-AB-Online-Controlled-Experiment-01.html)
- B 站北极星与 ClickHouse RBM：[链接](https://www.bilibili.com/read/cv21106590/)
- 知乎 AB2.0 从 ClickHouse 预计算迁 Doris 的公开分享：[链接](https://www.sohu.com/a/848315597_121665362)

### 11.4 交互、可访问性与设计

- W3C, *ARIA Authoring Practices: Grid Pattern*：[链接](https://www.w3.org/WAI/ARIA/apg/patterns/grid/)
- W3C, *WCAG 2.2: Use of Color*：[链接](https://www.w3.org/WAI/WCAG22/Understanding/use-of-color.html)
- W3C, *WCAG 2.2: Reflow*：[链接](https://www.w3.org/WAI/WCAG22/Understanding/reflow.html)
- Nielsen Norman Group, *Progressive Disclosure*：[链接](https://www.nngroup.com/articles/progressive-disclosure/)

### 11.5 引擎与存储

- ClickHouse, *Incremental Materialized Views*：[链接](https://clickhouse.com/docs/materialized-view/incremental-materialized-view)
- ClickHouse, *Bitmap Functions*：[链接](https://clickhouse.com/docs/sql-reference/functions/bitmap-functions)
- Apache Doris, *Materialized View Overview*：[链接](https://doris.apache.org/docs/query-acceleration/materialized-view/overview)
- StarRocks, *Asynchronous Materialized Views*：[链接](https://docs.starrocks.io/docs/using_starrocks/async_mv/)
- BigQuery, *Materialized Views*：[链接](https://cloud.google.com/bigquery/docs/materialized-views-intro)
- Snowflake, *Materialized Views*：[链接](https://docs.snowflake.com/en/user-guide/views-materialized)
- Apache Druid, *Design*：[链接](https://druid.apache.org/docs/latest/design/)

---

<div class="ab-callout">
  <div class="t">关于本页</div>
  <p>本页是《AB 测试平台全网竞品与方案调研》2026-10 版的独立专题，基于 8 路并行调研、20 份 DataTester 官方文档、公开论文与工程博客整理。界面演示中的数据全部虚构，仅用于说明信息架构与交互，不代表任何厂商的真实产品。厂商功能、默认参数与价格以其最新文档为准；涉及内部平台的部分已标注「推断」，不应作为采购或架构决策的唯一依据。</p>
</div>
