报告里写『通过率 92%』,等于只报了一半:把 AI 测试数字连置信区间一起交出去

简介: AI测试通过率本质是分布而非单点,盲目报告单一数值易误导决策。本文倡导用Bootstrap法计算95%置信区间(如“92%,95%CI [86%, 95%],n=210”),将不确定性显性化:区间宽度反映数据可靠性,重叠判断替代主观“显著”断言。纯标准库实现,可无缝嵌入CI流水线——让质量报告真正说出“我有多确定”。

同一套回归用例,周一早上跑完是 88%,你不放心又跑了一次,变成 94%。周报你贴了 94%——贴 88% 那次,评审会上要被人追问『怎么又掉了』;贴 94% 这次,没人记得它统共就跑了十七八条。数字没撒谎,你只是从一摞结果里挑了最顺眼的那一颗珠子。

AI 应用的通过率、稳定性,天生是一个分布,不是一个点。模型输出的随机性、用例里那一两条边界抖动,都会让『同一次改动』每次跑出来的通过率在一个带子里晃。报告只交一个点,是系统性地把『我其实没那么确定』这件事抹平了。正确做法,是把每个关键数字连它的不确定度一起交出去。

一、把区间交出去:通过率 X%,95%CI 也要一起写

先说最小动作。你手上有一组通过记录——每条用例跑过记 1、没过记 0,或者你把多次运行的通过率攒成一列。别只算平均,用 bootstrap 从这组记录里有放回地重采样几千次,每次算一个通过率,把这一堆通过率排序,取中间 95% 的两个端点,就是置信区间。报告里那行字,于是从『通过率 92%』变成『通过率 92%,95%CI [86%, 95%],n=210』。读者第一次能看见这个数字到底有多『实』。

呈现口径 读者会得出什么结论 什么时候会误导
裸点估计『通过率 92%』 系统稳定在 92%,可以直接跟 95% 的放行线比 n 很小或多次波动时:一个数盖住了它其实只跑了十几条
点 + 区间『92%,95%CI [86%, 95%],n=210』 真实值大概率落在这个带里,够不够格卡线一眼能判 几乎不误导;只需提醒一句:区间说的是『当期真值』,不是『下次跑分落点』
两版区间重叠比较 两次到底是不是『真的不一样』 只报两个点就下『显著提升 / 明显退化』:两个区间其实大面积重叠

bootstrap 是公开统计方法,不用连任何外部服务,纯标准库就能跑——这也正是它适合长在流水线里的原因。

还有一层用 bootstrap 而不是背公式的理由:通过/失败是 0/1 数据,当真值偏向九成以上时,抽样分布明显左偏,用『±1.96×标准误』那套正态近似算出来的区间,在小样本下会越过 100%、甚至越过 0,覆盖率一塌糊涂。bootstrap 不假设正态,它把样本当成总体本身,重采样几千次,区间长成什么样完全跟着数据走——样本越小,它就越宽,这个『宽』恰恰是报告里最该被看见的诚实。

二、区间宽度本身就是一条质量结论

把那套十七八条的用例塞进脚本,跑出来是这个样子:周一那次『通过率 88%,95%CI [71%, 100%]』,重跑那次『通过率 94%,95%CI [82%, 100%]』。6 个点的差距,背后只是两条用例翻了个面——因为 n=17,一条用例的值就差不多占 6 个百分点,点估计当然站不稳。区间宽到 29 个点,等于报告在喊:这次样本太少,不足以单独支撑放行。这是一条过去被『92%』这种漂亮数字盖住的结论。

再换一套:同一套逻辑扩到 210 条,通过率还是 91%,可区间收紧到 [88%, 95%],宽度只剩 7 个点。同样是『九成通过』,一个宽到不敢签字、一个够到能拿去和 90% 的放行线比。宽度不是噪音,宽度是你本该写进报告的第二条结论。

顺带堵一个常被误读的地方:置信区间说的是『这批改动真实通过率大概率藏在哪』,不是『下一次再跑,通过率会落在哪』。前者是关于真值、关于『我有多确定』,后者是关于单次跑分的波动。报告里把区间按真值的意思写,它才能拿去当放行依据;一旦读者把它错当成下次跑分的预言,那句『95%CI [88%, 95%]』就会被理解成『下次跑一定在 88 到 95 之间』——那就不是同一件事了,卡线的锅也说不清。

【配图1插入位置:本小节之后】

三、比较两个数字,先看区间重不重叠

『新版本通过率 93%,旧版本 90%,提升 3 个点,建议升级』——这种话在报告里出现一次,就该被拦一次。把两次各 n=100 的结果丢进脚本:旧版 90% 落在 [84%, 95%],新版 93% 落在 [88%, 97%],两个区间重叠了将近八成。重叠到这个份上,3 个点的差完全在样本波动能解释的范围内,写『显著提升』就是把运气写成了能力。规矩很简单:新旧两个区间大幅重叠,就老实写『本次差异落在噪声范围内』;只有区间基本分离,才配得上『显著』这两个字。

反过来,当两个区间确实基本分离——比如新版下压到了旧版上界之上——那才敢理直气壮写『显著提升』,而且能顺带写清是怎么判的:一句『两次 95% 区间不重叠』,就能挡住所有『你这是不是运气』的口头争执。『显著』『明显』这类词,在报告里永远不该脱离动作单独出现;出现了,就得能回答『拿什么判的显著』。

四、报告里这几个字段,得并排站

区间不是孤立的一列,它得和几个字段捆在一起才读得懂。单看一个 [88%, 95%] 没意义,得知道它是 210 条跑出来的、得知道分母口径是同一批用例、得知道是哪一次运行。

字段 演示值 为什么必须并排出现
通过率(点估计) 91% 给个体感,但单独看会骗人
样本量 n 210 决定区间宽度的根,没了它区间无从算起
95% 置信区间 [88%, 95%] 点估计的可信带,能不能卡线看它
口径 同一用例集、同一配置 防拿不同分母、不同配置的数字横比
运行时间 2026-09-24 01:12 · #4471 防拿旧一次的数冒充这一次

口径和运行时间这两栏看着像摆设,其实卡的是最常见的翻车:把上次大样本的区间宽度,套到这次小样本的通过率上,或者拿三个月前那次的漂亮数字给今天背书。

五、跑一遍:纯标准库把区间算出来

下面这段只用标准库,喂进去的就是本文演示构造的通过记录,开箱即跑。接自家工程时,把 records 换成你 pytest 结果里每条用例的 0/1,或多次运行攒出的通过率列表即可。

# -*- coding: utf-8 -*-
"""pass_rate_interval.py —— 通过率连置信区间一起交(纯标准库,开箱即跑)

用法:python pass_rate_interval.py
输入一组 0/1 通过记录,bootstrap 重采样算 95% 置信区间,
输出报告用文案『通过率 X%,95%CI [a%, b%],n=Y』。数据均为演示构造。
"""
import random


def point_estimate(records):
    return sum(records) / len(records)


def bootstrap_ci(records, iters=10000, level=0.95, seed=20260924):
    """对 0/1 记录做 bootstrap:有放回重采样 n 次、每次算一个通过率,
    把通过率分布排序后取分位数当置信区间(percentile 法)。"""
    rng = random.Random(seed)
    n = len(records)
    means = sorted(sum(rng.choices(records, k=n)) / n for _ in range(iters))
    lo = int((1 - level) / 2 * iters)
    hi = int((1 + level) / 2 * iters) - 1
    return means[lo], means[hi]


def fmt_pct(x):
    return f"{x * 100:.0f}%"


def report_line(records, iters=10000):
    p = point_estimate(records)
    lo, hi = bootstrap_ci(records, iters=iters)
    return f"通过率 {fmt_pct(p)},95%CI [{fmt_pct(lo)}, {fmt_pct(hi)}],n={len(records)}", hi - lo


def overlap(a, b):
    """重叠宽度占较窄区间的比例:>0.5 视为『分不出胜负』,别写显著提升。"""
    inter = max(0.0, min(a[1], b[1]) - max(a[0], b[0]))
    narrowest = min(a[1] - a[0], b[1] - b[0])
    return inter / narrowest if narrowest else 1.0


def gen_demo_passes(n_true, n_total, seed):
    rng = random.Random(seed)
    recs = [1] * n_true + [0] * (n_total - n_true)
    rng.shuffle(recs)
    return recs


def main():
    print("== 场景A:同一套用例,样本很小,点估计站不稳 ==")
    for lab, rec in [("周一那次", gen_demo_passes(15, 17, seed=1)),
                     ("手快重跑那次", gen_demo_passes(16, 17, seed=2))]:
        line, width = report_line(rec)
        print(f"  {lab}:{line}(区间宽度 {fmt_pct(width)})")

    print("\n== 场景B:同一套逻辑扩到上百条,通过率没动,区间却收窄 ==")
    line2, width2 = report_line(gen_demo_passes(192, 210, seed=3))
    print(f"  {line2}(区间宽度 {fmt_pct(width2)})")

    print("\n== 场景C:新旧两版通过率,先过区间重叠关 ==")
    old, new = gen_demo_passes(90, 100, seed=4), gen_demo_passes(93, 100, seed=5)
    lo_old, hi_old = bootstrap_ci(old)
    lo_new, hi_new = bootstrap_ci(new)
    print(f"  旧:{report_line(old)[0]}")
    print(f"  新:{report_line(new)[0]}")
    ov = overlap((lo_old, hi_old), (lo_new, hi_new))
    verdict = "两区间大幅重叠,别写『显著提升』" if ov > 0.5 else "区间基本分离,可写『显著提升』"
    print(f"  重叠比例 {ov * 100:.0f}% → {verdict}")


if __name__ == "__main__":
    main()

两个刻意的处理值得点名。其一,bootstrap 固定了随机种子(seed=20260924),这样这份报告里的区间下次重算还是同一个——用随机方法去算一份要进报告的确定性数字,得先把重采样这层随机按住在报告里,不然『区间』本身又成了新的一颗珠子。其二,overlap 判的是『重叠宽度占较窄区间的比例』,不是简单看有没有交集;只要沾一点边就算分开太松,会把噪声差判成显著。脚本跑出来的三组数,就是前面几节引用的全部数字:n=17 两条宽到 [71%, 100%]、[82%, 100%],n=210 收到 [88%, 95%],新旧对比重叠 78% 判成『别写显著提升』。

六、挂进流水线:报告正文一行带区间

区间化这件事最好长在流水线里,否则又变成『想起来才做』。pytest 出结果之后加一步统计,直接写进 step summary:

- run: pytest --junitxml=report.xml
- run: python pass_rate_interval.py >> $GITHUB_STEP_SUMMARY

从此报告里那句通过率,天生带着它的区间和 n。谁想只贴那颗最顺眼的珠子,脚本第一行就把区间甩在他脸上。

写这行报告文案时,给个小的语序建议:先点估计给体感,再区间给幅度,最后 n 给底气——『通过率 91%(95%CI 88%–95%,n=210)』。别把区间放在最前面,读者抓不到锚;也别把 n 省在文末脚注里,忙的人根本不会往下翻,而 n 恰恰是那个能一票否决整句结论的数字。

七、回到那场评审会

下次有人拿你周报里那个漂亮的百分比对上『为什么又掉了』,答案不再是运气:那个数一直是带,不是点;宽的时候本就不该拿去签字,窄的时候才有资格和放行线比。把区间交出去,不是把报告写复杂,是终于把『我有多确定』这件一直在心里、却从没写下来的事,写下来了。

诚实的质量报告,报的不是一个通过率,是一整个『这个数大概落在哪』——只交点估计,等于把确定性的成本悄悄转嫁给了读报告的人。

相关文章
|
1天前
|
JSON 测试技术 数据格式
一次 pytest 跑出三个覆盖率:行、分支、需求,你的报告写的是哪个?
本文揭示覆盖率的三大分母陷阱:行覆盖易被生成代码虚高,分支覆盖难捕业务组合逻辑,需求覆盖最真实却常被省略。提出“三层分母并列报告”法——剔除样板重算行覆盖、按真值表补全分支用例、绑定需求条目审计覆盖,让93.4%不再掩盖81.0%的窟窿,让复盘从归因转向可对账。
|
5天前
|
人工智能 安全 测试技术
传闻中68.7万美元年薪的"测试AI的人":你的评测系统谁来评测?
2026年中,OpenAI评估智能体越权攻击评分系统,暴露“裁判需被裁判”的根本风险。Anthropic随即提出“嵌入式评估员”机制:第三方常驻、实时验证、独立发声。本文拆解其工程内核——将质量门禁前移至开发过程,为评测集、裁判模型、CI门禁构建可回归的meta-evaluation防线。
|
5天前
|
人工智能 安全 测试技术
同一模型、同一机器、只改一个开关,为什么压测结果仍可能不可信?
本文拆解NVIDIA Blackwell机密推理实验,强调复现实验需严控变量、同步评估吞吐/TPOT/安全状态与输出质量。指出性能数字不可直接外推,提出四维发布门禁(安全、质量、性能、稳定性),倡导测试工程师构建可复现的差分评测体系。(239字)
同一模型、同一机器、只改一个开关,为什么压测结果仍可能不可信?
|
2月前
|
人工智能 自然语言处理 API
Qwen3.8-Max-Preview深度全解析:2.4万亿参数旗舰MoE模型+Token Plan限时优惠完整落地指南
在大模型技术持续迭代的浪潮中,参数规模、架构创新与成本控制成为衡量旗舰模型的核心维度。Qwen3.8-Max-Preview作为阿里推出的全新旗舰预览版模型,以2.4万亿总参数量、原生MoE混合专家架构、1M超长上下文与双推理模式,构建了覆盖文本、图像、视频、代码的全栈能力体系,同时搭配Token Plan限时优惠政策,大幅降低企业与个人用户的使用门槛。本文将从技术架构、核心能力、API实战、Token Plan优惠与落地选型五大维度,对Qwen3.8-Max-Preview进行深度解析,帮助开发者与企业用户全面掌握这款旗舰模型的使用方法,实现高效、低成本的AI能力落地。
627 1
|
1月前
|
人工智能 JSON API
2026最新|ComfyUI AI漫剧全自动教程:统一人设、智能分镜、插帧动效、批量成片保姆级指南
专为8G显存笔记本优化的本地AI漫剧生成方案:全离线运行,无需API密钥、无水印、不限次数。集成Qwen剧本生成+ComfyUI图像渲染,支持角色锁定、AI插帧、MP4成片闭环。资源包预装全部模型、插件、工作流及一键脚本,彻底告别GitHub下载难题,开箱即用。(239字)
|
2月前
|
存储 缓存 监控
阿里云国际站代理商:CDN+OSS搭配指南:静态资源加速最佳方案
当团队把静态资源托管至OSS并开启CDN加速后,一个典型的落差是:回源带宽消耗依旧偏高、缓存命中率长期达不到90%,首屏耗时改善不够明显。问题的根源往往不在产品本身,而在于编排策略与监控机制的缺位。一套跑得通的阿里云CDN+OSS搭配静态资源加速方案,需要从缓存规则、回源架构和成本控制三个维度把账算清,而不只是完成简单的域名绑定。
489 1
|
3月前
|
人工智能 数据可视化 小程序
AI 生成的 Markdown 表格复制到 Word 后错列,怎么稳定处理?
:AI 生成的表格复制到 Word 后出现竖线、分隔线、错列,本质上多是 Markdown 表格没有转换成 Word 表格对象。本文从 Markdown 表格结构、Word 文本转换表格、Pandoc 转 docx、DS随心转多端导出几个角度,整理一套面向普通用户和技术写作者的排查流程。
588 1
|
4月前
|
存储 小程序 安全
如何为APP构建一个安全可控的沙箱运行环境,让第三方合作伙伴的小程序能够安全可控的运行在自己的APP里
如何为自己的APP引入一个安全可控的沙箱运行环境,沙箱为每个小程序创建一个独立的运行环境,实现第三方服务商通过小程序接入宿主APP,代码在自己可控的沙箱内运行,宿主APP通过管控后台掌握最终的决定权。
397 2
如何为APP构建一个安全可控的沙箱运行环境,让第三方合作伙伴的小程序能够安全可控的运行在自己的APP里
|
9月前
|
供应链 数据可视化 数据挖掘
1688运营自学全套流程,新店如何快速获得转化的指南!
新手入驻1688常因缺乏运营框架而难出单。本文系统解析平台搜索机制、流量布局与店铺成长路径,涵盖类目定位、双端差异化运营、产品矩阵搭建及三阶段进阶策略,助力商家快速掌握核心逻辑,实现高效成交。
|
3月前
|
机器学习/深度学习 数据采集 人工智能
水稻病害检测数据集分享(适用于YOLO系列深度学习分类检测任务)
本数据集含7000+张水稻病害图像,覆盖细菌性叶斑病、褐斑病、叶霉病三类,标注规范(YOLO格式),已划分训练/验证/测试集(8:1:1),支持YOLO系列等主流检测模型,助力智慧农业病害识别研究与落地。(239字)
423 7

热门文章

最新文章