首页 / 资讯中心 / 文章详情

多Agent协作让AI代码审查召回率翻倍的实践

多Agent协作让AI代码审查召回率翻倍的实践 ★ FEATURED ARTICLE
前阵子我拿一个历史遗留的支付网关项目做了个实验11.6万行Java代码让Claude以单Agent方式去查Bug用尽各种提示词优化单次最高只找到27个问题。后来我换了个思路让Claude自己组队——架构审查Agent、并发检查Agent、边界条件Agent、资源管理Agent各查各的最后由一个裁决Agent汇总合并结果一口气找出66个问题召回率直接翻倍还多。这个数字之差不是模型变聪明了而是Agent协作机制带来的质变。这篇文章我就把整个实验的来龙去脉、设计思路、提示词模板、上下文管理技巧和踩过的坑完整拆开给做AI工程化或者想在团队里落地AI代码审查的朋友一个可以照抄的参考。1. 为什么单Agent查Bug总是差一口气1.1 不是模型不够强是上下文嘴太小先算一笔账。11.6万行代码按平均每行20个token粗估全量就是230万token以上。市面上任何商用大模型的上下文窗口都装不下这个量级所以单Agent方案实际上必然要分片。分片之后问题就来了一个Bug往往不是单文件的问题而是跨文件、跨模块的调用关系导致的。比如一个支付金额校验的缺陷可能在订单服务里写了错误的数值比较在支付服务里又没有二次校验在数据库层还有精度丢失问题。单Agent每次只能看到其中一个文件它的判断依据天然是残缺的等于让一个人戴着望远镜找针看到哪里都像又哪里都拿不准。我试过各种缓解手段把相关文件拼进同一窗口、先用RAG检索再喂给模型、让模型自己决定要看哪些文件。结果都不理想。主要原因在于模型一旦看不到完整调用链就倾向于靠猜测补全逻辑猜对了皆大欢喜猜错了它就报一个幻觉Bug出来你还得花时间验证真伪。1.2 注意力漂移查着查着就走神了单Agent查Bug另一个隐蔽问题是注意力漂移。模型处理超长上下文时注意力分布是不均匀的原则上开头和结尾的内容权重更高中段内容容易被忽略。这就导致一个典型现象同一个Agent在同一个项目上如果我把代码顺序打乱它报出的Bug集合差异非常大有的问题在这个顺序下能发现换个顺序就漏了。更麻烦的是任务一致性难以维持。让一个Agent连续审查十几个文件查完第5个文件之后它可能已经忘了自己是在找Bug开始无意识地复述代码逻辑、解释代码意图甚至自己开始写改进建议。我对比过输出内容早期文件的审查结果里还有具体的行号和缺陷描述到后期文件就变成泛泛而谈的建议优化了根本没有定位到具体问题。1.3 单一角色必然存在思维盲区代码审查本来就不是单一维度的事它至少包含这些视角审查维度关注点典型缺陷业务逻辑条件判断、状态流转、异常分支金额校验缺失、状态机死循环并发安全锁、原子性、线程安全重复提交、死锁、数据竞争边界条件null、空集合、极端值NPE、越界、除零资源管理连接、文件句柄、内存连接泄漏、未关闭流安全合规注入、越权、敏感数据SQL注入、权限绕过单Agent在给定一个宽泛的找Bug任务时默认会偏向业务逻辑类问题因为它最容易从代码表面看出来。并发问题和资源泄漏问题需要结合执行时序和运行场景去推导模型在单一窗口下很难形成这种全局判断。我观察到单Agent报出的27个问题里业务逻辑类占了将近七成并发和资源类加起来不到五个这明显是角色单一导致的盲区。2. 多Agent组队查Bug的整体设计让模型学会开评审会2.1 角色分工按缺陷类型分配岗位意识到单Agent的天花板之后我参考了真实团队做代码评审的方式不是一个人从头看到尾而是不同背景的人各看各的角度前端同事关注交互边界后端同事关注接口一致性DBA关注SQL效率。于是我把这套逻辑搬到了Agent设计上。实验里我设置了五个角色每个角色只负责一个维度。架构审查Agent负责跨模块调用链的正确性业务逻辑Agent负责状态机和业务规则并发检查Agent专门看多线程场景资源管理Agent盯连接和内存安全审查Agent查注入和越权。为了让每个Agent的注意力足够聚焦我会在提示词里明确写清楚你只需要关注某某类问题其他问题不要报告后面会说具体模板。角色数量不是越多越好。我试过从2个加到5个召回率确实在提升但到6个以上就开始出现大量重复报告和幻觉问题。因为角色之间关注维度会有交叉比如安全审查和边界条件审查在非法输入校验上高度重叠这个分寸需要自己拿捏。2.2 协作流程分头扫描、两两交叉、统一裁决多Agent不是简单地把任务丢给多个Agent各跑一遍它需要一套明确的流程。我用的流程分三个阶段。第一个阶段是分头扫描。每个Agent拿到同一份代码库的索引和划分好的代码切片独立执行审查任务产出结构化的问题列表。这个阶段刻意不让Agent之间互相通信避免早期结论相互干扰。第二个阶段是交叉复核。把第一阶段每个Agent的问题列表随机分配给其他Agent进行复核。复核Agent要判断这个问题是否真实存在、严重程度如何、有没有更精确的复现路径。这一步能过滤掉相当一部分幻觉Bug因为不同角色从不同视角看同一段代码很容易发现这个所谓Bug其实是设计如此的误报。第三个阶段是统一裁决。由一个裁决Agent接收所有复核通过的问题去除重复项按模块和严重度排序产出一份最终报告。裁决Agent的提示词里有一条很关键要求它把每个问题映射到具体文件、函数和行号并且标注置信度。这为后续人工验证节省了大量时间。2.3 为什么组队比单Agent多跑几遍更有效有人肯定会问单Agent多跑几遍把每次的结果合并起来不也能提高召回率吗我最初也是这么想的但实测下来效果很有限。原因在于同一个模型在相同提示词下即使随机性带来一些差异它的思维模式依然是同质的。你可以把单Agent多跑几遍理解为同一个人反复用同一种思路看同一份代码发现的问题类型基本还是那一类。多Agent的价值在于把不同的思维框架固化到了提示词里而且每个Agent的任务约束让它的注意力始终钉在特定维度上。并发检查Agent不会去关心业务逻辑是否合理它就只盯锁、原子性和共享变量反而更容易发现那些藏在执行时序里的问题。认知多样性才是召回率提升的根本原因这一点在实验数据里体现得非常明显。3. 核心实现提示词、上下文与任务切分3.1 一套可以直接抄的角色提示词提示词是这次实验里最核心的部分。我的经验是角色提示词不能只写一句你是并发审查专家那不够必须把审查范围、输出格式、禁止事项全部写明。下面是我用的并发检查Agent提示词模板其他角色照葫芦画瓢就行。你是一名资深的Java并发编程审查专家。你的任务是对给定的代码片段进行并发安全审查。 只关注以下问题 1. 共享变量的可见性和原子性 2. 锁的粒度和死锁风险 3. 线程池使用是否正确 4. 集合类的线程安全问题 5. 竞态条件和重复提交问题 不要报告其他类型的缺陷例如业务逻辑错误或性能优化建议。 输出格式为JSON数组每个元素包含filePath文件路径、lineNumber行号、severityhigh/medium/low、problemType问题类型、description缺陷描述、suggestion修复建议。 注意只报告你有把握的真实问题不确定的请标记confidence为low。这段提示词里最关键的是最后两句。一句是把输出格式钉死为JSON数组这样后续流水线可以直接解析另一句是只报告有把握的真实问题并标记置信度这能显著压制幻觉Bug。我做过对比加了这句之后幻觉问题数量大概下降了40%。3.2 上下文管理的三条铁律多Agent方案比单Agent更吃上下文管理因为每个Agent都需要尽可能多的相关信息但窗口又是有限的。我总结出三条铁律供大家参考。铁律一不同角色给不同的代码切片。并发检查Agent需要看的是多线程相关的类、共享状态、锁使用而业务逻辑Agent需要看的是订单状态机、支付回调这些核心流程。如果统一给所有Agent一份相同的代码切片等于浪费了角色的差异性。我在实验里会给每个角色单独生成一份代码清单这份清单可以借助简单的静态分析工具生成也可以直接让调度Agent根据项目结构自行决定。铁律二用代码地图代替原始全量代码。什么叫代码地图就是给Agent一份结构化的项目索引包含包结构、类名、关键方法签名、类之间的调用关系而不是把11.6万行源码一股脑丢给它。代码地图消耗的token远小于原始代码但它给Agent提供了导航能力使它能精准定位到需要深入看源码的文件再针对性地拉取。这个策略让我的上下文使用量减少了约60%同时召回率没有明显下降。铁律三输出结构化结果禁止自由发挥。自由文本的问题在于Agent会写很多分析过程真正的缺陷反而被淹没在一大段流畅的叙述里。强制JSON输出后每个Agent的产出就是一行行明确的问题记录后端的去重和汇总流程处理起来非常方便。我见过很多团队做Agent应用时不约束输出格式结果下游流程被迫用正则去抓关键信息效率和准确率都很差。3.3 任务切分的两种粒度对比给Agent分配任务时有两种切分粒度。按模块切分是纵向的比如把支付网关拆成订单模块、支付模块、对账模块、通知模块每个Agent负责一个模块的所有方面。按缺陷类型切分是横向的每个Agent只看自己负责的缺陷类型穿透所有模块。纵向切分的优点是局部上下文完整Agent容易理解一个模块的内部逻辑适合模块内部的状态管理类Bug。横向切分的优点是能发现跨模块的共性问题比如所有数据库操作都没有关闭连接这种规律性缺陷纵向切分下每个Agent只会看到一个模块不具备全局视野。我的实践是推荐混合切分先按模块纵向切分让架构审查Agent、业务逻辑Agent各管几个模块再按类型横向切分让并发检查Agent、资源管理Agent穿透所有模块。这样既保住了局部上下文又覆盖了全局规律性问题。混合切分在实验里的召回率比单一切分方式高出大约20%。4. 实测效果66个Bug到底从哪来4.1 数字背后的含义召回率从27到66我把单Agent方案最好的一次结果27个Bug和多Agent方案的结果66个Bug做了对比按问题类型拆分之后差距非常直观。缺陷类型单Agent最佳多Agent协作提升倍数业务逻辑13171.3倍并发安全2115.5倍边界条件4123倍资源管理3155倍安全合规263倍其他351.7倍多出的39个Bug大头在并发安全和资源管理这两类这正是单Agent最容易忽视的领域。原因也好理解这两类缺陷没法从代码表面直接看出来需要沿着调用链去模拟运行场景单Agent在上下文不足的情况下根本没有余力做这种推演。而多Agent里的并发检查Agent和资源管理Agent可以反复咀嚼同一段代码专门从运行时序的角度去找茬效果自然不一样。4.2 成本与耗时多Agent值得吗提到多Agent方案很多人第一反应是贵。这次实验的成本数据可以说明一些问题。单Agent方案因为要反复尝试才能覆盖更多维度我跑了六轮总计消耗约80万token。多Agent方案因为每个Agent只聚焦单一维度输出更精简五个角色加一个裁决Agent总计消耗约120万token算下来是单Agent方案的1.5倍左右。从召回率看多Agent方案找到了66个问题是单Agent最好一轮的2.4倍。这意味着换算成找到单个Bug的平均成本多Agent方案的实际成本反而更低。更关键的是代码审查里漏掉一个生产环境的Bug修复成本可能是审查成本的几十倍从这个角度看多Agent方案的经济账非常划算。当然这不是说单Agent方案一无是处。如果项目只有几千行代码单Agent完全够用如果只是临时想快速看一遍代码质量单Agent也可以。但只要是中大型项目、历史遗留代码、或者你希望一次就把问题找全多Agent方案的优势是不可替代的。4.3 适合与不适合的场景多Agent查Bug不是万能的我实验下来总结出几个适用边界。最适合的场景是历史遗留系统。这类代码通常没有完善的测试用例也没有清晰的架构文档单靠人肉审查效率极低。多Agent能快速铺开所有模块而且因为它不依赖文档完全靠代码本身找问题反而能把人容易忽略的隐藏问题翻出来。其次是多人交接项目。新接手的开发者对代码不熟不知道该重点关注哪些模块。多Agent一次扫描能产出一份完整的问题地图帮助新人快速建立对项目健康状况的整体认知。不太适合的场景也很明确几百行的小脚本、一次性代码、或者对时延要求极高的实时交互场景。小脚本直接扔给单Agent或者干脆人肉看就行组队反而大材小用时延敏感的线上场景多Agent一轮跑下来分钟级起根本等不起。5. 复现这套方案从零搭一个多Agent查Bug流水线5.1 环境准备复现这套方案不需要重型的框架我用的就是一个Python脚本加模型API直接编排。建议环境Python 3.10以上、模型API访问权限、一份待审查的代码库建议先拿一个3万行以上的中大型项目试手小项目看不出差距。如果你完全没有基础建议先别上框架用最简单的requests循环调API把流程跑通再考虑引入现成的Agent编排框架。很多团队一上来就上重框架结果被抽象概念绕晕了连最基本的角色提示词都没调好。5.2 最小可跑的编排脚本下面这个脚本是我实验后精简的最小版本只保留了核心逻辑初始化角色列表、调用模型API、收集结果、裁决合并。你可以直接替换API接口适配自己的模型供应商。import json import openai # 初始化客户端按需替换 client openai.OpenAI( api_keyyour-api-key, base_urlyour-base-url ) def run_agent(system_prompt, code_snippet): 调用模型API返回JSON格式的Bug列表 response client.chat.completions.create( modelclaude-3.5-sonnet, messages[ {role: system, content: system_prompt}, {role: user, content: f请审查以下代码\n{code_snippet}} ], temperature0.2, response_format{type: json_object} ) content response.choices[0].message.content return json.loads(content) roles [ { name: 架构审查Agent, prompt: 你是一名架构审查专家关注跨模块调用链的正确性... }, { name: 并发检查Agent, prompt: 你是一名Java并发审查专家只关注线程安全... }, { name: 资源管理Agent, prompt: 你是一名资源管理审查专家只关注连接泄漏、未关闭流... } ] def chunk_code(code_files, max_tokens3000): 按token上限切分代码返回切片列表 chunks [] current [] current_tokens 0 for file_path, content in code_files.items(): tokens len(content.split()) if current_tokens tokens max_tokens: chunks.append(\n\n.join(current)) current [] current_tokens 0 current.append(f### {file_path}\n{content}) current_tokens tokens if current: chunks.append(\n\n.join(current)) return chunks def run_pipeline(code_files): 执行完整的多Agent审查流水线 chunks chunk_code(code_files) all_issues [] for chunk in chunks: for role in roles: result run_agent(role[prompt], chunk) all_issues.extend(result.get(issues, [])) # 裁决Agent去重合并 judge_prompt 你是最终裁决者请合并以下问题列表去重并输出最终报告... final_result run_agent(judge_prompt, json.dumps(all_issues)) return final_result if __name__ __main__: code_files load_project(path/to/project) report run_pipeline(code_files) print(json.dumps(report, indent2, ensure_asciiFalse))这个脚本里有两个容易被忽略但很关键的细节。一个是chunk_code函数里的max_tokens参数我把它设为3000这个值不能太高也不能太低。太高了Agent的注意力会分散太低了代码上下文不完整没法判断调用关系。另一个是temperature0.2做审查任务温度一定要低温度高了模型会放飞自我产生大量幻觉Bug这点在调参部分还会细说。5.3 参数调优记录我在实验里记录了几组关键参数的影响这里分享出来给大家参考。角色数量从2个加到5个召回率提升明显从5个加到6个以上召回率不再增长重复和幻觉问题开始变多。最优角色数大概是4到6个取决于代码库规模。温度0.2到0.3是审查任务的甜区。0.5以上幻觉Bug数量飙升我见过一次温度调到0.8一个Agent报出来的问题里有一半是它想象出来的验证成本极高。0.1以下输出太保守很多真实的低风险问题会被它忽略。切片大小3000到5000token的切片效果最好。少于1000tokenAgent看不到完整逻辑总在猜测超过8000token注意力漂移现象明显加重。如果你的代码干行很长建议先用AST或其他工具抽取关键信息再做切片。上下文相关文件的拼装我让Agent在审查时对每个文件都输出一个相关文件列表这些列表汇总起来后下一轮审查时把高频相关文件预拼入切片。这个策略有点类似RAG的优化思路实测能有效改善跨文件Bug的漏报率。6. 常见问题与避坑实录6.1 问题速查表实验过程中遇到不少问题这里整理成速查表方便大家直接对照排查。问题现象可能原因排查思路与解决多个Agent报同一个Bug角色维度和视角有重叠在提示词里明确每个角色的独占维度或靠裁决Agent去重幻觉Bug太多温度过高、提示词没有约束置信度温度降到0.2以下提示词强调只报告有把握的问题Agent开始输出分析文字而不是问题列表没有强制输出格式使用response_format强制JSON输出解析失败直接重试跨文件Bug漏报切片把相关文件拆散了让Agent返回相关文件列表下轮预拼相关文件审查结果前后不一致上下文长度超过注意力舒适区缩小切片尺寸或先给Agent项目索引让其自主选文件裁决Agent失真输入问题列表太长汇总时丢失细节让裁决Agent按模块分批处理再汇总最终报告成本增长失控角色多、切片多、调用次数呈指数增长限制每个角色只审查指定模块清单控制切片数量6.2 别忘了给Agent一个验证环节这是我在过程中最有价值的发现之一。最初版本的多Agent流程是分头审查-汇总报告两步走结果汇总出来的66个问题里有将近三分之一是误报。比如有个Agent报用户登录时密码没有加密传输实际代码里是在前端用HTTPS做了加密后端压根不需要处理这就是典型的基于局部代码的错误判断。加了交叉复核环节之后误报率大幅下降。具体做法是让两个不同的角色互相复核对方产出的问题列表。并发检查Agent的问题让资源管理Agent去复核业务逻辑Agent的问题让安全审查Agent去复核。因为两个Agent的思维框架完全不同一个误报很难同时骗过两套逻辑。实测下来经过交叉复核保留下来的问题人工验证通过率从约70%提升到接近90%。6.3 几个实测心得最后分享几个比较零碎但很实用的心得。第一个是给Agent一个预热机会。在正式审查之前先让每个Agent读一遍代码目录结构输出一份它理解的模块清单再让它去审查代码。这个小步骤能显著降低Agent迷路的概率相当于先让它认路再出发。我对比过加了预热步骤之后输出的问题里找不到对应代码位置的无效项明显减少。第二个心得是警惕看起来完美的报告。多Agent方案产出的报告往往结构整齐、描述专业很容易让人产生信任感。但模型终究是在做概率预测哪怕经过交叉复核仍然存在误报和漏报。我的建议是重要问题一定要人工复核至少看一眼出问题的那段代码再决定是否改造。AI审查的定位是帮你把需要看的地方圈出来而不是替代你所有判断。第三个心得是和持续集成结合。我现在把多Agent查Bug流水线接到了代码合并前的检查环节每次提交代码后自动跑一遍产出的问题列表直接同步到缺陷跟踪系统。这套流程运行了一段时间之后团队里很多人已经从抗拒AI审查变成了主动等审查结果因为很多低级错误在提交之前就被拦下来了省去了来回沟通的成本。这个例子大概能说明多Agent协作的价值不仅体现在一次性扫描里日常开发流程里同样能发挥稳定作用。
阅读完成 · 觉得有帮助?
咨询建站