抖音质量效能部不传之秘:用AI精准预估“可能出事”的模块

📅 2026/7/17 21:27:57 👁️ 阅读次数 📝 编程学习
抖音质量效能部不传之秘:用AI精准预估“可能出事”的模块

关注 霍格沃兹软件测试开发 公众号,回复「资料」, 领取人工智能测试开发技术合集

在抖音质量效能部搬砖那几年,每隔一段日子就会被拉进同一个“紧急群”——某个看起来人畜无害的代码提交,上线后把核心链路炸出一片红。复盘的时候大家总在叹气:要是能提前知道这模块“不干净”,哪怕多分一个测试人力进去也好啊。

后来我们还真搞出来了。没搞什么玄学,就是用 AI 做了一件事:每次代码变更,自动给这个变更的“出事概率”打分。从“到处救火”慢慢变成了“精准拆弹”。离开抖音后一直想把这套思路完整写下来,核心方法不涉及业务机密,今天就把这层窗户纸捅破。

一、先别急着上模型,想想你究竟要预测什么
很多人一上来就去找数据集、跑 XGBoost,结果折腾一个月连基线都出不来。我们最开始也犯了这个错。

真正要预测的不是“哪个模块有 Bug”,而是——“这次代码变更,引入线上故障的概率有多高”。这两者差别巨大。模块历史 Bug 多,只代表它旧债多,不代表这次改动一定出事;一个从来不出事的模块,被一个新人改了核心逻辑,往往才是大雷。

所以我们的预测对象是 commit(变更)。每一次 MR(Merge Request)提上来,模型就给它一个风险分。分高了,测试就重点关照,甚至直接卡发布。

二、把脏活干好:样本标注比调参重要十倍
有监督学习,第一步是拿到“有问题的变更”和“没问题的变更”作为正负样本。听起来简单,做起来全是坑。

我们当时的做法是打通两个数据源:

Git 仓库的 commit log(拿到 diff、作者、时间、改动文件列表)
线上故障/bug 跟踪系统(明确记录哪些故障是由哪个 commit 引入的)
正样本:能追溯到某个 commit 是故障根因的,标为 1。
负样本:上线后安安稳稳跑了两周,没惹出任何线上工单的 commit,标为 0。

这里头有三个血泪经验:

① 千万别用“修复 Bug 的 commit”直接做正样本。
因为修复 Bug 的那个 commit 本身是解决问题的,它的 diff 特征通常是“加个判空”“修个边界”,和真正“写出 Bug”的 diff 截然不同。我们一开始没区分,模型学废了,以为加 if 判空是高风险行为,闹了大笑话。

② 窗口期要卡死。
一个 commit 上线后,到底观察多久没出事才算负样本?我们试下来,双周迭代下,观察 10 个自然日比较稳。有些模块上线后三天才因为定时任务暴露问题,窗口太短会把大量“还在路上”的 Bug 标成负样本,污染训练集。

③ 别做“一视同仁”的随机采样。
业务代码里,不出事的变更占了 95% 以上。如果你直接全量丢进去,模型会学到一招绝技:永远预测低风险,准确率贼高,屁用没有。我们后来做了下采样,让正负样本比例控制在 1:5 左右,同时给正样本加高权重,模型才学会认真对待那些危险信号。

三、真正值钱的不是算法,是这一把特征
抖音的代码库极其庞大,业务线几十条,语言主要是 Java/Kotlin/Go/C++。我们设计特征的时候只有一个原则:让不懂模型的人看了也觉得“有道理”。否则你推不动,研发老大会觉得你在搞玄学。

我们最终沉淀出五类特征,每一条都是跟开发、测试反复扯皮磨出来的:

  1. 变更规模 —— 越大越容易出事,但有个例外
    新增行数、删除行数、总修改行数
    涉及文件数、涉及目录数
    是否改了底层库(如网络层、存储层):单独的布尔特征,改了直接 +20% 风险分起步
    例外是什么?纯 import 整理和格式化代码。这种变更动辄几百行,但几乎零风险。我们后来用正则扫 diff 内容,如果 90% 以上的改动行只是空白/缩进/import 替换,就直接压权重。

  2. 代码复杂度 —— 你写的圈复杂度,最后都变成锅
    改动代码块的最大圈复杂度
    是否新增了嵌套超过 3 层的 if/for
    是否修改了已有高复杂度函数(圈复杂度 > 15 的老代码)
    这个特征抓“屎山上的新包”非常准。有一回直播推荐模块一个小 MR,只改了 5 行,但扎在一个 1200 行、圈复杂度 38 的老函数里。模型直接给了高危。开发不信,结果上线当晚缓存击穿,故障单编号我到现在都记得。

  3. 历史债 —— 这文件/这模块以前老出事,现在大概率还有事
    该文件过去 90 天线上故障触发次数
    该模块(目录粒度)最近 3 次迭代的 Bug 密度
    上次该模块出故障距今的天数(越近越危险,因为可能修了又引入新问题)

  4. 人的因素 —— 有些哥们儿写的代码就是自带“气场”
    我们给每个提交者算了一个开发者缺陷注入率:此人过去半年提交中,引入过线上故障的比例。这个值不是固定不变的,会按时间衰减,最近一次闯祸加权最高。

另外还加上:

提交者入职时长(新人前 3 个月是故障高发期)
这次改动是否他首次接触该模块(首次触达 + 高复杂度,基本等于点炮)
当时组里有个实习生,能力很强但业务不熟,模型给他的 MR 几乎每次都标高。头两个月他很不爽,后来真出过两次 P1 故障,他主动请我们吃饭,说“这玩意儿比我 Code Review 靠谱”。

  1. 过程质量 —— 代码评审时就已经露出马脚了
    CR 评论总数、提出问题的评论数
    是否有“需要修改”的 CR 意见被作者忽略直接合入(这个极狠,一旦出现,风险分至少拉高 30%)
    关联需求变更次数(提测期间需求还在变的,Bug 率明显更高)
    这些特征从 GitLab/Jira 的 API 里都能抓到。我们把它们拼成一张宽表,一条 commit 一行,大概 60 多个特征,最后模型训练全用这个。

人工智能技术学习交流群
伙伴们,对AI测试、大模型评测、质量保障感兴趣吗?我们建了一个 「人工智能测试开发交流群」,专门用来探讨相关技术、分享资料、互通有无。无论你是正在实践还是好奇探索,都欢迎扫码加入,一起抱团成长!期待与你交流!👇

image

四、模型选型:别整花活,树模型能打十年
我们也试过把 code diff 扔进 TextCNN、CodeBERT 里学语义,效果一言难尽——有时候它会给“修了个文案”的 MR 打高分,因为训练语料里很多故障 commit 也改了文案。纯粹捣乱。

最后老老实实用 LightGBM。快、稳、可解释性好,几千个 commit 几分钟训完,AUC 能做到 0.82~0.85(看业务线),已经完全够用了。

随手贴一段我们核心训练的骨架,脱敏后的伪代码:

import lightgbm as lgb

params = {
'objective': 'binary',
'metric': 'auc',
'boosting_type': 'gbdt',
'num_leaves': 31,
'learning_rate': 0.05,
'feature_fraction': 0.8,
'scale_pos_weight': 5, # 正负样本不平衡下的正样本权重
}

model = lgb.train(
params,
train_data,
valid_sets=[valid_data],
early_stopping_rounds=50,
verbose_eval=False
)
评估的时候我们不只看 AUC,而是看业务指标:召回率@Top20%。 意思是模型给出最高风险的前 20% MR,能抓住多少真正的故障变更。在我们几个核心业务线上,这个值稳定在 75%~80% 之间。翻译成人话就是:只重点测试 20% 的变更,就能提前拦截四分之三以上的潜在线上事故。

五、怎么让开发信你?SHAP 可解释性是你唯一的武器
光报个“高风险”三个字,研发迟早会骂你是算命先生。我们一开始吃过亏,被人在周会上当面质疑:“凭什么说我的 MR 有风险?”

后来我们上了 SHAP,给每一个预测结果附上归因。MR 详情页里会显示:“本次变更风险评估为 高,主要因为:【修改文件历史故障密度高】、【开发者当前迭代首次接触该模块】、【圈复杂度增量达 12】。”

这玩意儿一上,风向立马变了。研发看完不是甩锅,而是主动去优化那坨高复杂度代码。有个客户端大佬看到 SHAP 归因里“圈复杂度”排第一,直接重构了播放器模块,后面三个迭代该模块故障清零。这个结果比任何模型指标都有说服力。

六、工程落地:别让它成为摆设,要把它塞进发布流水线
模型训完如果只生成一份报告邮件,结局一定是躺在邮箱里吃灰。我们做了三件事把它真正用起来:

  1. CI 自动触发预测
    提 MR 时,Jenkins 流水线自动调模型推理接口。如果风险分为“高”,自动在 MR 评论区发警告,并给测试负责人打 IM 消息。

  2. 质量卡点
    高风险 MR,强制要求:

至少两位高级工程师 CR 通过
对应的自动化回归套件必须全部通过,不允许跳过
开发自测 checklist 由 AI 辅助生成重点验证场景(基于 diff 涉及的接口)
3. 低风险快速通道
对于风险分极低的 MR,我们给了一条“轻测通道”,只跑冒烟用例即可合入。这大大缓解了测试团队的人力瓶颈,也是测试 leader 愿意全力推这件事的动力——他可以把人挪去真正危险的地方。

模型服务本身用 Flask 简单包了一层,后来迁移到公司内部的推理平台。每季度用最新数据全量重训一次,防止模型老化。冷启动问题,我们通过组织级架构知识图谱解决:新模块没有历史数据,但可以根据它依赖的底层库、所属业务域、代码结构相似度,从相近模块“继承”一个初始风险分。

七、不是所有团队都值得现在上模型
最后泼盆冷水。如果你所在的团队:

业务刚起步,两个月才发一次版,样本量不到 500
没有规范的 commit 和故障记录,连哪个 commit 导致事故都查不出来
质量文化薄弱,开发根本不 care 预测结果
那劝你先别急着上 AI。先搞数据基建,把“谁写的代码搞出了事”这件事追踪清楚。没有这个基础,模型就是空中楼阁。

对于样本不够的小团队,其实可以先搞一个加权规则引擎:把前面那些特征加权求和,人工调阈值。虽然糙,但比裸奔强一百倍。

写在最后
离开抖音质量效能部有一阵子了,回忆起来,最让我自豪的不是模型 AUC 有多高,而是有一天,一个开发哥们儿在群里说:“我靠,这个 AI 比我老婆还了解我会不会写出 Bug。” 虽然作为技术人,我更希望他把精力花在别让自己老婆有机会了解这方面。

AI 从来不能取代测试工程师,但它可以把测试从繁琐的全面覆盖里解放出来,把有限的精力聚焦在最容易出事的地方。所谓“精准测试”,不是炫技,是你真真切切少接了半夜三点的告警电话。

希望这篇文章,能让你在自己的项目里,少背几口锅。

推荐学习
测试智能体与智能化测试平台公开课,从Web/App/接口测试智能体,再到智能体工具Opencode,爱测智能化测试平台,手把手带你掌握AI智能体与智能化测试平台!

👉 扫码进群,报名学习!

image

image

关于我们
霍格沃兹测试开发学社,隶属于 测吧(北京)科技有限公司,是一个面向软件测试爱好者的技术交流社区。

学社围绕现代软件测试工程体系展开,内容涵盖软件测试入门、自动化测试、性能测试、接口测试、测试开发、全栈测试,以及人工智能测试与 AI 在测试工程中的应用实践。

我们关注测试工程能力的系统化建设,包括 Python 自动化测试、Java 自动化测试、Web 与 App 自动化、持续集成与质量体系建设,同时探索 AI 驱动的测试设计、用例生成、自动化执行与质量分析方法,沉淀可复用、可落地的测试开发工程经验。

在技术社区与工程实践之外,学社还参与测试工程人才培养体系建设,面向高校提供测试实训平台与实践支持,组织开展 “火焰杯” 软件测试相关技术赛事,并探索以能力为导向的人才培养模式,包括高校学员先学习、就业后付款的实践路径。

同时,学社结合真实行业需求,为在职测试工程师与高潜学员提供名企大厂 1v1 私教服务,用于个性化能力提升与工程实践指导。