必须为自己的发现拿出证据的代码评审平台
大多数评审工具产出的阅读量远多于可修的工作量。我们做的这个平台,让多个分析智能体并行处理同一次变更,再由第二轮反过来质疑它们找到的每一条,活下来的发现会带着替换代码和背后的证据一起出现。终端、编辑器、接口和后台服务背后是同一个引擎,因此无论从哪里发起,评审的含义都一样。
- 行业开发者工具
- 合作方式自研产品,内部开发
- 状态在用,并持续扩展
每一种发起评审的方式,背后都是同一个引擎
平台读取一次提交的变更,判断它触碰了什么,然后同时交给多个分析智能体。发现会被合并、去重、按严重程度排序并设上限,交回来的是一份可以从上往下处理的清单,而不是一堵需要通读的墙。它不是 linter,也不是把单个模型的意见写成判决。
无论请求来自终端命令、编辑器、接口,还是按自己的节奏盯着仓库的后台服务,跑的都是同一个引擎。它们共用一份历史:在键盘上发起的那次评审,就是面板稍后展示的那一次;在合并请求上,它更新自己那条评论,而不是往下再堆一条。

为什么还要再做一个评审工具
自动评审先遇到的是可信度问题,其次才是覆盖率问题。我们的设计正是针对这三处失败。
噪声的代价高于它的收获
一个会标出格式改动、重排的导入和自信猜测的工具,会把团队训练成扫读。一旦评审输出开始被扫读,那条真正重要的发现也会被一起扫过去。
没有修复方案的发现,只是又一张工单
只描述问题就停下的评审意见,把活儿又推回给本来就很忙的人。读的人仍然得自己想出修好之后的代码长什么样,于是常常判断它可以再等等。
每个入口的行为都不一样
终端里的评审、编辑器里的评审、合并请求上的评审和按计划运行的评审,是彼此分开的工具,行为不同,历史也不同。同一次变更可能在一个入口通过,在另一个入口被拦下。
我们做了什么
一条流水线,四种抵达它的方式,以及在模型的猜测和交给人去读的东西之间的几层怀疑。
每个入口背后都是同一个评审引擎
同一条流水线负责解析变更、过滤、补充上下文、分派给智能体并合并结果。格式化与存储归调用方负责,这正是入口可以不同、而评审不会不同的原因。
- 终端命令、编辑器集成、带实时更新的接口和后台服务,跑的是同一次评审
- 共用一份历史:在键盘上发起的那次评审,就是面板稍后展示的那一次
- 模型供应方位于同一个接口之后,增加或更换一个是配置问题,而不是重写
发现送来时已经带着修复
五级严重程度收敛为三种动作:现在修、尽快修、稍后看,于是报告可以从上往下处理。每条发现都由代码地图补充过上下文,指向真实的调用路径,而不是一次模式匹配。
- 每条发现都带替换代码,不带的会被数据结构直接拒掉
- 评审从符号索引里取上下文:哪些函数变了、谁在调用它们、哪些测试覆盖它们、谁导入了谁
- 发现以内容而不是行号来标识,重新格式化一个文件不会让已经处理过的问题复活
猜测与报告之间的五层
每一层都比后一层便宜,绝大多数本会成为噪声的东西,在昂贵的步骤发生之前就已经消失。最后一层最严格:平台会试着拿源码来证明这条发现。
- 只改空白、注释和导入顺序的变更,在联系任何一个模型之前就被丢掉,静态模式扫描则先标出有风险的代码
- 低置信度的发现在评审结束后立刻剔除,随后第二轮会反过来质疑每一条幸存者,只保留驳不倒的那些
- 力所能及时,平台会写一小段程序,在隔离沙箱里拿真实源码检验这条主张;如果检验跑不起来,这条发现会被保留,而不是悄悄消失
只提议、从不落地的对抗模式
针对一个代码库的三波演练:一组智能体寻找可被利用的地方,第二组写补丁,第三组拿补丁去对它声称堵上的漏洞做检验。结果会回到已验证修复、部分修复、仍然存在或误报四者之一。
- 进攻方各自带着不同的任务书:业务逻辑审计、怀有敌意的客户、混沌工程、可观测性和合规审查,这样一轮扫描不会是同一种直觉的五份复制
- 补丁以 diff 的形式产出并接受验证,从不写进仓库;落地什么由人决定
- 智能体在一份命令白名单内工作,破坏性操作被禁用,它们的输出还会被检查是否夹带了注入的指令
实际发生的变化
我们公布平台做了什么,而不是它做得多好的数字。任何准确率说法都需要一次我们没有公布过的测量。
一份清单
一次评审产出什么
跨智能体合并、去重、按严重程度排序并设上限的发现。它是用来从上往下处理的,不是用来从头读到尾的。
经过检验,而非猜测
什么会送到人面前
琐碎变更根本不会到达模型,弱发现被丢掉,剩下的要被质疑,力所能及时平台还会先拿源码去证明它。
由人来决定
变更如何落地
修复和补丁以提议的形式出现,带预览,也带原文件的备份。没有人点头,什么都不会写进仓库。