在上一篇文章中,我介绍了 opencode-actions——一个基于 OpenCode 构建的 GitHub Action,用来做自动化的 PR 代码审查。那个版本的 review action 用的是一个模型、一个 prompt,针对整个 PR diff 做一次综合审查。
这个方案能用,但有个明显的问题:一个 prompt 要同时关注代码质量、安全漏洞、性能问题和架构设计,每一项都不够深入。 就像让一个工程师同时扮演 QA、安全审计、DBA 和架构师——每个角色都能说两句,但都不专业。
Cloudflare 在今年四月发了一篇博客,详细介绍了他们用 OpenCode 构建的多 Agent 并发代码审查系统。他们用了 7 个专业 reviewer 加 1 个 coordinator,在 5169 个仓库上跑了 13 万次审查。核心思路是:不要让一个模型什么都看,而是让多个专业模型各看各的,最后用一个 coordinator 统一汇总。
看完这篇文章,我决定在 opencode-actions 中实现类似的能力。这篇文章就是 multi-review action 的设计记录。
为什么需要多 Agent 并发审查?
单模型审查的问题不只是"不够深入"。实际使用中有几个具体的痛点:
- 维度冲突:安全审查要求严格(宁可误报不能漏报),性能审查要求务实(关注可测量的指标而非理论风险)。一个 prompt 很难同时表达两种截然不同的审查哲学。
- 上下文稀释:当 prompt 中塞了太多"你要检查 A、B、C、D、E"时,模型的注意力被分散,每个维度的审查质量都打折扣。
- 结果模糊:一个模型输出的"有条件合并"到底是因为安全问题还是性能问题?很难区分。
Cloudflare 的做法是把审查拆成独立的维度,每个 reviewer 只关注自己擅长的领域。他们的 security reviewer 有明确的 “What to Flag” 和 “What NOT to Flag” 指令——告诉模型什么该忽略,比告诉它什么该检查更重要。
架构:并发 Reviewer + Coordinator
multi-review 的核心架构用一句话概括:N 个专业 reviewer 并发审查,1 个 coordinator 汇总去重。
整个流程是这样的:
| |
关键设计选择:
- 单 Server 多 Session:只启动一个 OpenCode Server 实例,所有 reviewer 和 coordinator 共享。这样避免了 N 个 reviewer 各自冷启动 MCP server 的开销。
- Promise.all 并发:所有 reviewer 通过
Promise.all同时启动,不排队。实际运行时间取决于最慢的那个 reviewer,而不是所有 reviewer 的总和。 - 全局超时 + 自适应余量:一个全局 deadline,每个 reviewer 的剩余时间 =
max(30s, deadline - now)。先完成的 reviewer 不影响后面的,后面的 reviewer 自然获得更少的时间。
四个专业 Reviewer
默认启动四个 reviewer,每个有独立的 YAML 定义:
| Reviewer | 关注领域 | 决策标签 |
|---|---|---|
| Quality | 代码质量、bug、逻辑错误、风格一致性、错误处理 | 可合并 / 有条件合并 / 不可合并 |
| Security | 输入验证、认证授权、注入漏洞、数据暴露、OWASP Top 10 | 安全无虞 / 存在风险 / 高危漏洞 |
| Performance | 算法复杂度、内存模式、N+1 查询、缓存、并发 | 性能良好 / 性能有疑虑 / 性能问题严重 |
| Architecture | 耦合度、模块划分、分层、接口设计、霰弹式修改 | 架构合理 / 架构有疑虑 / 架构有问题 |
每个 reviewer 的 prompt 都遵循同一个约束:第一行必须是决策标签,然后是总结、阻塞项和建议项。这让 coordinator 能结构化地解析每个 reviewer 的输出。
和 Cloudflare 的做法一样,每个 reviewer 的 prompt 都明确告诉它只看当前代码中存在的问题,不要重复早期版本的问题,不要建议修改未变更的代码。
Team 配置
reviewer 的组合通过 default-team 参数配置,格式是 persona:count:
| |
当 count > 1 时,同角色的 reviewer 会带上编号(如 security-1、security-2),用同一个 prompt 但独立运行。相同 prompt 的多次运行可以起到交叉验证的效果——如果两个 security reviewer 都发现了同一个漏洞,可信度自然更高。
Cloudflare 有个类似的"风险分层"机制:trivial 改动(≤10 行)只跑 2 个 agent,full 改动(>100 行)跑全部 7 个。multi-review 目前靠用户手动配置 team,未来可以加入自动分层。
Coordinator:去重和交叉验证
并发审查带来的直接问题是多个 reviewer 可能发现同一个问题。比如一个 SQL 注入,quality reviewer 可能从 bug 角度报告,security reviewer 从安全角度报告。如果不处理,最终报告会有重复。
coordinator 的工作就是整合:
- 跨 reviewer 去重:同一问题只报告一次
- 交叉验证:至少 2 个 reviewer 同意的问题标记为"已确认"
- 冲突处理:意见不一致时取多数意见
- 保留领域见解:安全发现即使只有一个 reviewer 提到,也要保留
- 最严重决策:如果任何一个 reviewer 认为不可合并,最终决策就是不可合并
coordinator 的 prompt 模板支持自定义,通过 {{REVIEWS}} 占位符注入各 reviewer 的输出:
| |
最终生成的 PR comment 包含两部分:coordinator 的综合报告在上,各 reviewer 的详细审查结果折叠在 <details> 标签中。
和 Cloudflare 方案的对比
两者使用了相同的思路——多 Agent 并发 + Coordinator 汇总——但在规模和复杂度上有明显差异:
| 维度 | Cloudflare | multi-review |
|---|---|---|
| Agent 数量 | 7 个专业 agent + coordinator | 4 个(可配置) + coordinator |
| 并发模型 | SDK 多 session,circuit breaker + failback | SDK 多 session,Promise.all + 全局超时 |
| 模型路由 | 按任务复杂度分配不同模型(Opus/Sonnet/Kimi) | 单一模型,通过 model 参数指定 |
| 弹性 | 三级 circuit breaker,provider 级别的 failback chain | 超时 + fallback comment(coordinator 失败时直接展示原始结果) |
| 风险分层 | 自动(trivial/lite/full) | 手动配置 team |
| 扩展性 | 插件架构,7 个 plugin 组合 | YAML persona 定义,内置 4 种 |
| Token 优化 | 共享 context file,7x 的 MR 上下文不重复 | 每个 reviewer 独立接收完整 diff |
| 适用场景 | 内部 GitLab,5169 仓库,企业级 | GitHub/Gitea,开源项目,开箱即用 |
最核心的差异在弹性上。Cloudflare 的 circuit breaker 和 failback chain 是为生产环境设计的——7 个并发 AI 调用,provider 限频和宕机是必然事件。multi-review 的规模小得多,4 个并发的失败概率可控,用超时 + fallback comment 就够了。
另一个差异是 token 优化。Cloudflare 把 MR diff 写到一个共享文件,7 个 reviewer 读同一个文件而不是各拷一份。注意这里共享的是原始 diff(输入数据),而不是 reviewer 之间的审查结论。每个 reviewer 的审查过程仍然是完全独立的。这个优化在 7 个 reviewer 的情况下能省 85% 的重复 token。multi-review 目前每个 reviewer 都接收完整 diff,在 4 个 reviewer 的规模下重复还能接受,但如果 team 配置到 7+ 就需要考虑类似优化了。
Reasoning Effort 和 Thinking
multi-review 支持 reasoning-effort 和 enable-thinking 两个参数,直接传递给 OpenCode SDK 的 agent 配置:
| |
默认 reasoning-effort: max 和 enable-thinking: true,这意味着每个 reviewer 和 coordinator 都会用最大推理力度并输出思维链。对于代码审查这种需要深度分析的任务,这个默认值是合理的。
Cloudflare 也有类似的分层:coordinator 用 Opus(最强推理),code quality 和 security 用 Sonnet(平衡速度和能力),文档审查用 Kimi(便宜)。multi-review 暂时没有按角色分配不同模型的能力,但这是一个明确的优化方向。
使用方式
在 .github/workflows/ 中添加:
| |
这段配置的效果是:在 PR 中评论 /multi-review 或 /mr,就会触发多 Agent 并发审查。
代码实现
核心实现在 orchestrator.ts 中的两个函数。
并发审查——runParallelReviewers:
| |
Coordinator 汇总——runCoordinator:
| |
如果 coordinator 本身失败了,还有个 fallback:
| |
这确保了即使汇总环节出问题,审查结果也不会丢失。
和单模型 Review 的关系
multi-review 和之前单模型 review action 不是替代关系,而是互补:
| review | multi-review | |
|---|---|---|
| 定位 | 快速审查,适合每次 PR 都跑 | 深度审查,适合关键 PR 或手动触发 |
| 模型数 | 1 个 | 4+ 个(可配置) |
| 耗时 | 1-3 分钟 | 3-8 分钟 |
| Token 消耗 | 低 | 中(N 倍于单模型) |
| 触发方式 | PR 创建/更新自动触发 | 手动评论触发 |
| 适合场景 | 日常迭代,快速反馈 | 重要功能、安全相关、大型重构 |
日常开发用 review 做快速检查,关键 PR 用 multi-review 做深度审查。两个 action 可以共存于同一个仓库。
未来优化方向
参考 Cloudflare 的经验和当前实现的局限,有几个明确的优化方向:
- 自动风险分层:根据 diff 行数和文件类型自动决定跑几个 reviewer。typo 修改变动不需要 4 个 agent 并发审查。
- 共享上下文:把 diff 写到文件而不是每个 reviewer 都拷贝一份,减少 token 消耗。但需要注意一个微妙的问题:共享的边界在哪里? 共享原始 diff(输入数据)是安全的,但如果过早共享 reviewer 之间的中间结论,会导致严重的偏差问题——确认偏差、锚定效应、同质化审查。正确的设计是:reviewer 阶段完全隔离,只共享输入;coordinator 阶段才汇总结论。这不仅是 token 优化的问题,更是一个审查独立性的架构决策。
- 模型路由:coordinator 用强模型,文档审查用轻量模型,按角色分配不同 provider。
- 增量审查:push 新 commit 后,只审查变更的部分,不从头开始。
总结
multi-review 的核心思路来自 Cloudflare 的文章:把一个复杂任务拆成多个专业子任务,并发执行后统一汇总。这比一个全能模型覆盖所有维度更有效,因为每个子任务的 prompt 更聚焦,模型的注意力更集中。
实现上,multi-review 用 OpenCode SDK 的多 session 能力做并发,用 Promise.all 做编排,用全局超时做兜底,用 coordinator 做去重和交叉验证。这是一个在开源项目规模下足够实用的架构——没有 circuit breaker 和 failback chain 的复杂度,但覆盖了并发审查的核心需求。
- opencode-actions — GitHub Action 仓库
- Cloudflare: Orchestrating AI Code Review at Scale — 设计灵感的来源
- opencode-actions - 一个 coding review agent — 单模型 review action 的介绍
- OpenCode 配置之外的优化 — opencode-review 插件的设计,session 内的代码审查
