AI 帮快手排 Bug:它不是万能,但真的省心

AI提示词2小时前更新 jinlian
0 0

最近几年,大前端技术发展很快。更新得快,功能也变得更复杂。业务和技术绑得特别紧。快手用户特别多,每天几亿人在用,大家用得时间也长。这让我们遇到了很多问题:技术种类太多了,大家用的资源也多。这样一来,性能不稳的风险就变大了。

以前,我们遇到性能问题,要解决它太难了。那些工具不好用,门槛很高。只有少数老专家能搞定。他们靠的是多年的经验和感觉。但是,专家数量有限,问题却越来越多。我就在想,AI 能不能解决这个矛盾呢?

我 2019 年进了快手,一直负责稳定性的工作。我这个人喜欢研究系统底层,搞过不少难的技术。快手第一个开源项目 KOOM 就是我写的。今天,我想和大家聊聊我们在“AI 搞性能稳定性”这件事上,是怎么想的,以及我们做「柯南 AI」平台时踩过哪些坑。

AI 帮快手排 Bug:它不是万能,但真的省心

快手的稳定性发展,我把它分成了四个阶段。每个阶段都比前一个做得更好。最早我们自己做了 APM。后来把零散的工具都放到了 APM 平台。有了平台,我们才能去解决问题。最后,我们形成了一整套预防故障的体系。这和移动互联网的发展是同步的。从大家都在抢用户,到后来的用户存量竞争。性能和稳定直接影响用户体验,成了公司竞争的关键。现在,我们又来到了 AI 时代。

大前端的性能稳定性问题,已经提了十多年了。硬件方面,iPhone 的算力比最开始厉害了一百倍。QCon、GMTC 每年都有专门的讨论。但是,问题真的都解决了吗?没有。你看,上半年 QCon 的主题是“大前端越挫越勇”,下半年就变成了“AI 和跨端怎么更好结合”。这说明,问题并没有变简单。我们还在碰到麻烦,效率还不够高。如果用算法的复杂度来比喻,过去十年,我们面对的问题类型其实没变。但是,因为鸿蒙这些新东西的出现,问题变得更复杂了。要处理的数据也更多了。所以,我们确实面临着很大的挑战。

AI 怎么帮我们搞定性能稳定性

AI 到底能不能帮我们走出困境?我先从人的角度说一下我的看法。你的团队里有没有这样一种情况:有些 Bug,只有团队里的“老司机”才能修好。新来的同事就插不上手,学不到东西。而那些老司机呢,总是被这些难搞的 Bug 缠着。他们就没时间去做更重要的事情了。这样一来,问题就会变得更多,团队能力也上不去。

所以,一开始我就觉得,AI 不是来取代人的。它更像一个放大器。它能让团队做得更多。它能把那些专家才知道的经验,变成我们所有人都能用的能力。

但是,要让这个放大器有用,我们得先把它装对地方。我们的稳定性体系,是分阶段一步步建起来的。前面是基础,后面才能搭上去。AI 也得长在这个体系上,才能改造它。不然,就像没水的源头,没根的树。

稳定性涉及几十个小方面,包括技术、流程、运营等等。AI 应该从哪里切入呢?我们内部讨论了好几轮。最后决定从**“解决问题”**这个环节开始。因为这个环节最花研发时间,也最影响用户体验。而且,人在排查问题时,经常会有盲区。研究发现,人脑同时处理的变量,最多只有四个。

我们把“解决问题”分成了两块:找出根本原因紧急处理。找出根本原因又分两种:特别难的,和比较简单的。这正好对应大模型的推理、检索和生成能力。

我们从上到下,设计了一套灵活的 Agent 架构,搭建了「柯南 AI」平台。我们的目标很清楚:让找出根因和紧急响应更快、更准。最开始,我们把它做成了内部的聊天机器人。它能给出排查建议,甚至能自动修复一些代码。以后,它会一步步地集成到 IDE 里,变成编码助手,或者在内部排查平台里和大家对话。

技术选择上,我们的 Agent 框架也更新过。从最开始用 AutoGen,到后来自己基于 OpenAI Agent SDK 的能力来做。它支持流程编排,有多种策略,也能接入我们自己的命令行工具 Agent。基础建设分两头:AI 这边,我们根据任务选择模型。简单的任务用小模型,需要很多推理的用大模型。如果涉及到图片等多种信息,就再加上视觉能力。同时,我们也推进内部平台标准化,让工具能随用随取。服务端也很重要:系统必须能监控,能调试,能测试。而且要提前算好成本,不然规模一大了,钱就花不住了。

实践:AI 怎么帮我们找出问题根源

前面说了我们为什么做,怎么做。接下来,我用一个真实例子,说说我们到底做了什么。这个例子我们内部叫它**“五星 NPE”**。它看起来就是个空指针错误,好像加个判断就能解决。但它很奇怪,只在大型活动的时候出现。而且,它的错误信息里,只有系统自己的代码调用,根本找不到哪里出了问题。如果你把日志丢给 ChatGPT、Claude 这些模型,它们也搞不定。因为信息太少,它们没办法推断。

那我们的工具能找到原因吗?

动手前,我们先问了研发同事。结果呢,96% 的人觉得在线上排查问题很痛苦。但有趣的是,没出事的时候,他们嫌日志太多。出事了,又嫌日志不够。之前友商也分享过,工程师有 60% 的时间花在修 Bug 上。我查到的数据也差不多,在 30% 到 50% 之间。这说明,“写代码容易,修 Bug 难”不是个别现象。

最近,大家都在说 Linus 那句“Talk is cheap, show me the code”到了 AI 时代变成了 “Code is cheap, show me the talk”。但我想说的是:“Code is cheap, debug is expensive—show me the fix。” 写出一段能跑的代码可能很快。但是,要交付一个没有缺陷的版本,就得有一套能把“昂贵的排障”变得更省钱、更高效的体系。这就是我们接下来要讲的。

为什么修一个 Bug 这么花时间?我把这些年的经验总结成一句话:排查问题,其实就是一场科学推理实验。它结合了多种推理方法。我发现麻省理工大学也有一门课,讲的是同样的道理。先观察现象,收集数据。然后提出假设,用排除法验证,直到找到真相。AI 能不能做好这个实验呢?我就从 AI 的“优点”和“缺点”两方面来看。

我们想想,AI 的推理能力,能帮我们解决多少排障问题?AI 的优点很明显:它总结日志的速度很快。它能联想到更多的可能性。它见过的异常问题也多。只要我们稍微引导一下,它就能把零散的信息,很快连成一张“线索图”。但是,它也有短板:我们公司的内部代码、内部工具,还有很长的推理链,这些都是它不了解的。最麻烦的是那些“深层 Bug”,触发条件多,路径长。需要十几步连续的推理,模型很容易就跟不上了。

我们给 AI 建了一套四级评估体系。最低一级是**“总结问题”,这个它几乎都能做到。往上一级是“提出假设”,准确率就开始下降了。再往上是“验证假设”,这就需要人来帮忙,多聊几轮才能搞定。最高一级是“直接给出可行的解决方案”**,直接把问题修复。目前,它只能辅助解决一些简单问题。我们先定下这些标准,然后不断地往里填数据,调整策略。这样我们才能知道 AI 到底能做到哪一步,下一步该怎么走。我们也会随着模型能力的提高,持续观察 AI 在稳定性方面的表现。

我这些年最大的感受是,排查问题就像破案。都要从零散的线索里,找出原因,抓住“真凶”。想做一个真正好用的稳定性 Agent,开发的人自己得是个老侦探。见过各种各样的“案发现场”,才能把经验总结成规则。最难的 Bug,就像是“完美犯罪”,现场干干净净,连指纹都没有。前面说的“五星 NPE”就是这样,只剩下一段系统代码调用,几乎没有任何线索。没有足够的信息,AI 也很难办。

为了在这种“没线索”的情况下也能破案,我们内部做了一个工具,叫 Holmes。它把传统的方法分成了**“静态”和“动态”**两类:静态就是日志、内存快照这些“尸检报告”;动态就是调试器、性能分析工具这些“让程序再死一次”的利器。老程序员都喜欢调试器,就是因为它能一步步重现错误过程,把瞬间定格成连续的画面。

Holmes 的做法是,在这两方面都进行扩展:静态方面,我们把日志和内存快照变成了可视化的界面。动态方面,我们通过远程热修改技术,实时收集程序运行时的数据。

今天,我想重点说说可视化界面在排查问题中的作用。手机程序主要是靠界面交互的。所以很多 Bug 都和界面有关。复杂的应用遇到的界面问题,通常是很多问题组合在一起的,需要从应用层一直看到系统框架层。我们遇到过一种很难定位的崩溃:只有一张截图,一份界面结构,还有一系列点击事件。把这三样东西拼起来,我们就能知道用户到底点了哪个按钮,触发了哪段代码。这样就能把“没头没脑”的系统错误信息,翻译成“点按钮 A 导致的崩溃”。别小看这一步,它让研发同事能立刻联想到最近改过的代码,把排查时间从几小时缩短到几分钟。

实际做的时候,Holmes 收集的界面信息必须**“刚刚好”**。信息不能太多,也不能太少。多了会干扰判断,少了又缺关键线索。同时,我们得对系统界面框架非常熟悉,才能在不影响性能的前提下,一次性收集到界面层级、布局参数和事件链路。

第一次看到收集结果的人,常常会被那些密密麻麻的参数吓到。确实,只有写工具的同事才记得住每个字段是啥意思。这又回到了老问题:工具越复杂,会用的人就越少。资源又没用对地方。

AI 时代给了我们机会,来打破这个循环。我们还是用了前面说的 Agent 框架:先让大模型把版本、系统、错误代码这些基本信息处理一遍。然后,我们用专家总结的经验规则,让大模型把问题分类。每一类问题,都有一个专门的分析 Agent(作者注:AI 发展很快,2026 最新架构已在 Skill 方向发展,但思想一致)。比如,界面分析 Agent 会读取 Holmes 收集的数据,结合代码。它会不断地问自己“还需要其他工具吗?”“找到根本原因了吗?”最后在规定时间内给出结论。如果超时还没解决,就标记失败,让人工来处理。这样,复杂的参数就由 Agent 自动消化了。研发同事只需要知道“哪个按钮崩了”。工具终于从“少数人的绝活”变成了“团队都能用的标准工具”。

这听起来很顺利,对吧?先判断问题,再分类,最后给出代码。但是,真正做过 Agent 的人都知道,大模型犯错的情况,比你想象的要多。而且,每一步的准确率都会下降。一步是 80%,两步就只有 64% 了。我们做工业级产品,要求准确率接近 100%。所以,那些工程上的小细节,就变得非常关键

在信息处理方面,我们踩过两类坑。第一类是信息给得太少,目标却定得太大。比如,直接让模型“分析一下这次崩溃”,结果往往乱七八糟。第二类是信息给得太多,职责又分不清楚。模型反而迷失了。用数学的话说,前者是“欠定”,后者是“超定”。我们想要的是“适定”:不多不少,刚好够用。所以,我们把问题拆成了很多个职责单一的 Agent。每个 Agent 的提示词都经过精心调整。我们还通过一些例子,教会它怎么调用我们公司的工具。最后的效果是:系统先给出可能的原因,再列出排查方向。如果问题简单,可以直接生成代码修改建议,一键就能采纳。如果问题复杂,研发同事可以沿着线索继续深入查找。

前面说的多是程序崩溃的问题。另一方面,性能分析工具 Profiler 负责性能问题。大家最熟悉的应该是火焰图。这个名字,是十多年前 Netflix 的工程师 Brendan Gregg 想出来的。他用工具生成的可视化图:代码调用栈越高,火焰就越“旺”,哪里是瓶颈一眼就能看出来。现在呢,火焰图这个名字有点名不副实了。Android 的 Perfetto 不只画火焰图。它把 CPU、内存、调度、应用事件和内核追踪,都塞到了一张图里。采集十几秒,就能产生 60 MB 的数据。采样时间太短,信息不够。采样时间稍微长一点,数据就多得没法处理了。复杂的问题需要复杂的工具,复杂的工具又带来了复杂的使用方法。而且,问题本身还在不断变得更复杂。

过去我们遇到性能问题时,一般是这样做的:先花时间学习怎么用火焰图工具。然后在图里拖来拖去,放大缩小,一层层地找瓶颈。这一步对工程师的底层知识要求很高。做完这些,才能真正开始分析:看历史案例,对比类似问题。整个过程又长,门槛又高,效率又低。还很容易漏掉关键线索。这些正是 AI 可以解决的痛点。

我们给出的火焰图方案,还是用了**“专家经验前置”的思路:做 AI 火焰图排障的人,首先得是一个能熟练看懂火焰图的性能专家。方案的核心在于数据预处理算法**。我们要想办法,把那 60 MB 的原始火焰图数据压缩一下,变成模型能高效处理的信息。而且,要和代码、事件精准地对应起来。这样才能先做粗略的筛选。后续处理时,再按需加载必要的信息进行分析。最后,火焰图的分析结果会从四方面展示:卡顿、启动、时间片和自定义查询。系统会直接给出结论,并指出对应的代码位置,支持一键跳转。我们不用再像过去那样手动拖拽寻找瓶颈了。排查路径大大缩短。

实践:AI 怎么帮我们快速处理紧急故障

接下来,我想聊聊紧急故障处理。它的核心就一个字:

我说个真实案例。iOS 26 升级后,苹果又改了一些不兼容的地方。都 25 年了,它还在改 Objective-C Runtime。而且在文档里“好心”提醒:这里可能会崩(作者注:详见《iOS 26 你的 property 崩了吗?》)。结果,快手线上还在跑的几百个老版本,在更新到 iOS 26 后,一下子都崩溃了。只有真正经历过的人,才能体会那种痛苦:版本太多,用户太广,想止损都不知道怎么办。我们清点了下现有的办法,有三种:

  • 应用商店更新:一周时间,只有 50% 的用户能更新到。剩下 50% 的用户肯定要崩一次。
  • 代码回滚:这次是苹果改动了,我们不可能让苹果回滚。

所以,我们问自己:有没有一种工具,能在崩溃发生的那一刻,直接**“兜底”**?就像《英雄联盟》里的艾克开大招一样——时光倒流,让程序回到正常状态?我们内部也把这个工具叫做 Ekko。它的思路很简单:不管是谁引起的异常,也不管为什么会触发,先跳过错误,让用户不崩溃就行。当然,实现起来一点都不简单。

行业里以前有一种方案,叫前置 Hook。但是它必须在异常发生前就介入。对所有用户都生效,就算他们从来没崩溃过。Ekko 避开了这个缺点。Ekko 和行业方案最大的不同,在于它是**“事后”**的。只有当用户真正崩溃了,它才启动兜底流程。这样,对正常用户的影响就降到零了。这听起来简单,但实现起来一步比一步难。比如,对于 NSException 异常,我们要注册 exception_preprocessor。对于 C++ 异常,要 hook personality routine。对于 Mach 异常,还得和系统内核通信,难度是越来越高。

程序崩溃被捕获后,运行流程已经被打断了。我们必须精确恢复现场:代码地址、寄存器、栈帧、局部变量,一个都不能错。我们的方案也改了很多次:1.0 版本用的是常规的栈回溯,遇到 Mach 异常就没辙了。2.0 版本引入了异步 unwind,又遇到了因为代码体积优化,导致 unwind info 被删掉,造成兼容性问题。最后,我们干脆自己写了反汇编器,把控制权完全掌握在自己手里。

工具虽然厉害,但落地还是难。配置跳转指令、恢复上下文这些步骤还是很麻烦。只能由少数专家来操作。一旦线上出现问题,专家又不在,风险就更大了。所以,我们把 AI 引进来:由 Agent 自动分析崩溃现场,生成兜底配置。它还会给出影响范围和推荐参数。这既降低了操作门槛,也减少了人为失误。

再讲一个故事。我不知道大家见过多大的事故。我见过的是上千万次的崩溃,而且只发生在半小时内。最开始只是一个小崩溃,一个小时才崩一两百次。大家在处理时,为了止损,就做了一个操作——把弹气泡功能关掉了。以为这样就能止血了。没想到“关掉气泡”这个操作本身的问题,和最开始崩溃的原因一样。结果,崩溃量从几百次瞬间涨到了几十万次。这件事给我们最大的教训就是:处理故障时,依赖人做判断,非常不靠谱。人在高压下会紧张,很容易漏掉关键信息。

所以,我们把 AI 引入进来。它不会紧张。它也能把每次操作都记录下来,并给出处理建议。到最后,它甚至能自动处理故障。做法还是基于前面说的 Agent 架构:故障来了,先分析,给出建议和结论。如果判断需要兜底,就调用兜底工具,生成配置并发布。

直接看效果。第一,Checklist:你现在很紧张没关系,我们会把我们处理了几百次报警总结出来的步骤,一条条列出来给你。这能帮你防止遗漏。第二,问题总结:崩溃上报的字段有一百多个维度。人眼看肯定会漏掉。很多问题其实有自己的特征。比如,图里会提示“Android 35、高通芯片”这些条件。有了这些信息,第一步确定问题范围就很快。第三,在给出维度后,它还会继续提供代码层面的分析,并给出可能的修复方向。这省去了人工查找的时间。

总结与展望

接下来我想说说,我们在开发 Agent 过程中真实的感受。也算是一次认知上的升级。首先是思维方式的改变。写传统程序时,我们默认是“图灵机”那种确定性:输入固定,输出也一定。但大模型需要概率思维。如果你还用确定性思维去调试,只会给自己找麻烦。我们得先搞清楚它擅长什么,哪里不行,能力边界在哪里。这样才能决定哪里用 AI,哪里还是用硬代码。这能省下很多返工时间。

其次,要发现瓶颈并主动解决。提示词工程本身,并不能提高模型本身的上限,因为模型的基础能力没变。但是,一份精心设计的提示词,能让模型已有的能力充分发挥出来。这需要专家多年的隐性知识和直觉,才能达到模型能力的上限。模型单次推理的深度有限。所以,也要基于专家经验,把复杂问题拆成一个个好管理的小部分。同时,尽可能地打通公司内部各个系统的数据。另外,评估体系必须同时建立。AI + 稳定性的能力是个螺旋上升的过程。传统程序只花时间,AI 还要花钱(Token)。烧钱的速度,逼着我们把评估做得像上下文工程一样严谨。

回到最开始的问题:AI 会不会取代人?我更想听听“创始人”的声音。Linus Torvalds 被问到“有没有大模型没经过允许就给你提交代码”时,他直接说:“肯定发生了,而且会越来越多。”在他看来,工具的演进从来没停过:机器码 → 汇编 → C → Rust,现在只是又多了一层 AI。代码审查和维护也是一样。Linus 希望 AI 能先帮他找出“那些很明显的傻瓜 Bug”。毕竟,连他自己也免不了犯低级错误。

主持人想把话题引到“AI 会取代程序员”这个负面话题上。但 Linus 没跟着说。他反而强调:自动化工具一直都只是人类能力的延伸。从机器码到汇编,再到高级语言,每一次发展都让开发者走得更远。AI 也不例外——真正决定价值的,永远是我们怎么去用它

现在 AI 话题很热。越是热闹的时候,我们越要冷静。我们认为,体力型的排查工作,最终都会被自动化。但是,人类需要更高级的能力:提出正确的问题,识别模型的错误,在合适的时机介入。俗话说,AI 一天,人间一年。AI 发展很快。随着模型能力的提高,我们也会把工作流程从“人参与其中”向“人监督其中”发展。面对 AI 原生时代,一切才刚刚开始。

© 版权声明

相关文章

暂无评论

暂无评论...