2013年,Apache Rave这个开源项目里埋着一个漏洞,编号CVE-2013-1814。修复它的代码补丁其实早就存在,静静躺在代码仓库里。但没人找到它。
这一躺,就是十年。
直到十年后,才有人把这个漏洞和它的修复代码对上号。这件事听起来像个笑话,但它揭示了一个很现实的问题:全世界的安全漏洞数据库里,有60%到63%的已知漏洞,压根找不到对应的修复代码链接。
这个问题有个专业名字。
**补丁检索**:给定一个已知的安全漏洞描述,去代码仓库里找出哪一次代码提交(commit)修复了它。这是整个漏洞管理工作流的地基,没有这一步,后面的风险评分、受影响版本追踪、供应链扫描全都无从谈起。
为什么这件事这么难?想象你要在一个几万次提交记录的仓库里,凭一句"这个软件存在跨站脚本攻击漏洞"的描述,去大海捞针找出那一次具体的代码修改。难点有三个。
第一,仓库太大了。研究显示,49%的漏洞所在仓库有超过5000次提交记录,想一条条看根本不现实。第二,代码改动太长了。平均一次提交的代码差异(diff)能跑到15000个token,而像BERT这样的老牌文本模型一次只能处理512个token,连零头都装不下。第三也是最要命的一点,漏洞描述和修复代码说的根本不是一回事。安全公告里写的是"缓冲区溢出"这种安全症状,但程序员在提交记录里写的是"越界读取"这种技术内因,两边用词几乎不重叠,靠关键词匹配的传统搜索引擎根本连不上线。
这就好比你拿着病人说的"我肚子疼"去翻医生的手术记录,而手术记录里写的全是"阑尾切除"这种专业诊断名词。如果系统只会做关键词匹配,那永远也配不上对子。
一个叫PatchHolmes(意思是"补丁界的福尔摩斯")的系统,想要解决这个老大难问题。
两阶段流程:先海选,再精读
PatchHolmes的设计思路分两步走。
第一阶段像选秀海选,目标是从几千几万次提交里,先筛出100个最可能的候选者,不要求精准,只要求别漏掉真正的答案。第二阶段才是真正的精读,让一个AI智能体仔细审查这100个候选人,最终只锁定一个。
第一阶段用了两条腿走路的办法。一条腿是关键词检索加时间衰减,另一条腿是语义向量检索。两条腿各自给出一份排名,再用"倒数排名融合"(Reciprocal Rank Fusion,简称RRF,一种把多个排序结果合并成一个的算法,排名越靠前的权重越大)的方法把两份名单拧成一份。
关键词检索这条腿,打分公式里给了四个信号不同的权重:提交信息的关键词匹配占35%,代码差异本身的关键词匹配占15%,时间关联度两项加起来占50%。为什么提交信息权重最高?因为程序员写commit message时用的是接近自然语言的描述,这和漏洞报告的用词更接近;而代码diff里全是代码本身,和自然语言描述的漏洞重合度最低,所以权重最小。
时间关联这个信号也很有意思。一个漏洞被发现、被官方记录(reserve date)、被公开披露(publish date),这些时间点和真正修复它的那次代码提交,时间上往往离得很近。于是研究者设计了一个公式,衡量某次提交的时间和漏洞关键时间点的"距离",距离越近分数越高,距离每差一个排位,分数就打三分之一的折扣。
语义检索这条腿用的是Qwen3-Embedding-8B这个嵌入模型,把漏洞描述和每一次代码提交都转换成4096维的向量,距离越近代表语义越相关。这里有个值得一提的细节:研究者本想换用当时榜单排名更高的Octen-Embedding-8B模型,结果一试发现召回率从43%暴跌到12%,说明"榜单第一"不等于"适合这个任务",公开排行榜的优势未必能迁移到特定场景。
第一阶段结束,100个候选人名单出炉,交给第二阶段。
四件工具,一个侦探
第二阶段才是这篇论文真正的创新所在,也是它名字里"福尔摩斯"的由来。
**智能体(Agent)**:这里指一个能自主决定下一步做什么的AI程序,它不是一次性输出答案,而是像侦探破案一样,一步步观察线索、调整思路,直到找到结论。
这个AI侦探手里只有四件工具。第一件叫"看名单",一次性看完全部100个候选提交的一行摘要,包括提交ID、消息首行、改动了几个文件。第二件叫"读详情",深入读某一个候选提交的完整信息,包括提交说明、文件清单和代码差异,限额8000字符。第三件叫"查细节",如果某个文件被截断了没读完,可以单独再调出这个文件的完整差异,限额16000字符。第四件叫"下结论",只能用一次,提交最终答案和理由。
这个"只能看一次名单,精读几个候选,最后下一次结论"的流程,本质上是在模拟一个真正的侦探破案过程:先把所有嫌疑人列一遍大致印象,挑出最可疑的几个仔细盘问,最后锁定凶手。
这里有个关键区别,论文反复强调的一个点:之前最强的对手方法叫Favia,它是"逐个盘问",对每个候选人单独问一句"是不是你干的",每个人都独立回答是或否外加一个信心分数。问题在于,十个候选人可能都被判定为"是",而且都给了同样高的信心分数,这时候系统只能按照候选人出场的先后顺序随便挑一个,完全没有依据。
论文里举了个真实例子特别能说明问题。CVE-2015-9251是jQuery的一个跨站脚本漏洞,在候选名单的100个里,真正的修复代码排在第9位。Favia把全部10个候选人都标记为"是",信心分数都打了满分5分,结果按顺序选中了排名第1的那个,但那其实只是一次无关的代码重构,根本没修复漏洞。而PatchHolmes的侦探依次读了排名1、2、9、4、3的提交,发现第9个候选人里加了一行代码,专门阻止跨域请求里text/javascript类型的响应自动执行,这正是修复XSS漏洞该有的样子,于是精准锁定它。
打个比方,这就像十个嫌疑人轮流被单独审讯,每个人都对警察说"我认罪",审讯室里没有对比环节,警察只能按进门顺序随便定一个有罪。但如果换成把十个人叫进同一个房间,让侦探逐一盘问、互相印证口供细节,真正的凶手往往会在细节比对中露馅。如果不采用这种"集体过堂"式的审查方式,系统永远没法摆脱"按顺序乱猜"的命运,因为单独审问根本提供不了让人做选择的额外信息。
实验结果:数字不会说谎
这套系统在GitHubAD这个包含809个CVE漏洞的测试集上,表现确实亮眼。
在最关键的指标"排名第一命中率"(Recall@1,意思是系统给出的头号候选就是正确答案的比例)上,PatchHolmes拿到59.95%,而Favia只有34.61%,另一个对照组IRCoT(一种边检索边推理的通用方法)只有28.55%,还有一个叫SPFinder的传统两阶段方法拿到27.32%。差距最大的一项,PatchHolmes领先了32.63个百分点。
这个数字意味着什么?意味着原来十个漏洞里,Favia只能猜对三四个,而PatchHolmes能猜对六个。如果一个安全团队每天要处理上百个漏洞,这个差距累积下来,省下的人工核查时间是巨大的。
更有说服力的是一组"控制变量"实验。研究者把PatchHolmes第一阶段筛出的同一份100人候选名单,分别交给Favia和IRCoT处理,排除候选名单质量本身带来的差异。结果Favia在相同候选集下从34.61%提升到39.80%,说明候选集质量确实有帮助,但提升有限;而PatchHolmes光是靠AI侦探的审查流程,就把命中率从32.63%(直接取第一阶段排名第一的结果,不经过智能体审查)提升到59.95%,整整多出27.32个百分点。
这说明什么?说明真正起决定作用的不是候选名单筛得多准,而是审查这份名单的方式。候选集的质量提供了20个百分点左右的改善空间,而审查方式本身能撬动27个百分点的提升,后者才是大头。
论文还测试了换掉模型会不会影响结果。在同一个Qwen模型家族内部,从235B参数的大模型换成30B参数的小模型(且只有3B是激活参数,相当于模型实际工作时只动用一小部分"脑容量"),命中率只下降了0.86个百分点,几乎可以忽略不计。换成完全不同的模型家族gpt-oss,表现依然远超"不用智能体"的基线水平。这说明效果的来源不是某个特定模型多聪明,而是整套"先看全貌再精读细节"的审查机制本身在起作用。
这就好比一个破案流程设计得足够科学,不管换成哪个经验丰富的探长来执行,都能破案;但如果流程设计有问题,哪怕换福尔摩斯本人来,该漏掉的线索照样漏掉。流程的价值大于执行者个体的差异,这是整篇论文最硬核的一个发现。
这套方法在另一个独立的测试集PatchFinder_top10上也做了验证,这个数据集每个漏洞只给10个候选,由另一套系统PatchFinder预先筛选。PatchHolmes的侦探流程原封不动搬过去用,命中率从PatchFinder自己给出的24.28%提升到39.86%,几乎翻了一番还多。更值得一提的是,这个数据集里有675个漏洞压根没把正确答案放进候选池,相当于无论如何也猜不对,天花板是46.10%,而PatchHolmes已经把能够恢复的差距补上了71.4%。
成本也算了一笔账。处理一个漏洞,PatchHolmes平均消耗大约9.6万个输入token,花费大约0.007美元,跑完全部8401个漏洞只要58美元。而Favia因为要对每个候选逐一审问,每个漏洞要消耗约67万token,跑完全库要花约400美元。PatchHolmes用了约七分之一的成本,换来了更高的准确率。
这里还有一个很朴素但很重要的细节值得说一说。论文的系统提示词里,研究者特意告诉AI侦探一个统计规律:根据以往数据,真正的修复代码排在候选名单第1位的概率大约只有12%,大部分情况下藏在第2到第20位之间。这个提示的用意很简单,防止AI偷懒,一上来就无脑选第一个。这个细节背后藏着一种对AI行为模式的洞察,大模型确实有"迷信榜单第一名"的倾向,需要人为提醒它别偷懒。
当然这套系统也不是完美无缺。论文的局限性部分很坦诚地提到,所有能拿来测试的漏洞,前提都是修复代码已经被人类找到了,那些至今没人找到修复代码的"死亡漏洞",根本无法纳入任何基准测试,这是整个研究领域共同的盲区。另外有7%左右的漏洞实际上对应多个合法的修复提交,而官方记录往往只登记了其中一两个,如果AI选中的是一个正确但未被记录的修复,系统依然会把这次判定为失败,这是评测方式本身带来的误差。
写在后面
读到这篇论文时,最触动我的不是那些漂亮的准确率数字,而是它用一个非常朴素的方式戳破了一个行业迷思:很多人默认模型越大越聪明,效果越好一定是砸了更强的大模型。但这篇论文反复用实验证明,把235B参数换成30B,准确率只掉了不到1个百分点,换一个完全不同的模型家族,结果依然稳健。真正撑起效果的是审查流程的设计,是"先全局浏览再精读细节再对比下判断"这套逻辑本身,而不是某个具体模型的参数量。这个发现对那些盲目追求用最大模型来解决问题的做法,算是一记提醒。
还有个细节值得单独拎出来说。研究者在尝试第一阶段检索模型时,特意试了当时排行榜上最靠前的一个嵌入模型Octen-Embedding-8B,结果效果反而比普通的Qwen3-Embedding-8B差了三倍不止。排行榜上的通用能力和特定任务的实际表现,中间隔着一道看不见的沟。这提醒我们评估任何AI工具时,都不能只看它在某个通用榜单上排第几,得看它在你真正要解决的那个具体问题上表现如何。
十年前那个被遗忘在Apache Rave仓库里的修复代码,如果当年有这样一套AI侦探系统在跑,会不会提前被发现?没人知道答案,但这个问题本身,值得每一个还在人工核对漏洞补丁的安全团队想一想。
Q&A
Q1:PatchHolmes是什么?
A:PatchHolmes是一套用AI智能体做补丁检索的系统,分两阶段工作:先用混合检索方法筛出100个候选代码提交,再让AI智能体通过四种工具逐一审查,最终锁定真正修复漏洞的那一次代码提交。
Q2:PatchHolmes和之前的方法Favia相比优势在哪?
A:Favia对每个候选逐个独立打分,容易出现多个候选都给高分导致无法区分的情况。PatchHolmes让AI一次性看完所有候选名单再精读对比,排名第一命中率从Favia的34.61%提升到59.95%,而且只需十分之一左右的token消耗。
Q3:PatchHolmes换一个更小的AI模型效果会下降很多吗?
A:不会。在同一个模型家族内,把参数量从235B换成30B(实际激活仅3B),准确率只下降了0.86个百分点。换成完全不同的模型家族gpt-oss,效果依然远超不用智能体的基线,说明效果主要来自审查流程设计而非模型本身。







