把新提示词和旧提示词各跑一遍再比较平均分看起来像 A/B 测试但这通常只能算离线对比。真实线上实验面对的是用户反复访问、同一会话多轮对话、模型随机输出、检索库变化、限流与超时以及“回答更好但成本翻倍”这种多目标冲突。若分流不稳定、指标在看到结果后才修改或者每天盯着显著性随时停止最后得到的数字很可能无法支持因果结论。本文实现一条最小但完整的实验链路先写实验假设与指标契约再按用户稳定分流业务指标、质量指标和安全护栏同时采集实验结束后以用户为分析单位计算效果差异和区间任何严重安全或可用性退化触发快速回滚。文中样本数据均由程序明确构造仅用于演示统计方法不代表任何线上产品效果。1. AI 实验和普通按钮实验有什么不同按钮颜色实验的处理通常很明确用户看到红色或蓝色按钮。AI 回答实验的处理是一整条链路可能包含系统提示词、模型版本、温度、检索参数、工具集合、内容护栏和后处理。只改提示词却让两个实验组走不同检索索引结果就无法归因上线期间知识库频繁更新也可能使先后进入的用户面对不同世界。生成结果还有随机性。同一用户问同一句话两次输出未必相同而用户体验由整个会话组成第一轮回答会影响下一轮提问。如果按“每次请求”随机分组一个会话会在 A、B 之间跳动既污染体验也破坏独立性。多数对话产品更适合按用户稳定分流并让实验版本在会话创建时固定下来。评价信号也更复杂。点击、任务完成和再次追问来自真实行为但可能稀疏且受界面影响LLM 自动评分规模大却有位置偏差和漂移人工审核可信但昂贵。一个合理实验会把业务行为当主要结果把人工与自动评测当诊断信号同时设置延迟、错误率、成本和安全事件等护栏。实验不是“上线后看看”而是一次预先承诺。开始前应写清目标人群、随机化单位、处理差异、主要指标、护栏指标、最小可检测效应、预计样本量、最长运行时间、排除规则和停止规则。结果出来后再换指标等于不断射箭再画靶心。2. 指标树先保证没有伤害再谈平均质量指标可分为四层。第一层是业务主要指标例如用户是否完成任务、是否解决问题、是否需要转人工。每个实验最好只有一个明确主要指标否则多个指标中总能挑出一个显著改善。第二层是质量诊断例如事实正确率、引用有效率、人工偏好或结构化输出成功率。第三层是体验指标例如首 Token 延迟、总延迟、重试率和中断率。第四层是不可妥协的护栏严重安全事件、隐私泄露、工具越权、整体错误率和单次成本上限。护栏与普通指标的区别在于动作。主要指标不显著结论可能是证据不足护栏越界动作通常是停止扩量或回滚。安全事件还不能只依赖统计显著性一次确认的高严重度泄露已经具有业务意义没有必要等到样本更多。成本指标要定义口径。按请求平均成本容易被大量短请求稀释更实用的口径可能是“每个成功任务成本”或“每个活跃用户日成本”。延迟应看中位数和尾部而不仅是平均值少量极慢请求会直接破坏体验。错误率则要区分模型服务失败、工具失败、解析失败和业务拒答便于定位根因。质量指标同样要防代理目标。让回答更长可能提高自动评分却增加延迟和用户阅读负担让模型更积极调用工具可能提高完成率也可能增加越权风险。指标树的作用不是让所有数字都上涨而是明确什么是目标什么是解释什么是不能交换的底线。3. 稳定分流同一个用户始终看到同一版本不要使用语言内置的hash()做跨进程分流。某些语言会随机化哈希种子同一标识在不同进程或重启后可能得到不同结果。更简单可靠的方法是把实验键、稳定用户标识和分流盐拼接后使用密码学哈希转换成固定桶号。盐不应该是秘密但必须固定并版本化。实验键区分不同实验防止所有实验把同一批用户都分到 B分配结果最好在首次曝光时落库后续分析以曝光日志为准而不是事后重新计算。匿名用户可用稳定设备标识但需遵守隐私政策无法稳定识别时应明确实验单位变成会话并避免把会话级结果当作用户级独立样本。否是是否用户或会话是否符合实验条件默认版本稳定哈希分桶对照组 A实验组 B记录首次曝光业务/质量/护栏事件数据质量检查用户级统计分析收益且护栏通过?逐步扩量保持或回滚下面的程序提供稳定分桶、白名单排除和权重校验。它只依赖标准库可直接运行自检。生产环境还需把首次曝光写入不可变事件表包含实验键、版本、分组、用户标识的脱敏值、时间和配置哈希。# assignment.pyfrom__future__importannotationsimporthashlibfromdataclassesimportdataclassdataclass(frozenTrue)classExperiment:key:strsalt:strcontrol_weight:int50treatment_weight:int50def__post_init__(self)-None:ifself.control_weight0orself.treatment_weight0:raiseValueError(权重不能为负数)ifself.control_weightself.treatment_weight!100:raiseValueError(两组权重之和必须为 100)defbucket(user_id:str,experiment:Experiment)-int:ifnotuser_id.strip():raiseValueError(user_id 不能为空)materialf{experiment.key}:{experiment.salt}:{user_id}.encode(utf-8)digesthashlib.sha256(material).digest()returnint.from_bytes(digest[:8],big)%10_000defassign(user_id:str,experiment:Experiment,eligible:boolTrue)-str:ifnoteligible:returncontrol_not_enrolledthresholdexperiment.control_weight*100returncontrolifbucket(user_id,experiment)thresholdelsetreatmentdefdemo()-None:expExperiment(keyanswer-v4,salt2026-09-fixed)first[assign(fuser-{i},exp)foriinrange(1000)]second[assign(fuser-{i},exp)foriinrange(1000)]assertfirstsecondassertassign(internal-tester,exp,eligibleFalse)control_not_enrolledassertset(first){control,treatment}print({name:first.count(name)fornameinset(first)})if__name____main__:demo()程序打印的组数只是确定性哈希在一千个演示标识上的结果不是实验结论也不要求恰好五五开。真正上线后应做样本比例失配检查实际进入各组的人数是否显著偏离配置比例。严重偏离通常意味着曝光埋点丢失、资格过滤在分组后不对称执行、缓存命中绕过某个版本或分流代码不一致。出现这种情况应先修数据链路不要继续解读业务效果。4. 随机化单位、分析单位与污染若按用户随机化就应尽量按用户聚合分析。把一个重度用户的一百次请求当成一百个独立样本会让标准误过小使结果看起来比实际更确定。可以先为每个用户计算实验期内的任务成功率、平均成本或是否至少成功一次再比较两组用户若业务必须使用请求级模型应采用聚类稳健标准误或分层模型。企业产品还可能存在组织内污染。同一团队成员共享答案、模板和知识按个人随机会让 A 组行为影响 B 组。此时可以按租户或团队随机化但独立单位数量会显著减少需要更长时间或更大覆盖范围。实验设计必须围绕因果干扰关系而不是只选择最方便的 ID。跨实验污染也要控制。两个实验同时修改系统提示词组合效果可能不同于各自单独效果。简单方案是把同一层的互斥实验放入命名空间一个用户在该层只进入一个实验确实需要交叉时用因子实验并预先分析交互项。不能等结果冲突后才发现同一用户同时经历了三个版本。机器人、内部测试账号、离线回放和监控探针应在资格规则中预先排除。排除必须与实验组无关并在分组前执行。基于实验后行为排除用户例如“删除出现错误的人”会直接引入选择偏差。5. 曝光日志是事实源不是请求日志的附属品用户被分到 B 不代表真正看到了 B。缓存可能返回旧答案模型调用可能在展示前失败功能开关也可能覆盖分配。实验分析应区分“被分配”“实际曝光”和“产生结果”。主分析通常遵循意向治疗原则按原始分配比较所有合格用户避免只分析成功曝光者带来的偏差同时可提供实际曝光分析作为诊断但必须说明其选择条件。曝光事件至少包含实验键、实验版本、分组、随机化单位、时间、请求或会话标识以及处理配置哈希。业务结果事件通过稳定标识关联曝光。一个请求若多次重试只应按照预定规则计算一次结果不能让失败重试扩大样本量。时间窗口也需预先确定。任务完成可能在回答后几分钟发生付费转化可能在几天后发生。窗口过短会漏记过长会把后续其他体验混入。采用事件时间而非入库时间并处理迟到事件实验结束后留出固定成熟期再冻结分析数据。日志不应保存不必要的原始敏感提示词。统计链路通常只需意图类别、长度桶、状态码和脱敏标识需要抽检原文时采用受控存储、最小权限和保留期限。实验便利不能成为无限收集数据的理由。6. 样本量先问“多大改善值得上线”显著性与样本量紧密相关。流量足够大时极小差异也可能显著却没有业务价值流量小时实际有价值的改善也可能暂时不显著。开始前应定义最小可检测效应也就是小于这个幅度即使存在也不值得为它承担迁移成本和风险。二元指标的样本量依赖基线比例、期望效应、显著性水平和统计功效。连续指标还依赖方差。基线与方差最好来自实验前稳定周期而不是凭感觉填写。若主要指标很稀疏可选择更近端且已验证的代理指标但需要证明代理与最终目标有关。实验应覆盖完整业务周期。工作日和周末、白天和夜间可能有不同用户。仅跑到样本量满足就立刻停止可能恰好捕获短期异常。预先设置最短周期与最长周期并处理节假日、促销和大规模故障等外部冲击。多个版本同时与对照比较会增加误报概率。应预先限制主要比较或使用适当的多重检验控制。不要在几十个切片中搜索显著结果后把偶然波动包装成针对某类用户的洞察切片分析最好用于生成后续实验假设。7. 一个不依赖第三方库的二元指标分析器下面程序按用户级成功或失败计算两组比例差、相对提升、两侧近似检验和 Wilson 区间。演示数据由固定种子的伪随机程序生成只为展示代码输出它不是产品实验结果。小样本、极端比例、复杂聚类或序贯设计应使用经过验证的统计包并由统计人员复核。# analyze_binary_ab.pyfrom__future__importannotationsimportmathimportrandomfromdataclassesimportdataclassdataclass(frozenTrue)classArm:name:strsuccesses:inttotal:intdef__post_init__(self)-None:ifself.total0ornot0self.successesself.total:raiseValueError(成功数与样本数不合法)propertydefrate(self)-float:returnself.successes/self.totaldefnormal_cdf(value:float)-float:return0.5*(1.0math.erf(value/math.sqrt(2.0)))defwilson(successes:int,total:int,z:float1.95996398454)-tuple[float,float]:ratesuccesses/total denominator1z*z/total center(ratez*z/(2*total))/denominator marginz*math.sqrt(rate*(1-rate)/totalz*z/(4*total*total))/denominatorreturncenter-margin,centermargindefcompare(control:Arm,treatment:Arm)-dict[str,float]:pooled(control.successestreatment.successes)/(control.totaltreatment.total)standard_errormath.sqrt(pooled*(1-pooled)*(1/control.total1/treatment.total))differencetreatment.rate-control.rate z_scoredifference/standard_errorifstandard_errorelse0.0p_value2*(1-normal_cdf(abs(z_score)))return{control_rate:control.rate,treatment_rate:treatment.rate,absolute_difference:difference,relative_lift:difference/control.rateifcontrol.rateelsemath.inf,z_score:z_score,p_value:p_value,}defdemo()-None:# 固定种子的演示数据不代表真实线上效果。rngrandom.Random(20260921)control_events[rng.random()0.40for_inrange(2000)]treatment_events[rng.random()0.42for_inrange(2000)]controlArm(control,sum(control_events),len(control_events))treatmentArm(treatment,sum(treatment_events),len(treatment_events))print(compare(control,treatment))print(control Wilson interval:,wilson(control.successes,control.total))print(treatment Wilson interval:,wilson(treatment.successes,treatment.total))if__name____main__:demo()近似检验的 p 值回答的是在零差异假设和模型假设成立时观察到当前或更极端差异有多不寻常。它不是“B 更好的概率”也不衡量收益大小。决策时必须同时看绝对差异、相对差异、区间、业务价值和护栏。如果实验使用用户级随机化代码里的成功数应来自每个用户一个二元结果。若一个用户有多次任务可预先定义“至少一次成功”“首个合格任务成功”或“用户任务成功率达到阈值”等聚合规则。不同规则回答不同问题应在实验开始前固定。8. 为什么每天看一次 p 值会增加误报经典固定样本检验假设分析时点预先确定。若每天查看结果一旦 p 值低于 0.05 就停止等于进行了多次获胜机会整体误报率会高于名义水平。这种做法在 AI 产品中特别常见因为上线看板随时可见。有三种朴素处理。第一种是坚持固定样本和固定结束时间中途只看护栏不根据主要指标提前宣布成功。第二种是预先设计有限次数的组序贯分析为每个时点分配错误预算。第三种使用始终有效的序贯方法但必须完整实现其假设和停止规则不能把普通 p 值改个名字。中途因护栏恶化而停止不属于“偷看获胜”。安全、错误率和成本越界本来就是预设停止条件。关键是区分“为了保护用户而停”和“为了抓住一个好看的瞬间而停”并在实验协议与日志中记录原因。实验长时间没有显著结果也不能随意延长直到出现显著。到达预设最长时间后应报告区间它是否仍包含值得关注的正向和负向效应如果区间太宽说明流量或指标敏感度不足如果区间已经排除有意义改善就可以停止投入。9. A/A 测试和实验健康检查上线新实验平台前先做 A/A 测试两个组运行完全相同配置但经过完整分流、曝光、事件与分析链路。预期不是每个指标都完全相等而是在长期重复中差异符合随机波动样本比例合理用户不会跨组埋点没有系统性缺失。A/A 还能发现缓存键遗漏。如果缓存只按问题文本而不包含实验版本A 用户生成的答案可能被 B 用户复用两个组会被稀释。会话状态、检索结果缓存和工具执行缓存也应检查是否包含必要版本维度。正式实验每天至少检查资格人数、分配人数、实际曝光人数、各组事件完整率、跨组用户数、配置版本数和样本比例失配。若实验组比对照组更容易在曝光前失败只看已曝光用户会把这部分伤害删除因此分配到曝光的漏斗必须保留。还要确认模型供应商或路由层没有在实验期间悄然换版本。请求记录中应保存可获得的模型快照、区域、网关配置和提示词哈希。无法锁定时至少保证两个组同时随机进入相同基础设施让外部变化对两组尽量对称。10. 快速回滚要在实验前准备回滚不是把代码重新部署一次。最可靠的方式是服务端功能开关分流层读取一个版本化配置紧急时将实验流量权重设为零让新请求立即回到已验证对照。配置变更需要鉴权、审批、审计和可观察的生效状态客户端缓存应设置合理过期时间。会话中的回滚需要特别定义。强制正在进行的会话切回旧提示词可能让上下文格式不兼容继续保持 B又会让风险持续。一般做法是安全事故立即终止相关工具权限并切换普通质量退化则让存量会话按旧版本完成、新会话回到 A。具体策略应在实验协议中写清。触发回滚的护栏应包含阈值、窗口、最小事件数和严重度。例如连续窗口错误率超限可自动降流一次确认的敏感数据泄露可立即全停。自动化动作要有防抖和人工接管避免监控噪声让配置来回振荡。回滚后仍需保留实验记录和失败样本不能删除不漂亮的数据。记录谁在何时因什么指标执行了什么动作确认流量是否回落、缓存是否清空、工具凭证是否撤销。只有这样复盘才能分清模型缺陷、基础设施故障和监控误报。11. AI 实验的典型失败模式第一类是分流单位错误请求级随机导致同一用户跨组。修复为用户或会话级稳定分配并以同一单位分析。第二类是只看自动评分裁判偏好新版本更长的文风用户任务成功却没改善。修复为预先指定业务主要指标自动评分只作诊断并定期人工校准。第三类是存活者偏差仅分析成功返回的回答忽略 B 组更多超时。修复为保留从分配到曝光再到结果的完整漏斗主分析按原始分配。第四类是指标污染团队看到初步结果后修改“成功”定义。修复为版本化指标 SQL 或计算代码任何变更都产生新实验解释。第五类是新奇效应。用户第一次看到更热情、更长的回答可能更愿意点赞但几周后厌烦。高频功能应观察效果随实验天数和用户使用次数的变化。第六类是学习效应用户逐渐适应某个交互方式切换版本后历史经验继续影响行为。必要时使用新用户队列或更长洗脱期。第七类是网络效应或共享知识污染。团队成员互相复制 AI 输出个人级随机失效。按组织随机或明确实验只估计“可存在干扰时的实际部署效果”。第八类是成本结算延迟Token、工具和外部搜索费用在不同系统异步到达。实验结束前等待数据成熟并按配置与请求关联核对。第九类是只报告相对提升。基线从 1% 到 1.1% 可称提升 10%实际仅增加 0.1 个百分点。始终同时报告两者及区间。第十类是把“不显著”写成“两组一样”。不显著只说明当前数据无法排除零差异只有区间足够窄并落在业务等价范围内才能支持近似等价判断。12. 从小流量到全量的决策流程实验前先通过离线回放、单元测试、红队样本和人工检查避免把明显错误送到用户。随后以极小流量验证系统健康重点检查错误、权限、日志和成本不急着判断业务提升。健康后逐级扩量每一级都等待核心护栏稳定再进入预设的正式实验流量。正式分析时先验证数据质量实验版本唯一、分配稳定、样本比例正常、跨组为零或可解释、结果窗口成熟。再看护栏任何不可接受退化优先处理。最后分析主要指标的效果与区间质量和切片指标用于解释原因而不是替换预设结论。若 B 获得有业务意义的改善且护栏通过也不必一次切到百分之百。逐步扩大并继续观察基础设施容量与长尾风险。全量后保留对照哨兵或采用时间序列监控确认效果没有因用户构成、模型升级或知识库变化而消失。若结果不确定最诚实的结论是“当前证据不足”。检查区间与数据质量决定继续到预设上限、改进指标或重新设计更强差异的版本。不要把每次实验都包装成胜利可靠的实验系统的价值恰恰包括及时终止没有价值的改动。13. 如何验证指标真的反映用户价值实验平台能精确计算指标不代表指标选对了。点赞率容易受按钮位置、用户表达习惯和新奇感影响会话长度增加可能意味着用户更投入也可能意味着回答一直没解决问题。上线前应把代理指标与人工任务成功或真实业务结果做关联验证并观察这种关联在不同意图和用户群中是否稳定。建立指标时先写“失败解释”。如果 B 组点赞更高还可能是什么原因可能回答更讨好可能弹窗更显眼也可能差评事件丢失。针对每种替代解释增加最小诊断信号。例如同时看任务完成、再次追问、转人工和人工抽检而不是继续创造一个更复杂的综合分。自动裁判得分适合高频诊断但裁判本身必须固定版本并用人工集校准。实验期间更换裁判提示词会让前后数据不可比若必须修复应生成新指标版本并重新计算两组而不能只从当天起采用新标准。裁判输入必须匿名避免它知道哪个是实验版本。用户反馈存在选择偏差。愿意点赞的人不是所有用户的随机样本沉默也不等于满意。可以在小比例流量中随机触发轻量调查并控制打扰频率也可以用任务后的可观察行为做补充。任何隐式信号都要说明假设不能把“用户没有继续提问”直接解释为问题已解决。对成本和延迟指标要与用户目标对齐。B 组回答更长导致总耗时增加但首个可用内容更快体验可能仍改善反之流式首字很快却长时间不结束也会让工具调用迟迟不能完成。应按链路分解排队、首 Token、生成、工具和后处理耗时并用尾部分位数发现少数严重卡顿。14. 处理缺失、异常与实验期间故障现实数据不会整齐。结果事件可能迟到、重复或丢失用户可能跨设备登录模型供应商可能短暂故障。分析前建立数据质量表按组统计分配、曝光、请求、有效响应和成熟结果数量。若某一环节的缺失与分组相关简单删除缺失记录会造成偏差。对于模型超时应把它视为实验结果而非无效样本。用户拿不到回答就是失败即使无法计算回答质量。业务主要指标按预设规则记为失败或保留在意向治疗分析中质量评分可以只对可评分回答计算但必须同时报告覆盖率不能让一个经常失败的模型靠少量幸存答案取得高分。极端成本和延迟值不要看到后就随意截断。截断规则应在实验前由系统限制或统计协议定义并对两组一致执行。若异常来自真实死循环它正是需要发现的风险若来自埋点错误则修复数据并记录排除原因。所有排除数量按组公开。实验期间发生全站故障时若两组同等受影响配对随机化通常仍保留一定可比性但指标方差会变大若故障只影响 B 依赖的新服务那就是处理效果的一部分不应删除。是否延长实验应依据预设最长周期与数据成熟规则不根据结果好坏决定。15. 从结论到发布还要经过一次风险评审统计报告完成后把结论翻译成具体部署动作。列出主要指标的绝对变化和区间、所有护栏、关键分层、样本比例检查、运行周期以及已知限制。评审者应能从报告追到指标代码、曝光版本和原始聚合表避免只有一张截图。如果决定上线先确认容量。实验流量下正常不代表全量下工具配额、缓存和模型限流仍正常。根据每用户调用次数估算峰值做受控负载验证并为外部依赖设置限流、超时和降级。扩量阶段沿用同一护栏与回滚开关不能因为“实验已经赢了”就停止观察。上线后保留结果复核窗口。实际全量用户构成可能与实验合格人群不同其他功能也可能同时变化。若效果消失先检查流量组成和实现一致性再讨论模型退化。实验结论只对当时定义的人群、处理和环境有效不是永久保证。如果不发布也要保存失败知识哪种改动、针对哪个假设、在哪些指标和切片上失败。下一次团队遇到相似想法时可以直接复用证据。成熟实验文化不是赢得更多实验而是用更少用户成本排除错误方向。16. 上线前检查清单确认实验假设、主要指标和最小可检测效应已经冻结随机化单位与分析单位一致分流使用稳定标识和固定哈希资格过滤在分流前执行实验版本进入缓存键曝光事件能证明用户实际看到版本重试不会重复计数指标计算有版本护栏有动作阈值严重安全事件可立即停流停止规则和最长周期明确没有通过每天偷看普通 p 值择时结束成本、尾延迟和错误率均按组统计回滚开关已演练会话中途策略已定义所有配置变更留有审计记录。一套可信的 AI A/B 测试不是一个分组字段加一张显著性报表。它是一条从稳定分配、真实曝光、指标契约、统计边界到可验证回滚的完整链路。先把因果问题和安全底线写清楚再让数据回答问题才不会把模型随机性和平台噪声误认成产品进步。参考资料NIST/SEMATECH e-Handbook of Statistical MethodsMicrosoft ExP Platform: Controlled Experiments at ScaleTrustworthy Online Controlled Experiments, Cambridge University PressPython hashlib 官方文档SciPy 统计检验官方文档
