当你盯着一个Pull Request,心里想“这看上去没问题”,然后生产环境就崩了——这种故事是不是听得太多了?多数线上事故的根源,并不是代码写得有多烂,而是那些沉默的假设:比如“这个请求只会处理一次”“数据迁移肯定跑在Worker之前”“那个API字段永远不可能为空”“事件总是按顺序到达”。这些假设不被显式写进任何一行代码里,却决定了一段变更到底安全还是危险。

你可以随便叫一个AI编程助手去问“这段diff可能出什么问题”,它会给你一段回复。问题在于:这种自由形式的答案太容易一眼扫过去、打个哈哈就过了,而且每次问,回答都不太一样。没有一个标准逼着模型把推理过程摊出来——没人要求它把“未受保护”的结论对应到具体的文件和行号,也没人要求“严重”这个词背后有比“听着吓人”更精确的度量。这正是Assumptions被造出来的原因。它是一个SKILL.md文件——没有构建步骤,没有任何外部依赖,不用跑服务器,也不需要登录账号——唯一做的事,就是强制把智能体的审查结果塞进一个固定、有证据背书的格式里。

这个工具不取代你的Agent的判断力,而是把那种判断力约束成一种格式,让你能快速审核,而且很难用空话来绕过去。

整个工作流分成四个阶段。第一阶段是触发与范围界定。你要给它一个Git diff或者PR变更内容,再通过一个模式标识告诉它关注哪个风险方向——比如部署、安全、并发或者失败场景。这样不是漫无目的地乱扫,而是针对高风险的路径展开分析。第二阶段是证据驱动的风险扫描,具体拆成几条线:认证与授权范围会检查租户隔离是否被无意打破;幂等性会审查重试和并发逻辑能不能扛住重复请求;迁移相关会检查Schema变更和上线先后顺序;消息队列部分则会验证事件重放和顺序丢失时的行为。每条线都在代码里翻证据,而不是拍脑袋下结论。

第三阶段是状态和置信度的判定,这也是大多数代码审查跳过的一步。对每一个挖掘出来的风险项,它会给出一个状态标识:Verified in Code代表有明确保护,Partial Safeguard说明部分保护,Missing Safeguard表示找不到防护措施,而Uninspected则标明某些范围未审查。与此同时还带一个证据置信度:High、Medium或Low。这个状态和置信度的拆分,解决了一个经典问题——“Unprotected”回答的是“仓库里有没有防护”,而“Evidence confidence”回答的是“我对这个判断有多大的把握”。比如,如果你直接在一个handler里看到缺失了幂等键,那么状态就是Unprotected,置信度是High;如果某个校验逻辑检查得模模糊糊,证据链拼接得比较吃力,置信度就是Low。这样一来,看台账的人不需要靠猜来评估你的审查结论有多可靠。

最后的输出是一个结构化的风险台账——Assumption Ledger。里面每一条发现都必须满足一系列硬性要求才能进榜单:风险被表述成可证伪的条件,比如“重复退款请求已被阻止”,而不是“这段代码看起来是幂等的”;必须附带文件路径和行范围(如果实在拿不到行号,可以用路径和符号来定位,并且绝不允许从摘要或者搜索片段里瞎猜行号);还要明确写出如果这个假设不成立,会带来什么具体后果;如果找到已有防护措施就列出来,没找到就明确写“未在X、Y中找到防护,Z范围未审查”;另外每个条目都必须给出一个证伪测试或者验证步骤;再有就是状态(Protected/Partially protected/Unprotected/Unknown)、证据置信度(High/Medium/Low)和优先级(P0到P3)。

这个设计的巧妙之处在于,它不靠魔法提高审查质量,而是靠一种近乎死板的结构,把“我觉得这可能有风险”变成“我看过的这份证据说明,在xx文件第yy行缺失了某个防护,所以这里是一个P1、置信度高的未保护点,你最好写一个测试来证伪它”。当你面对的是数百行变更和几十条AI生成的噪声警告时,这种格式上的约束就成了沟通效率的分水岭。它不像你用大模型随口一问得来的那种回答——那种回答你会本能地略读,然后挑几条改改。Assumptions产出的台账是让你一行一行盘查的,因为每一条都是可以追问、可以复现、可以直接点进代码里复核的断言。

所以它本质上不是让审查变得更聪明,而是让它变得更诚直——把“我看过了,没啥大问题”这种模糊安全感,替换成“我看过这里和这里,没有找到防护,需要你确认一下”的硬证据。对于受够了线上事故复盘会上互相甩锅的团队来说,这可能比一百次“AI建议”更有用。