1. 从提示词到产线这套多智能体代码审查方案到底在解决什么问题代码审查这件事做过团队协作的人都有体会。一个人写完代码提交PR等另一个人抽出时间来读读完提意见作者再改改完再等一轮。快的话半天慢的话拖两三天。如果赶上 reviewer 本身排期紧一个几百行的改动能在队列里躺一周。更麻烦的是人工审查的质量极度依赖审查者的状态——周一上午和周五下午看同一段代码给出的意见可能完全不是一个水平。LinkedIn 工程团队搞的这套多智能体代码审查系统核心目标就是把这套流程从“靠人盯”变成“靠系统跑”。它不是简单地调一个大模型 API 让它看看代码有没有问题而是把代码审查拆成了多个专职角色每个角色有自己的提示词、自己的上下文范围、自己的输出格式最后汇总成一份结构化的审查报告。这套思路在业内叫“多智能体协作”但落到代码审查这个具体场景上它要解决的问题非常实际如何让 AI 给出的审查意见足够稳定、足够具体、足够可执行而不是一堆“建议考虑边界情况”之类的废话。我最初接触这个方向的时候第一反应是为什么不直接用一个强模型加一段精心设计的提示词后来实际跑过几轮才发现单智能体方案在代码审查场景下有几个绕不过去的坑。第一上下文窗口有限一个大型 PR 可能涉及十几个文件、上千行改动全部塞进去模型会“分心”关键问题反而被淹没。第二不同维度的审查需要不同的思维方式——安全漏洞要看数据流和边界条件性能问题要看循环和数据结构选择代码风格要看命名和结构一致性用一个提示词让模型同时关注所有维度结果往往是每个维度都浅尝辄止。第三单次调用的输出格式很难控制模型可能给你一段散文式的评论也可能给你一个列表格式不稳定就没法做后续的自动化处理。多智能体方案的本质是把“审查”这个复合任务拆解成多个单一职责的子任务每个子任务由一个独立的智能体实例完成每个实例有自己的系统提示词、自己的输入范围、自己的输出规范。这样做的好处是显而易见的每个智能体只需要关注一个维度提示词可以写得更精准上下文可以控制得更紧凑输出格式可以强制约束。最终汇总的时候再按严重程度和文件位置做归并和去重。这套方案适合谁来参考如果你是一个中小团队的 tech lead正在被 PR 审查的瓶颈卡住这套思路可以直接借鉴。如果你是一个对 AI Agent 感兴趣但还没找到落地场景的开发者代码审查是一个非常好的练手项目因为它的输入输出边界清晰效果评估也相对客观。如果你已经在用 Copilot 或类似的工具做代码补全但还没试过让 AI 参与审查环节这篇文章会给你一个完整的落地路径。2. 多智能体架构拆解为什么不是一个模型干所有事2.1 单智能体方案的三个致命短板在展开多智能体架构之前有必要先把单智能体方案的问题说透。我试过用一段很长的系统提示词让一个模型同时做安全审查、性能审查和风格审查结果是这样的模型确实会输出三个部分但每个部分的质量都很平庸。安全部分只会说“注意 SQL 注入”性能部分只会说“避免不必要的循环”风格部分只会说“命名可以更清晰”。这些意见没有错但也没有用——因为它们没有指向具体的代码行没有给出具体的修改建议作者看完之后不知道该改什么。第一个短板是注意力稀释。当提示词里同时包含安全、性能、风格、可读性、测试覆盖等多个维度的指令时模型在处理具体代码时会在这些维度之间“切换”导致每个维度的分析深度都不够。这就像让一个人同时做三件事每件事都只能做到及格线。第二个短板是上下文污染。大型 PR 里不同文件的改动性质可能完全不同——有的文件是新增功能有的文件是重构有的文件只是改了个配置。如果把所有文件混在一起送给模型模型很难针对每个文件给出精准的意见。更糟糕的是前面文件的内容可能会影响模型对后面文件的判断产生“幻觉关联”。第三个短板是输出不可控。单智能体方案的输出格式完全依赖提示词的约束力但模型在实际运行中经常会“自由发挥”。有时候给你一个 JSON有时候给你一段 Markdown有时候直接在代码行后面加注释。如果下游需要做自动化处理比如把意见回写到 PR 评论里格式不稳定就是灾难。2.2 多智能体的角色划分逻辑LinkedIn 这套方案的角色划分不是拍脑袋定的而是按照代码审查的实际工作流来拆的。一个经验丰富的审查者在看代码时脑子里其实在并行跑好几条线这条数据流有没有安全问题这个循环的时间复杂度是多少这个命名是否符合团队规范这个改动有没有破坏已有的测试多智能体方案就是把这几条线分别交给不同的智能体去跑。具体来说角色划分遵循三个原则。第一按关注点拆分不按文件拆分。一个智能体负责安全它就看所有文件里的安全相关问题另一个智能体负责性能它就看所有文件里的性能相关问题。这样每个智能体的提示词可以写得非常聚焦不需要在多个关注点之间做权衡。第二每个智能体有独立的上下文窗口。安全智能体只需要看涉及数据输入、数据库操作、权限校验的代码片段不需要看 UI 组件的样式调整。性能智能体只需要看循环、递归、数据库查询、缓存相关的代码。这样每个智能体的输入量可以控制得很小模型的分析深度反而更高。第三输出格式强制结构化。每个智能体被要求输出一个 JSON 数组数组里每个元素包含文件路径、行号范围、问题类型、严重程度、问题描述、修改建议。这个格式是固定的模型没有自由发挥的空间。汇总智能体拿到这些结构化数据后再做归并、去重、排序最终生成一份人类可读的审查报告。2.3 智能体之间的协作与通信机制多智能体系统里智能体之间的通信方式决定了整个系统的效率和可靠性。LinkedIn 这套方案采用的是共享黑板模式而不是直接的消息传递。所谓共享黑板就是所有智能体的输出都写到一个共享的数据结构里汇总智能体从这个数据结构里读取所有输出然后做统一处理。为什么不用直接的消息传递因为代码审查这个场景不需要智能体之间实时对话。安全智能体不需要知道性能智能体发现了什么性能智能体也不需要等安全智能体先跑完。它们可以并行执行各自把自己的发现写到黑板上最后由汇总智能体统一处理。这种模式的好处是解耦——任何一个智能体挂了不会影响其他智能体的执行任何一个智能体的输出格式有问题汇总智能体可以做容错处理。通信的数据结构设计也很关键。每个智能体的输出被规范化为一个统一的Finding对象包含以下字段字段名类型说明file_pathstring问题所在的文件路径line_startint问题起始行号line_endint问题结束行号categorystring问题类别security/performance/style/testseveritystring严重程度critical/major/minor/infodescriptionstring问题描述suggestionstring修改建议confidencefloat置信度0-1这个结构是汇总智能体做归并和排序的基础。没有这个统一结构后续的自动化处理就无从谈起。3. 提示词工程实战每个智能体的提示词到底怎么写3.1 安全审查智能体的提示词设计安全审查智能体的提示词是整个系统里最需要精雕细琢的部分。因为安全问题的漏报代价很高但误报太多又会让人工审查者失去信任。我实际写下来一个可用的安全审查提示词需要包含以下几个要素。首先是角色定义。不要只说“你是一个安全专家”要具体到“你是一个专注于 Web 应用安全的代码审查专家熟悉 OWASP Top 10 漏洞类型擅长从代码中识别注入攻击、权限绕过、敏感信息泄露等风险”。角色定义越具体模型的行为越稳定。其次是审查范围。明确告诉模型只看哪些类型的代码忽略哪些类型的代码。比如“只关注涉及用户输入处理、数据库查询、文件操作、网络请求、权限校验的代码。忽略纯 UI 渲染、样式定义、日志打印等不涉及安全风险的代码。”这样做的好处是减少模型的无效分析提高有效发现的密度。然后是输出格式约束。给出一个具体的 JSON 示例让模型照着填。示例里要包含一个真实的漏洞场景比如[ { file_path: src/api/user.py, line_start: 45, line_end: 47, category: security, severity: critical, description: 用户输入直接拼接进 SQL 查询语句存在 SQL 注入风险, suggestion: 使用参数化查询替代字符串拼接例如 cursor.execute(SELECT * FROM users WHERE id %s, (user_id,)), confidence: 0.95 } ]最后是边界条件说明。告诉模型什么情况下不要报问题。比如“如果代码中已经使用了参数化查询或 ORM 框架的安全方法不要报 SQL 注入问题。如果敏感信息已经通过环境变量或密钥管理服务注入不要报硬编码问题。”这些边界条件能显著降低误报率。3.2 性能审查智能体的提示词要点性能审查智能体的提示词设计和安全审查有相似的结构但关注点完全不同。性能问题的特点是上下文依赖性强——一个循环在数据量小的时候没问题在数据量大的时候就是灾难。所以性能审查智能体的提示词里必须要求模型结合上下文判断而不是看到循环就报问题。我在提示词里会加这样一段“在判断性能问题时先分析代码的执行频率和数据规模。如果代码位于请求处理的热路径上且数据规模可能随用户增长而增长则标记为性能问题。如果代码只在初始化阶段执行一次或数据规模固定且较小则不标记。”这段指令能过滤掉大量无意义的性能告警。性能审查的输出格式和安全审查保持一致但category字段改为performanceseverity的判定标准也不同。比如 N1 查询通常标记为major不必要的对象创建标记为minor而算法复杂度从 O(n) 恶化到 O(n²) 则标记为critical。3.3 风格与可读性审查智能体的提示词技巧风格审查是最容易被低估的部分。很多团队觉得风格问题不重要但实际上风格不一致的代码会显著增加后续维护的成本。风格审查智能体的提示词需要和团队的编码规范强绑定。我的做法是把团队的编码规范文档作为提示词的一部分直接注入。比如“以下是本团队的 Python 编码规范函数名使用 snake_case类名使用 PascalCase常量使用 UPPER_CASE每行不超过 120 个字符导入顺序为标准库、第三方库、本地模块……”然后把规范的具体条目列出来。这样模型在审查时就有了明确的依据而不是凭自己的“感觉”来判断。风格审查的另一个技巧是只报确定性高的问题。命名不规范、行超长、导入顺序错误这些是确定性的可以直接报。但“这个函数应该拆成两个”这种主观判断最好留给人工审查不要让 AI 来提。所以风格审查智能体的提示词里要加一句“只报告违反明确编码规范的问题不报告主观性的重构建议。”3.4 汇总智能体的提示词与去重逻辑汇总智能体的任务不是审查代码而是处理其他智能体的输出。它的提示词核心是去重、归并、排序。去重的逻辑是如果两个 finding 指向同一个文件的同一行范围且 category 相同则合并为一个保留 confidence 更高的那个。归并的逻辑是如果多个 finding 指向同一个文件的不同行但描述的是同一类问题则归并为一个 finding在 description 里列出所有相关行号。排序的逻辑是按 severity 降序排列同 severity 内按 confidence 降序排列。这样人工审查者打开报告时最先看到的是最严重、最确定的问题。汇总智能体的提示词里还需要包含一个质量过滤步骤“如果某个 finding 的 confidence 低于 0.6且 severity 为 minor 或 info则直接丢弃不纳入最终报告。”这个过滤规则能有效控制报告的长度避免人工审查者被低价值信息淹没。4. 从 PR 触发到报告生成完整实操流程拆解4.1 触发机制与代码差异提取整套系统的入口是 PR 的创建或更新事件。在 GitHub 或 GitLab 上可以通过 Webhook 监听pull_request事件当事件类型为opened或synchronize时触发审查流程。触发之后的第一步是提取代码差异。这里有一个关键决策是审查整个文件还是只审查差异部分我的经验是只审查差异部分但保留足够的上下文。具体做法是用git diff命令提取变更的行然后对每个变更块向前后各扩展 20 行作为上下文。这样模型既能看到改了什么也能看到改动周围的代码环境。提取差异的脚本大致如下git diff origin/main...HEAD --unified20 diff.txt--unified20参数表示每个变更块前后各保留 20 行上下文。这个数值可以根据项目情况调整一般来说 20 行足够模型理解上下文又不会让输入过大。4.2 智能体调度与并行执行拿到 diff 之后系统需要把 diff 分发给各个智能体。这里有一个优化点不是所有 diff 都需要送给所有智能体。比如如果 diff 里只改了 Markdown 文档那安全智能体和性能智能体根本不需要跑。所以调度层需要先做一个预分类根据文件扩展名和变更内容决定哪些智能体需要激活。预分类的规则可以很简单.py、.js、.java等代码文件激活全部智能体.md、.txt等文档文件只激活风格智能体.yaml、.json等配置文件激活安全智能体检查敏感信息泄露和风格智能体。激活之后各个智能体并行执行。每个智能体独立调用模型 API独立处理自己的输入独立输出 JSON 结果。并行执行的好处是总耗时取决于最慢的那个智能体而不是所有智能体耗时之和。在实际测试中四个智能体并行执行的总耗时大约在 15-30 秒之间取决于 diff 的大小和模型的响应速度。4.3 结果汇总与报告生成所有智能体执行完毕后汇总智能体开始工作。它读取所有智能体的 JSON 输出执行去重、归并、排序、过滤最终生成一份 Markdown 格式的审查报告。报告的结构是这样的先是一个概览表格列出每个文件发现了多少个问题按严重程度分类统计。然后是详细列表按文件分组每个文件下按行号排序列出所有 finding。每个 finding 包含行号范围、严重程度标签、问题描述和修改建议。报告生成后可以通过 GitHub API 自动回写到 PR 的评论里。回写的时候要注意格式用 Markdown 的引用块和代码块来区分问题描述和修改建议让作者一眼就能看出哪里有问题、该怎么改。4.4 人工反馈闭环与提示词迭代这套系统上线后最重要的不是它第一次跑出来的结果而是人工反馈的闭环。每次 AI 给出审查意见后作者可以选择“采纳”“忽略”或“标记为误报”。这些反馈数据被收集起来用于迭代提示词。具体来说如果某个 finding 被多次标记为误报就需要检查对应的智能体提示词是不是太宽松了需要加边界条件。如果某个类型的漏洞被多次漏报就需要检查提示词是不是没有覆盖到这种场景需要补充示例。我自己的经验是提示词迭代的频率在前两周最高基本上每天都要调整。两周之后误报率和漏报率会稳定在一个可接受的水平。之后可以降低迭代频率每周回顾一次反馈数据即可。5. 踩坑实录多智能体代码审查的常见问题与排查技巧5.1 模型输出格式不稳定的排查与修复这是最常见的问题。即使提示词里给了 JSON 示例模型有时候还是会输出带 Markdown 代码块包裹的 JSON或者输出一段解释文字再加 JSON。解决办法是在汇总智能体之前加一个格式清洗层用正则表达式提取 JSON 部分然后做 JSON 解析。如果解析失败就重试一次重试时在提示词里强调“只输出 JSON不要输出任何其他文字”。另一个技巧是使用模型 API 的JSON mode如果支持的话。比如 OpenAI 的 API 支持response_format: { type: json_object }开启后模型会强制输出合法 JSON。这个功能能省掉很多格式清洗的工作。5.2 误报率过高的根因分析与解决误报率高的根因通常有三个。第一提示词里的边界条件不够具体。比如只说“不要报误报”但没说清楚什么算误报。解决办法是给出具体的反例“如果代码中使用了 ORM 框架的 filter 方法不要报 SQL 注入。”第二上下文不足导致模型误判。比如模型看到一个字符串拼接就报 SQL 注入但实际上这个字符串是用于日志输出的不涉及数据库。解决办法是扩大上下文窗口让模型能看到这个变量的来源和用途。第三模型本身的能力边界。有些问题需要跨文件分析才能判断但单个智能体只能看到当前文件的 diff。这种情况下要么接受一定的误报率要么引入跨文件分析的智能体但后者会显著增加系统复杂度。5.3 大型 PR 的处理策略与性能优化当一个 PR 涉及几十个文件、上千行改动时直接把所有 diff 送给智能体会导致两个问题输入过大导致模型响应变慢以及模型注意力分散导致审查质量下降。解决办法是分片处理把 diff 按文件切分成多个片段每个片段独立送给智能体审查最后汇总所有片段的结果。分片的时候要注意同一个文件的 diff 不要切得太碎否则模型看不到完整的上下文。一般来说一个文件一个片段如果单个文件的 diff 超过 500 行再按变更块切分。5.4 常见问题速查表问题现象可能原因排查方法解决方案模型输出不是合法 JSON提示词约束不够强检查原始输出加格式清洗层开启 JSON mode误报率高边界条件不具体统计误报类型补充反例和边界条件漏报严重问题提示词覆盖不全人工抽查漏报案例补充示例和场景描述响应时间过长输入过大或模型负载高检查输入 token 数分片处理换用更快的模型多个智能体重复报同一问题去重逻辑不完善检查汇总输出优化去重规则按行号和类别合并报告太长没人看低价值 finding 太多统计 finding 分布提高 confidence 阈值过滤 minor 问题5.5 我踩过的三个印象最深的坑第一个坑是提示词里的示例太完美。我一开始在提示词里给的 JSON 示例是一个格式非常规整、字段非常完整的例子。结果模型在输出时即使某些字段没有值也会硬编一个值填进去。比如line_end字段如果问题只涉及一行模型会填一个和line_start一样的值而不是留空。后来我把示例改成一个“有缺失字段”的例子告诉模型“如果某个字段不适用可以留空或省略”输出就自然多了。第二个坑是忽略了 diff 的上下文行。一开始我只把变更的行送给模型结果模型经常报“变量未定义”这种误报因为变量定义在变更行之前模型看不到。后来加了--unified20参数这类误报就基本消失了。第三个坑是没有做智能体激活的预分类。一开始所有 diff 都送给所有智能体结果一个只改了 README 的 PR 也触发了安全审查和性能审查浪费了计算资源不说还产生了一堆无意义的 finding。后来加了预分类逻辑只对代码文件激活全部智能体文档文件只激活风格智能体效率提升非常明显。6. 落地效果评估与持续优化方向6.1 如何衡量这套系统到底有没有用评估一套代码审查系统的效果不能只看它发现了多少问题还要看它发现的问题里有多少是真正有价值的。我用的指标有三个有效发现率人工确认有价值的问题数除以总发现数、漏报率人工审查发现但 AI 没发现的问题数除以总问题数、平均审查耗时从 PR 创建到审查报告生成的时间。在实际运行中有效发现率从最初的 40% 左右提升到了 70% 以上漏报率控制在 15% 以内平均审查耗时从人工审查的 4-8 小时降低到了 30 秒以内。当然AI 审查不能完全替代人工审查但可以把人工审查者从“找问题”变成“确认问题”效率提升是显而易见的。6.2 提示词迭代的节奏与版本管理提示词是这套系统的核心资产必须做版本管理。我的做法是把每个智能体的提示词存成独立的文件用 Git 管理。每次修改提示词都提交一个 commitcommit message 里写清楚修改原因和预期效果。这样当效果出现波动时可以快速回滚到上一个稳定版本。迭代的节奏建议是上线第一周每天回顾一次反馈数据调整提示词第二周隔天回顾一次之后每周回顾一次。每次调整只改一个变量比如只加一个边界条件或者只改一个示例这样才能准确判断改动的影响。6.3 从代码审查扩展到其他场景的可能性这套多智能体架构的思路不局限于代码审查。任何需要多维度分析的任务都可以套用这个模式。比如技术文档审查可以拆成“准确性审查”“完整性审查”“可读性审查”三个智能体。比如数据分析报告审查可以拆成“数据准确性审查”“逻辑一致性审查”“结论合理性审查”。关键是把任务拆解成单一职责的子任务每个子任务有独立的提示词和输出格式最后汇总。这个模式的可扩展性很强只要你能把任务拆清楚就能用多智能体方案来跑。我在实际使用中最大的体会是多智能体方案的价值不在于用了多少个智能体而在于每个智能体的职责是否足够单一、提示词是否足够精准、输出是否足够结构化。如果这三个条件不满足用再多智能体也只是把单智能体的平庸结果复制了多份而已。反过来如果这三个条件都满足哪怕只有两个智能体效果也会比单智能体好很多。
