指南
在线实验(A/B 测试)
你的离线比较说新版本更好。生产环境中的 A/B 测试向真实用户提出同一个问题。你自己的路由器把单位(用户或会话)随机分到两个组;oloproof experiment 读取它的日志,并用与其他所有规则相同的四种状态作答。该方法已在声明的条件下通过独立审计的准入:observed_until 是你对结果日志提取时刻的陈述,单位是独立随机分配的,任何单位的结果都不取决于另一单位所在的组,分配比例变化期间结果没有漂移,并且每次查看都读取完整日志。超出这些条件,答案不受保证。
日志与声明
两个文件,CSV 或 JSONL:一个分配日志,每个单位一行(你声明的单位列,以及 arm);一个结果日志,包含单位及其 value。
experiment:
name: checkout-v2
unit: user
allocation: {control: 0.5, treatment: 0.5}
control: control
treatment: treatment
assignments: logs/assignments.csv
outcomes: logs/outcomes.csv
kind: rate
rules:
- {id: lift, kind: superiority}
- {id: no-harm, kind: non_inferiority, margin: 0.01}oloproof experiment experiment.yaml --policy release.yaml --jsonkind: mean 接受一个声明的 range: [low, high];direction: max 把更低视为更好。没有结果行的已分配单位视为缺失,并在每一侧按其最差值界定,除非 missing_outcome: zero 声明没有行即为零。为每个单位都记录一行,包括零:只包含已转化者的转化日志会把其他每个单位读作缺失,答案将停留在 INSUFFICIENT_EVIDENCE。补零假设每个计入单位的结果窗口都已关闭;一小时前才分配的单位还没有转化,把它算作零会偏向转化更快的那一组。声明 outcome_window_hours、as_of 和 observed_until(提取结果日志的时间),并在分配日志中加入 assigned_at 列,则只计入窗口在 as_of 之前关闭的单位;缺少它们时,无论哪种监测方式,missing_outcome: zero 都会被拒绝。每个时间都要带时区偏移或 Z 书写(2026-10-11T00:00:00Z);两者都没有的时间会被拒绝。as_of 不得晚于 observed_until,两者都不得在未来:提取之后的结果不在日志中。窗口决定问题:48 小时的窗口回答“48 小时内是否转化”,因此它必须覆盖你所指结果的延迟。单位 ID 在去除空格后按文本比较,42.0 读作 42。退出码取最差规则的退出码:0 PASS,1 FAIL,3 INSUFFICIENT_EVIDENCE,4 MANUAL_REVIEW。
它先检查什么
- 样本比例。 各组的单位数与声明的分配进行检验(两组用精确二项检验,更多组用卡方,阈值 0.001)。不匹配会让每条规则变为 MANUAL_REVIEW:分流出错意味着各组不再可比,而更多同类数据也修复不了它。在读任何差值之前先找出原因(丢失用户的重定向、只作用于一个组的机器人过滤)。
- 一个单位出现在两个组。 分配发生了泄漏;每条规则读作 MANUAL_REVIEW。
- 一个单位有多条结果行。 拒绝,因为同一用户的事件并不独立。声明 aggregate: unit_mean,让每个单位自己的均值作为它的结果:此时答案关于平均用户,而非平均事件。
- 空组。 在有结果之前为 INSUFFICIENT_EVIDENCE。
- 在 missing_outcome: zero 下,不对应任何已分配单位的结果行。 零依赖于连接,因此连接出错会把真实单位读作零;在 ID 一致之前,每条规则都为 MANUAL_REVIEW。在默认设置下,它们被计数并排除在外。
它如何判定
每个组的均值获得 Oloproof 对单次运行已在使用的区间(比率用精确 Clopper-Pearson,其他情况用基于下注的有界均值),各占一半的误差预算,差值由两者相反的端点界定。它在任何样本量下都成立,比教科书上的正态区间更宽。优效性规则在整个区间高于零时通过;非劣效性规则在其下端不低于负的界值时通过。
monitoring: anytime 对两个组都使用下注区间,无论你查看多频繁、何时停止都成立。前提是每次查看都传入截至那一刻的完整日志:读过之后,绝不要按时段删除或筛选行。默认的 fixed 在你计划的样本量处读取一次。
多个处理组
声明 treatments: [b, c] 来代替 treatment:,并为每条规则指定它所比较的处理组(treatment: b)。m 个组中每个组的区间取 1 - alpha/m,因此由联合界,每个处理组减去对照组同时被覆盖:每个处理组一条规则,各一项主张,整个族一起成立。每个区间都比两组时更宽,因为每个组都要为其他组付出代价。有多个处理组时,报告在通过每条点名它们的规则的处理组中点名最佳者,并说明它是否与其他每个通过的处理组分开:每个差值由同一组同时区间界定,不含零。并列者保持声明的顺序,从不分开。样本比例检查已经读取每个组。联合保证覆盖的是一个实验文件中的各组:把处理组拆分到多个文件就放弃了它。
比率指标
点击率是点击数除以会话数,而一个有很多会话的用户并不是很多个独立用户。在每个单位一行上声明该比率,并给出每个单位的值都落在其中的范围:
ratio: {numerator: clicks, denominator: sessions, numerator_range: [0, 50], denominator_range: [1, 50]}
aggregate: unit_sum # only if a unit has several rows: they are added估计目标是每个组的平均分子除以其平均分母。两个均值都由已认可的区间界定,各占其应得的误差预算份额,比率则通过对它们的端点相除得到,因此在任何样本量下都成立,不依赖正态近似。区间触及零的分母不给出区间。超出其范围的值是一个点名该单位的配置错误,绝不截断。Delta 方法的区间通常更窄,显示在旁边,从不判定。
测试之前的协变量
一个与测试前测得之物(上个月的支出、上周的会话)相关的结果,在去掉它之后波动更小。提供每个单位在测试前的值,以及一个在读取本测试结果之前就已固定的系数:
covariate: {values: logs/pre_period.csv, range: [0, 500], theta_from: logs/history.csv}判定的结果是 Y - theta (X - c)。theta 要么是声明的(theta:,可选 center:,默认为范围的中点),要么在测试之前某个时段的历史文件上拟合(covariate 与 outcome 列),绝不在本测试自己的结果上拟合。由于 X 是在分配之前测得的,并且哪些单位有 X 也是在分配之前就确定的,调整后的差值有相同的估计目标。文件中没有值的单位不做调整。一个有效的调整仍可能比不调整更宽,因为调整后结果的范围更宽,所以报告同时显示两个区间并说明哪个更窄;它不声称任何节省。
新奇与干扰,只做显示
novelty: {exposure_column: exposed_at, time_column: at, days: 7} 从分配日志读取每个单位的首次曝光,从每条结果行读取其时间,并显示曝光后前 days 天与之后的差值。一个已判定的早期差值,配上一个未判定或相反的后期差值,会被标为"可能是新奇效应"。这种拆分从不判定规则:在某个时段没有行的单位被排除在该时段之外,而不是按最坏情况界定。它每行取一个结果,不接受比率或协变量。
cluster_column: team 统计持有多个组单位的团队,并询问一个单位的结果是否可能依赖另一个单位所在的组。如果可能,请按团队随机化,并把它声明为单位。
多个处理组、比率和协变量已于 2026 年 11 月 3 日经独立审计及其确认认可,条件与两组相同。
离线与在线
指定离线比较及其指标(offline_comparison: <id>,offline_metric: pass_rate),答案会报告两个已判定的方向是否一致。这只做报告,从不判定任何事:不一致是去检查测试集的理由,而不是对发布的裁决。
陷阱
- 中途偷看。 每天读取固定期限的测试并在好日子停下,会放大虚假的胜利。请规划样本量,或声明 monitoring: anytime。
- 新奇与学习。 用户会对任何新东西做出反应,然后趋于平稳。第一周的提升可能消退;运行足够长的时间以覆盖你的用户周期,并声明 novelty: 以查看拆分。
- 干扰。 区间假设一个单位的结果不依赖于另一个单位所在的组。共享库存、交易市场、社交功能或被一个组预热的缓存都会打破这一点;此时请按更大的单位(一个地区、一个团队)随机化,并声明 cluster_column: 以查看各簇混合的程度。
- 分流变化下的漂移。 区间假设分配在测试期间保持不变,或在分配变化时结果没有漂移。从 10% 逐步提高到 50%,或在一个工作日和一个周末先 90/10 后 10/90,会让每组对各时段的加权不同,并把时间效应混入差值;样本比例检查读取的是汇总计数,看不到这一点。请保持分流固定,或只根据逐步提高之后的时段做决定。
- 更换单位。 用同一单位随机化和分析。随机化用户却把会话当作独立计数,会错误地收窄区间。
这无法告诉你的
- 结果是否适用于测试时间窗、地区或流量之外的用户。
- 关于测试前未声明的指标的任何事;事后选择的指标只是描述。
- 你的路由器是否真的做了随机化:样本比例检查能发现大的故障,发现不了细微的。
- 未通过的处理组中哪个最好:只有通过的处理组才排名。分层分配和轮换(switchback)设计尚未构建。