前阵子我把团队里的 AI 代码审查从“单模型跑一遍”改成了“多模型协作”的玩法,折腾了大半个月,整体效果比预期好不少。这篇文章就聊聊我为什么放弃单一模型、怎么设计这个多模型审查团队的架构、每一步在工程上怎么落地,以及这中间踩到的一堆坑,希望对正在做智能代码审查或者准备往这个方向试水的朋友有点帮助。
先交代背景:我们团队日常代码量不小,CI 上早就挂了静态检查和单测,但真正的人肉 Review 永远是瓶颈,尤其是一些低级错误、跨文件影响和安全隐患,只靠开发者自己很容易漏。于是我们尝试引入大模型来做智能代码审查,最开始就是“每次 PR 丢给一个大模型,让它输出问题清单”。然而用了一段时间后发现,单一模型看起来很强,但真放到工程化场景里总有种使不上劲的感觉。后来我们换成了多模型组合,相当于组了一支“审查团队”而不是雇一个“全能员工”,把问题按类型、风险、语言、变更范围拆开,分配给不同模型来干。
为什么偏偏是多模型?代码审查这个任务不同于聊天、翻译、写文章,它要求模型既理解全局语义,又对细节敏感;既懂通用编码规范,又能盯住安全边界。一个模型往往很难在所有维度上同时做到足够好。我的经验是:通用能力强的模型在架构影响分析和大上下文理解上占优,而另一些更偏安全对齐或更擅长某个语言生态的模型,在找隐患和风格问题时反而更稳。与其强行让一个模型变身“全栈专家”,不如把它拆成一个各有所长的小团队,让它们在各自擅长的那一档上发挥。
下面从设计思路、架构分工、落地细节、评测方法和避坑经验几个方面展开聊。
1. 为什么单一模型撑不起代码审查这件事
1.1 代码审查不是“读代码”,是“审变更”
很多人有个误解,觉得 AI 代码审查就是把 diff 扔给大模型,让它找出明显的 bug。但真正的 Code Review 要干的事复杂得多:它要评估这次变更有没有改变原有行为的意图、有没有破坏调用方的契约、有没有漏掉对应的测试、有没有引入安全隐患或者性能回退、符不符合团队的代码规范。这比“这段代码有没有语法错误”高了一个维度。
举个例子,你改了某个工具函数的入参类型,编译能过,单测也绿,但另一个服务还在按老的字符串方式调用。单一模型如果没有跨文件理解能力,可能根本发现不了这个问题。这类问题不是代码质量问题,而是“变更影响范围”问题,需要模型有全局视野和调用链推理能力。单一模型如果上下文窗口不够大,或者“注意力”不够分散,就很容易只盯着当前文件里的那几行改动用劲。
代码审查更像是一个老师的批改工作:不但要看答案对不对,还要看解题思路对不对、是否适合这个学生当前的阶段、会不会留下后续隐患。单一模型如果训练数据分布偏向某一个语言或框架,相当于这个老师只擅长某一门课,其他科目硬着头皮批,错误率自然高。
1.2 单一模型越用越别扭的三类场景
我实际用了大概一个季度,梳理了三个最典型的别扭场景。
第一,语言和框架偏好问题。我们团队有 Python、Go、TypeScript 三种主语言,还有些 Java 旧服务。一些通用模型的 Python 能力明显好于 Go,或者反过来。你让同一个模型审查不同语言的 PR,它的“手感”是不一样的,甚至不同框架下的最佳实践也容易记混。比如让它审 Go 的并发代码,它有时会把 Python 风格的思维带进来,给出的建议很别扭。
第二,上下文窗口限制导致“只看了局部”。大模型的上下文窗口在增长,但把一个大 PR 的全部 diff 都塞进去,仍然是件很奢侈的事。有的 PR 会涉及 20 多个文件,改动上千行,塞进去后模型不仅可能超出窗口,还会出现“中间的细节遗忘”现象,review 意见变得泛泛而谈。单一模型一旦被塞爆,输出质量断崖式下降,这不是换一个更大模型就能解决的问题,因为更大的窗口意味着更高的成本和更长的延迟,工程上不可持续。
第三,误报和漏报是跷跷板。单一模型为了尽量少漏报,倾向于输出更多疑点,结果就是误报率很高。我们测试初期,单模型给出的 Review 评论里真正值得修改的可能不到三成。开发者被 AI 狼来了搞烦了之后,甚至会直接忽略机器评论。反过来,如果压低误报,又会漏掉一些真正有价值的提醒,安全漏洞就这样沉底了。这属于单一模型的本质矛盾:你很难在同一个“性格”里同时要求它激进和保守。
我用一个简单的表格总结一下当时遇到的痛点:
| 审查维度 | 单一模型的常见表现 | 带来的实际影响 |
|---|---|---|
| 跨文件影响分析 | 上下文不足,只在当前文件里打转 | 调用方被破坏的问题漏检 |
| 安全隐患识别 | 知识有覆盖面,但偏通用,缺少针对性规则 | SQL 注入、越权等典型问题漏报 |
| 代码风格一致性 | 过于“老好人”,倾向给出中庸建议 | 团队规范无法被严格执行 |
| 测试完整性 | 经常只建议“补单测”,给不出方向 | 没有实际指导意义 |
| 误报控制 | 漏报和误报难以兼顾 | 开发者不再信任机器评论 |
那段时间我一直在琢磨,代码审查的最终目标不是“让一个模型读懂代码”,而是“让一组模型在不同维度上互相补位”。单一模型的边界,恰恰是这套多模型方案的起点。
2. 多模型审查团队的架构设计与模型分工
2.1 不是堆模型,是组团队
多模型不是简单地把几个模型的结果拼在一起,那样只会得到一堆互相重复、格式混乱的评论。我参考实际团队运作方式,把不同的模型当成审查团队里的不同角色:
- 主审 Reviewer:负责整体逻辑和变更合理性,通常选综合能力最强的模型,赋予大上下文和全局视角。
- 规则专家 Expertise Reviewer:负责特定技术栈的问题,比如 Python 并发、Go 内存模型、TypeScript 类型体操这些专项内容,选择在该领域数据上有优势的模型。
- 安全审计员 Security Reviewer:专门盯安全问题,倾向选安全对齐做得更细的模型,并配合安全规则库做更严格的扫描。
- 汇总与仲裁人 Moderator:把上述角色的输出进行归类、去重、排序,再对冲突意见做仲裁,一般由成本可控而指令遵循能力较好的轻量模型来当。
这样设计背后有一个工程逻辑:单一模型是全栈工程师,但方向太多,而每个角色的聚焦范围小了以后,提示词可以配得更细,输出会显著更稳定。这和带团队是一样的,你让一个人同时负责需求理解、架构设计、代码评审、安全测试,他一定不如一个各司其职的小团队做得好。
组团队时有个原则:不要“多多益善”。我一开始试过把所有能调的模型都调一遍,结果评论数量爆炸,很多意见建议互相矛盾,仲裁的成本比收益还高。后来收敛成了“三个审查执行者 + 一个汇总仲裁”的最小配置,效果反而最好。模型数量超过一定阈值,边际收益会快速下降,而成本和延迟直线上升。
2.2 按审查维度分流,而不是按模型名气排序
多模型分工最怕“谁强谁上”,正确的思路是“谁合适谁上”。我们最终采用了按审查维度分流的策略,而不是让每个模型都看全部 diff。
先说综合逻辑审查维度。这个角色需要看完整变更、理解业务意图、发现逻辑漏洞和方法设计问题。适合配备长上下文能力和推理能力较强的模型。实际操作中,我们会把 PR 描述、相关 issue 上下文、主要文件的变更切片按调用关系组织后交给它,让它重点回答“这个改动会不会破坏现有行为”。
再说安全隐患维度。这属于专项任务,通用模型有时会把安全建议说得太概念化。比如“请检查是否可能存在注入风险”,结果它就回一句“建议使用参数化查询”。说法没错,但不落地。真正的安全审计要求结合具体代码路径,指出哪一行输入源可能不可信、怎么传到了危险函数里。这一维度我们靠“安全审查专用提示词 + 若干安全规则样例 + 对安全更敏感的模型”来覆盖。评测下来,这类模型对漏洞特征的记忆更贴近 CWE 分类体系,比通用模型更“容易往坏处想”。
第三个是代码风格与可维护性维度。我们引入了一个更“较真”的模型角色,专门盯命名、函数长度、重复代码、异常处理方式等工程规范类问题。这里不是看模型智力多高,而是看它听不听话、输出格式稳不稳定。有些轻量模型在规范类任务上的表现甚至比大模型更合适,因为它的任务是“照着规则找茬”,不需要太多发散思维。
最后,汇总与仲裁维度需要的是一个“理性人”角色。它不重新审查代码,而是把几个上游模型的评论合并、判断是否有重复或冲突,再给出一个统一的评审报告。这个角色不需要很强的代码能力,但对指令理解、JSON 结构拆解和内容去重要求比较高,所以我们用了一个相对便宜、响应速度快的模型。
2.3 路由层:一份 PR 进来怎么分发
有了角色,还需要一个路由分发层。用大白话说,一份 PR 进来后,系统要决定让哪个角色先看、看哪些部分、以什么顺序交回结果。目前我们用的是四层路由策略。
第一层是按语言和框架分流。大部分 PR 都有主语言,我们把“前端 TypeScript 变更”送到更熟悉 JS/TS 生态的审查角色,把“后端 Go 服务变更”送到对应角色。不要把所有语言都塞给同一个模型,因为提示词里如果混入“你可能需要处理 Python、Go、Java、TS 等”,模型反而不知道该把注意力往哪放。
第二层是按风险等级分流。根据变更涉及的服务重要性、是否改了鉴权/支付/数据删除等高风险逻辑、是否涉及 DB Schema 变更,将 PR 标记为 high/medium/low。高风险 PR 会启用全部角色并增加安全专用规则,低风险变更只跑一次轻量主审,避免每次都动用全部模型导致成本失控。
第三层是按文件依赖关系做切片。一个大 PR 我们不会一次性把所有 diff 塞给模型,而是先分析变更文件之间的依赖图,把真正相关的文件组织成一个审查单元。比如你改了一个 API 定义文件和两个调用文件,这三个文件应该进入同一个上下文;而一个无关的工具类文件改动则单独评估。这个切片逻辑是解决上下文超限的关键手段。
第四层是时序路由:先并行跑几个审查角色,等结果回来后再交给仲裁角色。不同模型审查可以并行,节省延迟;仲裁必须在所有结果返回后触发。有些团队喜欢做成“两轮辩论”,即主审先给出意见,安全角色再对主审意见做复核。这个思路在某些场景有用,但对大部分业务代码来说,单轮并行已经够用,两轮会让整个链路慢非常多。
3. 落地一套可用的多模型审查流水线
3.1 整体流程:从 PR 触发到生成报告
把架构想清楚后,流水线本身就不复杂了。我们的实现大概分九个环节:
- 收到 PR 创建或同步事件(包括 commit push),触发审查任务。
- 拉取变更元信息:PR 标题、描述、变更文件列表、改动行数、目标分支。
- 做变更预处理:识别语言分布、依赖关系、风险等级。
- 根据路由策略生成审查计划,决定调用哪些模型、每个模型看哪些切片。
- 并行调用多个模型 API,把各自的角色提示词和代码切片组合起来。
- 等待所有模型返回后,先做一轮规则层面的后处理,过滤明显不合格的意见(比如空话、与变更无关的统一模板)。
- 交给汇总仲裁模型,统一输出一份结构化报告。
- 把报告加工成 PR 行内评论或汇总评论,按严重程度分级展示。
- 通过 webhook 把摘要推送到 IM 工具,通知开发者和团队负责人。
其中第 3 步和第 4 步是整个流水线里最容易被忽视的。很多团队直接在第 2 步后就把所有文件丢给模型,这是不对的。我们专门写了一个轻量解析器,自动判断改动文件的扩展名和目录,并读取团队自定义的 review-config 文件。这个配置文件可以声明某些目录属于高风险模块,某些目录不需要 AI 审查,大大减少了无效扫描。
3.2 一模型一策略:Prompt 不能一套走天下
Prompt 设计是这个项目的核心中的核心。很多人的第一版方案是写一个通用 prompt,里面写“你是一个资深代码审查专家,请审查以下代码”,然后复制给所有模型。这绝对是大忌。
不同角色的 prompt 必须分开写,差异点包括角色定位、关注重点、输出边界和禁止事项。我举个例子,主审 Reviewer 的 prompt 大概是这样的:
你是一名资深后端工程师,正在参加一个 Go 项目的代码评审。 请从“变更逻辑是否正确、是否有边界遗漏、是否破坏调用契约”三个角度审查。 背景信息: - PR 目标:xxx - 关键文件:网关层改动、订单服务调用方式调整 - 已知约束:不要给出风格类建议,那些由专门角色负责 请严格输出 JSON 格式,不要输出任何多余解释: { "issues": [ { "file": "文件路径", "line": 行号或函数名, "severity": "high|medium|low", "title": "问题摘要", "detail": "问题说明与修改建议", "confidence": 0-1 } ] }而安全审计角色的 prompt 则完全不同的侧重。它不需要关心业务逻辑是否自洽,只需要专注攻击面,并且输出格式里要包含“风险类型”字段,可以是注入、越权、敏感信息泄露、SSRF、不安全的反序列化等。这个差异化很重要,因为每个模型只有在边界收窄的时候,才能把注意力集中在它该看的东西上。
我再说一个细节:prompt 里让模型输出 confidence 这个字段,最终效果会好很多。你要求模型自己对每条评论给一个置信度,等于强制它做一次自我判断,实际上可以去掉很多泛泛而谈的废话。我们在后处理阶段只保留 high、medium 和一个最高置信度的 low,其余直接丢弃。
另外,给不同模型的上下文切片千万不要完全一样。安全角色可以只看涉及外部输入、文件读写、权限校验的代码路径;主审角色则看整体变更。这就相当于给不同角色安排不同的阅读材料,否则它们的工作重复度太高,浪费 token 也浪费彼此时间。
3.3 结果归一与冲突消解:谁说了算
多模型并行之后会有一个尴尬情况:模型 A 说这里有问题,模型 B 说这里没问题;A 认为严重程度是 high,B 认为只是风格问题。如果没有一套裁决机制,最终报告会让人一头雾水。
我们的做法分三步。
第一步是让所有模型在最开始就统一输出结构。无论是什么角色,输出都遵循我们自定义的一套简化 JSON schema。字段不外乎 file、line、severity、category、title、detail、confidence。差异不在结构上,而在内容上,安全角色会在 detail 里说明威胁场景,主审角色会在 detail 里解释逻辑矛盾。
第二步是自动去重和相似度聚类。如果多个模型提到同一文件同一行或同一函数,我们会把它们当作同一评论的不同来源,不做简单合并,而是保留一条主建议,并把“有多少个角色提到了这个问题”作为附加权重。如果两个模型从不同角度指出同一个隐患,比如主审说“这段逻辑可能导致空指针”,安全角色说“这个外部输入没有校验就进入了下游”,其实指向同一行代码的同一类问题,我们会尝试把它们合并成一条更完整的评论,既能说明问题,又能给出更具体的修复建议。
第三步是仲裁模型决策。所有自动处理后仍存在的冲突意见,才交给仲裁模型处理。仲裁模型不直接看代码,它只拿到几条互相冲突的意见和对应的上下文字段。我们会要求它输出一个最终意见,并解释理由。这个设计很像团队里的技术 Leader:你不需要亲自把每行代码看完,但你有足够的信息判断两个下属的争论谁更合理。
这里有个非常值得说的经验:仲裁模型和主审模型不能是同一个模型,至少要保持不同的温度参数和不同的 prompt 风格。否则就会出现“自己肯定自己”的问题,无论主审说得对不对,仲裁都倾向认同它。我们实测把同源模型同时做主审和仲裁,冲突消解的效果很差。后来我们特意用一个更偏“批判性”风格的模型担任仲裁,它反而会纠正主审的一部分误判。
4. 效果评估:比单一模型强在哪,坑在哪
4.1 用标注 Bug 集做回归评测,别靠感觉
任何审查系统没有评测都是耍流氓。我们在搭建这套多模型方案的第三天就开始准备评测集了,而不是等工作全部做完才去验证。评测集的做法是:找最近三个月已经合并进主干的真实 PR,由团队里经验比较丰富的工程师人工找出其中的真实缺陷,把它做成标注集,大概选了 80 个有明确“缺陷”的样本和 40 个没有明显缺陷的正常样本。
有了这个集子,我们定义了三个核心指标:缺陷命中率(Recall),即真实缺陷里有多少条被审出来;误报率(1 - Precision),即 AI 报出来的问题里有多少不属于真实缺陷;有效建议率,即开发者在实际修改中真正采纳的 AI 评论比例。最后一个指标很主观,却最能反映体验,如果开发者天天忽略你的评论,那精度再高也没意义。
拿早期“单一最强模型方案”和现在的“多模型组合方案”做对比,结果非常有意思。单模型在逻辑缺陷上的命中率尚可,但在安全类缺陷上漏掉很多;多模型组合显著提升了安全类缺陷的 Recall,逻辑类也略有提升。代价是总的评论数量变多了,需要仲裁过滤的垃圾意见也相应增加。不过经过过滤后,真正展示给开发者的评论反而更精简了,有效建议率从之前的不到三成提升到了五成多。
一个粗略的对比表:
| 指标 | 单一最强模型 | 多模型组合(过滤后) |
|---|---|---|
| 逻辑缺陷命中数 | 11 / 20 | 14 / 20 |
| 安全类缺陷命中数 | 6 / 20 | 15 / 20 |
| 风格与规范问题命中数 | 8 / 20 | 12 / 20 |
| 每次 PR 平均评论数 | 16 条 | 32 条原始 / 7 条过滤后 |
| 开发者有效采纳率 | 约 28% | 约 52% |
我必须说明,这个数字只代表我们内部项目的情况,并不能直接推广。但它揭示了一个普遍规律:多模型组合的效果优势主要集中在“专业维度覆盖”上,而不是“单个模型智力变高”。多模型不会让最强的模型变聪明,但它能让那些之前没被覆盖到的漏洞类型被另一个模型捡起来。
4.2 成本与延迟的控制手段
多模型方案最让人纠结的就是钱和时延。我们上线初期,一次主流程 PR 审查大概要花 5-10 元以上的 token 费用,全程耗时可能超过三分钟,这对很多节奏快的团队是受不了的。
我控制成本的第一个思路是做分级调度,不给所有 PR 同样的待遇。低风险的依赖升级、文档变更、纯前端样式修改只跑一个轻量模型;核心业务和涉及数据安全的高风险 PR 才启用完整的多模型流程。分级之后,整体费用大概只用了原来无差别跑全量方案的 40%。
第二个思路是缓存和去重。同一时间段内,如果多个 PR 改动了很多相同的文件,我们会把已审查文件的结论缓存下来,按文件 hash 做 key。虽然真正合入代码前每个 commit 都可能变,但对于同一天内反复 push 修改同一文件的 PR,缓存能省掉大量重复计算。
第三个思路是模型参数调低一点。多模型方案下每个模型的任务边界都聚焦了,对最大输出 token 的要求并不高。我们把每个角色的输出上限限制在 800-1500 token,生成的评论不会太长。这既节省费用,也倒逼模型说重点,不要洋洋洒洒写一堆铺垫。
延迟方面,最有效的办法就是并行调用。四个角色各自看不同切片,不要做成串行依赖。我们实测,全部并行比串行节省约 60% 的时间。另一个技巧是给每个模型调用设置合理的超时时间和重试次数,默认 30 秒超时,超时后标记该角色本次缺席,由仲裁阶段根据已有结果补位,而不是无限等待拖垮整个流水线。
4.3 多模型的新问题:误报叠加与责任模糊
多模型不是银弹。它带来一个单模型没有的新挑战:误报叠加。如果每个模型的误报率是 30%,三个模型叠加后,哪怕经过了聚类和仲裁,最后漏到开发者那里的评论里仍然可能混着不少“看似有道理但实际不需要改”的话。因为仲裁模型自己也会出错,它可能把两条不准确的建议合并成一条看起来很专业的误导评论。
还有一个问题是责任模糊。单模型审查时,如果它漏了安全隐患,开发者会归因于“这个模型不行”,问题很清楚。多模型审查时,如果漏了,你很难定位是路由阶段把代码分给了错误的模型,还是负责安全审查的模型能力不足,又或者是切片把关键代码切掉了。这种模糊性对系统迭代是不利的。
所以,每一轮审查任务我们都会记录完整的溯源信息:评论是哪条链路生成的,来自哪个模型、哪个 prompt 版本、哪个切片上下文。这个可观测性非常关键,否则后续优化只能靠猜。
5. 实践中的踩坑记录与排查技巧
5.1 Prompt 在各种模型之间的“水土不服”
我们最初写了一套自认为很完美的 prompt,结果在模型 A 上表现很好,换到模型 B 上直接崩了。现象是:模型 B 完全忽略了输出 JSON 的要求,把一大段分析性文字直接输出,导致后处理解析失败;还有的模型对“severity”字段理解不同,有的认为 high 是“高危威胁”,有的认为 high 是“优先级很高”。
排查之后我发现,这些模型的指令遵循能力差异非常大。有的大模型天生就适合复杂指令,而轻量模型在指令里信息一多就容易丢。解决办法不是去骂模型,而是把 prompt 拆短,把关键指令比如“只输出 JSON”放到 prompt 最前面和最后面各写一次,再加上 few-shot 示例。给每个角色都准备一个标准的输出示例,通常放一条“符合要求的正面案例”和一条“不符合要求的反例”,这对稳定格式特别有效。
5.2 把整个 Merge diff 塞给大模型的代价
有段时间我们图方便,直接把一个改动上千行的 PR 全量塞给了一个长上下文模型。从结果看,模型并没有变得“全局视野更广”,反而产生严重的注意力稀释。它给出的评论分布在很多浅层问题上,比如建议把变量名改得更语义化,但真正严重的逻辑漏洞反而被淹没在长代码里。
人看长 PR 也会累,模型也一样。后来我强行规定:单个审查单元改动行数超过 200 行时,必须按逻辑模块拆成多个单元再分发给不同模型,每个模型只负责一个模块。虽然这增加了一点调度的复杂度,但每条评论的针对性都提高了。更重要的是,我们要在切片时保留函数的完整上下文,而不是硬切行号,否则断在函数中间,模型大概率会错乱。
5.3 模型之间互相带偏:仲裁模型需要独立的“人格”
我踩过最大的一个坑是让仲裁模型去“评论”主审模型的意见,而不是“仲裁”它们的意见。一开始仲裁模型的 prompt 是“以下是几个模型对同一 PR 的评论,请你判断哪些正确”,这个思路看起来没问题,但它实际上会被上游模型的详细解释带跑。特别是当主审模型给出很强的 confidence 并且解释得非常通顺时,仲裁模型几乎没有独立判断能力。
后来我特意调整了仲裁模型的输入方式:不展示具体代码上下文,只展示 file、line、title、detail 的摘要,并对上游模型做匿名化处理,不让仲裁模型知道哪条来自哪个模型。这样一来,仲裁模型被迫根据“几个观点本身”来判断,而不是根据“这句话是不是权威模型说的”。这个改动让冲突消解的自动准确率明显上升。
5.4 测评论集会过时,需要建立 Badcase 回流机制
我们第一版评测集的缺陷是从三个月前的 PR 里挖出来的。跑了一个月后,我们发现自己陷入一个怪圈:新模型版本在这些“旧题”上表现越来越好,但真实场景里新增的缺陷类型却覆盖不到。代码审查的评测和其他模型评测不同,它特别容易过时,因为团队的技术栈、业务场景、依赖库都在快速变化。
后来我建立了 Badcase 回流机制:每个周从最近被开发者标记为“这个 AI 没审出来”的问题里挑一批,补充进评测集;同时把开发者觉得“这个 AI 评论没必要”的样本也回流到误报测试集。这种持续迭代的方式比一次性大评测更有价值。所有上线到生产链路的多模型变更,都必须先在评测集上跑一遍回归,得分低于上一版就不允许发布。
6. 多模型审查常见问题速查
下面这些坑和排查思路基本覆盖了我们实践里碰到的大部分问题,我用表格的形式列出来,方便后面要搭同类系统的团队直接对号入座。
| 问题现象 | 可能原因 | 排查与解决办法 |
|---|---|---|
| 某个模型频繁返回超时或解析失败 | 单次请求内容太长,模型输出不稳定 | 检查请求上下文大小,把大 PR 切片后再发送;输出 JSON 解析失败就加 few-shot 并启用格式约束 |
| 评论大量重复,且集中在前几个文件 | 路由时没有按依赖关系重组切片 | 增加文件依赖分析,把调用链相关的文件放入同一上下文,减少重复扫描 |
| 安全类缺陷漏报严重 | 安全角色使用的 prompt 太泛,模型不知道看什么 | 给出具体威胁类别和危险函数样例,并且只切与数据流相关的代码片段给安全角色 |
| 仲裁模型总是偏向主审模型 | 两个模型同源或仲裁 prompt 暴露了来源 | 匿名化模型来源,仲裁只接收规范化字段;选用不同指令风格的模型做仲裁 |
| 开发者反馈评论“没营养” | 后处理阶段过滤掉太多的 low 级别问题,剩下都是框架性套话 | 提高 low 级评论的保留门槛,只保留能给出具体修改行的建议 |
| 成本飙升 | 所有 PR 都跑全模型链路 | 引入风险等级和文件类型路由,低风险 PR 降级到轻量单模型 |
| 修复一轮后新缺陷仍漏 | 评测集老化,不覆盖新的缺陷类型 | 建立周级 badcase 流入机制,针对真实反馈更新评测集 |
表格能覆盖的是大多数通用问题,但每个团队的代码库都有自己的特殊语境。我的建议是遇到某种缺陷反复漏检时,不要第一时间怀疑模型智商,先去看给模型的上下文切片是否真的包含了能发现该缺陷的信息。很多时候模型不是看不到,而是对应的上下文根本没有被送进去。
7. 一些后续扩展的小方向
这套多模型审查团队的系统第一个稳定版本用了大约三周,现在已经完整跑在我们的 CI 主链路里。它是所有 PR 合入前的一道机器关卡,但不具备一票否决权,最终决定权还是掌握在团队开发者手里。未来我打算在几个方向继续延展。
一个方向是把代码变更摘要生成能力和审查能力打通:让主审角色先输出一份简洁的变更说明,再基于这份说明做后续审查,相当于让模型拥有“发现自己到底改了什么”的元认知能力。这个思路目前已经有小规模实验,效果还不错,生成的评论更有针对性。
另一个方向是引入多轮复查:对开发者修改过的 commit 只做增量审查,而不是重新扫全量 diff。这样能把一次 PR 流程中多次提交的累计成本降下来,也是提高开发者体验的关键一环。很多现成工具在这块做得很粗糙,每次提交都全量重扫一遍,既浪费时间又让开发者收到大量重复评论。
最后想说的是,代码审查这件事很难做到百分之百自动化,多模型组合只是把机器能做的事做得更可靠,把人的精力省下来去复核那些真正有争议的判断。我个人在实际操作中的体会是:先在几条真实 PR 上跑通小范围实验,不要让系统一周内直接覆盖全部仓库,哪怕多花一点时间在评测和反馈收集上,也比上线后被开发者集体拉黑要好。