陪审团查证、主审官举证:Code Jury 如何用多智能体法庭质辩终结 PR 评审幻觉
在 AI 编码工具(Claude Code、Codex、Cursor、Antigravity 等)全面接管研发日常的今天,代码产出速度暴涨了十倍,但研发效能的真正堵点却顺延到了下游:代码评审(Pull Request Review)。
为了分担人类工程师的审阅负担,不少团队尝试引入 AI 进行自动代码审查。然而,早期的尝试往往迅速沦为两场灾难:要么是单个智能体“自审自查”,陷入 自证清白的严重幻觉 与虚假绿灯;要么是拉入多个智能体互审互改,演变成 “无休止的乒乓补丁战” ——A 提修改,B 反对并改回,C 又引入无端抽象,甚至连改 10 轮依然无法收敛。
近期在开源社区备受瞩目的 Code Jury(agentsdance/codejury),以一种极富创见的“英美法系法庭质辩”架构,彻底打破了这一僵局。它将多智能体分工重构为 “只看不动的陪审团(Jury)” 与 “唯一动刀的主审法官(Judge)”,并推行极其严苛的 机械证据门禁(Mechanical Gate)。
本文将深入剖析 Code Jury 的核心架构、博弈收敛机制以及在生产级复杂并发系统中的真实质辩案例。
1. AI 代码评审的三大死穴与自主循环的假象
在探究 Code Jury 的架构之前,我们需要直面当前 AI 辅助代码评审中最为残酷的工程现实:
flowchart TD
subgraph Trap1 ["死穴一:单智能体自证清白 (Tautology)"]
direction TB
A1["智能体审查自身代码"] --> B1["沿用写代码时的认知盲区"]
B1 --> C1["生成充满 Mock 的自嗨测试<br/>掩盖真实生产缺陷"]
end
subgraph Trap2 ["死穴二:多智能体补丁大乱斗 (Patch War)"]
direction TB
A2["Reviewer A 提议修改"] --> B2["Reviewer B 强制回滚并重构"]
B2 --> C2["代码基线剧烈震荡<br/>轮次耗尽仍无法收敛"]
end
subgraph Trap3 ["死穴三:看似合理的致命毒药 (Plausible Poison)"]
direction TB
A3["Reviewer 提出'防御性校验'"] --> B3["表面上增加判空/防重"]
B3 --> C3["破坏底层状态机与资源租约<br/>引发服务死锁与资源泄漏"]
end
1.1 致命毒药:为什么看似正确的建议往往最致命?
在 Code Jury 的真实案例研究(针对高性能容器预热池 worker-pool #128 的评审)中,曾发生过这样一幕极其典型的场景:
针对一个并发任务调度通道,代码审查智能体煞有介事地指出:
“此处
select逻辑存在竞态风险,应当在分支前增加if ctx.Err() != nil { return }进行防御性保护。”
这个建议听起来无懈可击,任何没有深入并发上下文的模型或初级工程师都会毫不犹豫地“采纳并修复”。
然而,这是一剂致命毒药。
在底层的调度状态机中,进入该分支前任务已经被推入排队并占用了在途资源配额(In-flight Reservation)。如果直接简单 return 退出,被占用的在途配额永远不会得到释放,直接导致整个系统的 Worker 预热池发生 永久性资源欠载(Permanent Pool Under-fill)!
[!WARNING] 审查建议的真实存活率
Code Jury 的大量工业实测数据表明:在各类大模型提出的审查意见中,约有整整三分之一(33%)在严谨的逻辑与执行验证面前根本无法立足。 如果缺乏强制验证门禁,让审查意见直接落地修补,只会引入更多隐蔽的严重故障。
1.2 自主循环的皇帝新衣:十轮评审同一 commit
很多自研的评审自动化脚本声明自己支持 --max-rounds 10 的自主循环。但只要仔细审视其执行逻辑就会发现,由于缺少一个有权限且能够执行“复现、验证、打补丁、提交推流”的主体,这些脚本本质上只是把同一个 Commit SHA 重复读取并评审了 10 次,最后在毫无进展的情况下伪造收敛报告。
要想让多智能体评审形成真正的自治闭环,必须彻底重构智能体之间的权力边界与交互协议。
2. Code Jury 架构:法庭辩论与权力分立
Code Jury 抛弃了传统“流水线”式或“平铺直叙管道”式的评审设计,将人类法庭的 对抗制诉讼(Adversarial System) 与 权力制衡 引入了软件工程:
sequenceDiagram
autonumber
participant Worktree as 隔离工作区 (Git Worktree)
participant Juries as 陪审团 (Reviewers: Claude / Grok / Droid / Antigravity)
participant Gate as 机械举证门禁 (Triage Gate)
participant Judge as 主审法官 (Judge: OpenAI Codex)
participant Git as 远程仓库 (Source Branch)
Note over Worktree,Juries: 阶段一:陪审团独立并发调查 (只读沙箱)
Worktree->>Juries: 派发精准 Git Diff 与上下文契约
Juries-->>Gate: 提交独立 Findings (严格禁止改动工作区)
Note over Gate,Judge: 阶段二:法官介入与无证据不采纳 (机械门禁)
loop 逐条严密审理每一个 Finding
Gate->>Judge: 派发质辩任务:证明缺陷存在或提供反驳证据
Judge->>Worktree: 编写复现脚本,观察反向失败 (Red Test)
alt 无法复现或属于错误提议
Judge-->>Gate: 裁定 REJECTED (附带抛异常/未复现的实证命令)
else 确属存量旁路问题
Judge-->>Gate: 裁定 DEFERRED (记录原因,绝不动代码)
else 成功复现并修复
Judge->>Worktree: 应用最小改动修复
Judge->>Worktree: 验证回归测试转绿 (Green Test)
Judge-->>Gate: 裁定 ACCEPTED (附带复现证据与失败用例描述)
end
end
Note over Judge,Juries: 阶段三:结构化对抗反问与结案收敛
Gate->>Juries: 发送结构化反馈(附带直接反问,直面争议)
Juries-->>Gate: 重新检验证据链,直至全体输出 NO NEW FINDINGS
Judge->>Git: 自动提交修复代码并安全推流 (Push)
2.1 角色权责硬隔离:陪审团“只看不动”,法官“独揽刀权”
Code Jury 确立了最为核心的权力分立规则:
- 陪审团(Reviewers / Jury):
- 支持并发挂载多个完全异构的 Agent CLI,如 Anthropic Claude Code、xAI Grok、Factory Droid、Google Antigravity(
agy)、Qwen Code、Moonshot Kimi、OpenCode 等; - 权限硬性限制为只读/计划模式:以 Claude 为例,启动参数被强制限定为
--permission-mode plan --disallowedTools Edit,Write,NotebookEdit;以 Codex 为例,参数限定为--sandbox read-only; - 陪审团没有任何修改代码、创建提交的权限。它们的工作只有一个:对照 Base 分支精准扫描变更,以统一的格式(
claim、loc、body)提出异议。这从物理层面彻底掐死了“多智能体补丁大乱斗”的根源。
- 支持并发挂载多个完全异构的 Agent CLI,如 Anthropic Claude Code、xAI Grok、Factory Droid、Google Antigravity(
- 主审法官(Judge / Main Agent):
- 全局仅指定一个核心智能体作为法官(默认由 OpenAI Codex 担任,亦可配置为 Claude 或 Antigravity 等);
- 法官是全场唯一被授予工作区写入权限(
workspace-write、acceptEdits)的角色; - 法官坐在两轮评审之间的“人类工位”上,负责调查陪审团提出的异议、编写复现测试、执行代码修复并提交代码。
3. 机械举证门禁(The Triage Gate):无证据不采纳
“A skill can be skipped. That check cannot.”(Prompt 技能可以被绕过,但机械门禁不行)。这是 Code Jury 写入源码核心的设计哲学。
在 lib/findings.js 中,Code Jury 实现了严密的决议准入网关:
// lib/findings.js: 机械举证网关的准入逻辑
export function gate(finding, { verdict, test }) {
if (!finding) return "no such finding";
if (!VERDICTS.includes(verdict)) {
return `verdict must be one of ${VERDICTS.join(", ")}`;
}
// 驳回 (rejected) 或搁置 (deferred) 属于合理裁决,不需要复现证据
if (verdict !== "accepted") return null;
// 核心铁律一:采纳缺陷必须有复现证据记录!
if (!finding.reproduced) {
return `no finding.reproduced event for ${finding.id} — reproduce it before accepting it`;
}
// 核心铁律二:必须有亲眼目睹失败的回归测试!
const proof = test ?? finding.test;
if (!proof) {
return `accepting ${finding.id} needs --test <what failed without the fix>`;
}
return null;
}
3.1 什么是“无反向失败的测试只是装饰品”?
在自动化软件工程中,有一句至理名言:“A fix whose test passes with the fix reverted is decoration.”(一个在撤销修复后依然能通过的测试,纯属装饰品)。
Code Jury 的 Triage 流程将这条定律发挥到了极致:
- 当法官试图对陪审团提出的 Finding 给与
accepted(采纳)结论时,门禁首先检查磁盘上是否记录了finding.reproduced事件; - 法官必须明确回答:在撤销本次修复代码的情况下,究竟哪一个测试用例会发生断言失败(Observed Fail)。如果一个测试在有修复和无修复时全部亮绿灯,该决议将被网关直接驳回(Downgrade),缺陷保持
open状态,强迫进入下一轮重审。
3.2 质辩的四种确定性裁决(Verdicts)
主审法官在面对陪审团的 Finding 时,只能给出以下四种标准化判决:
| 裁决类型 | 准入要求 | 对代码库的影响 | 陪审团感知 |
|---|---|---|---|
accepted |
必须同时提供复现证据与失败单测描述 | 实施代码修复,追加回归测试用例 | 告知已修复,附带单测构造思路 |
rejected |
必须提供反驳证据(如报错截图、反例代码) | 严禁改动任何业务代码 | 附带反驳论据,接受陪审团反问质询 |
deferred |
证明属于存量历史包袱,且本次 PR 未加剧风险 | 严禁改动任何业务代码 | 解释为何不在本次范围,避免无谓重提 |
superseded |
该问题已被其他合并修复所覆盖 | 关联主修复项 | 状态同步,标记为已由前置操作解决 |
4. 结构化对抗反问与破除死锁机制
在过去,很多自动化脚本即便驳回了审查建议,下一轮审查时同一个智能体又会把同一条建议重新提一遍,导致循环震荡。
Code Jury 通过 反问闭环(Direct Question Feedback) 与 死锁熔断(MAX_TURNS) 完美化解了这一难题。
4.1 结构化反馈模版与直接反问
当法官处理完一轮评审后,系统不会把各家意见混在一起,而是为每个陪审团成员单独生成专属的针对性回复(prompts/feedback.md)。
对于法官驳回或搁置的 Finding,模版被强制要求以直接反问句结尾:
**2. 调度超时处理 — AGREE it is real, NOT fixing here.**
该问题在本次 PR 触碰的文件之前就已经存在(pre-existing),且当前变动并未增大该分支触发概率。修复它需要重构底层的定时器通道,属于独立需求。
Question: 你是否认同它属于存量问题且本次变动未扩大其影响?如果不同意,请给出具体依据,我将重新考虑。
[!TIP] 质辩实验数据
实测表明,以明确反问句结束争议,能够在单轮交互中将超过 60% 的争执型修改转化为明确共识(Explicit Agreement to Defer)。陪审团面对翔实的反驳证据与合乎逻辑的范围界定,会主动撤销异议。
4.2 避免无限缠斗:三回合死锁规则(MAX_TURNS = 3)
如果某个 Reviewer 极其固执,在面对法官提供的测试反证后依然反复重申同一条 Finding,系统该如何处理?
在 lib/loop.js 中,Code Jury 规定了明确的死锁截断规则:
// lib/loop.js: 针对单项异议的最大辩论轮次
export const MAX_TURNS = 3;
export function deadlocked(events, id) {
return turnsFor(events, id) >= MAX_TURNS;
}
- 回合计数针对单项事实,而非整场评审:一条异议最多允许来回质辩 3 个回合;
- 一旦达到 3 回合上限仍未达成一致,主审法官立即判定该问题触发
deadlocked,强制将其转入deferred状态; - 分歧即资产:双方的全部质辩证据、测试代码与反驳理由全部被完整归档进
~/.jury/runs/<slug>的持久化事件日志中。这既避免了死循环耗尽 Token,又为后续人类架构师介入留下了无可辩驳的完整证据链。
4.3 终结标志:严格的单行 STOP TOKEN
当一轮审查中没有任何新的正确性问题时,所有陪审员被严格要求必须在单独的一行输出:
NO NEW FINDINGS
主审法官只有在所有活跃陪审员的输出中均检测到该 Stop Token,且全量队列中不存在任何未判决的 open Finding 时,才会最终裁定收敛,执行 Git Commit 并推送分支。
5. 真实复杂工程实录:在“全绿测试”中捕获幽灵缺陷
在 Code Jury 针对高并发 Worker 池(worker-pool #128)的实际评审实录中,最震撼的不是它修了多少语法错误,而是它在整套测试套件已经全部显示绿灯的情况下,敏锐揪出了测试本身的虚假自嗨:
真实缺陷 1:抖动逻辑被彻底删除,测试依然亮绿灯
- PR 声明:为容器创建失败的退避机制增加了随机抖动(Jitter),防止惊群效应;
- 陪审团洞察:测试用例只断言了退避时间是否小于最大上限(Upper Bound)。这意味着哪怕直接把代码改成
return delay(完全砍掉 Jitter 逻辑),原有的 500 次采样测试依然能够 100% 成功通过! - 法官修复:重写单测断言,基于 200 次独立采样的方差与短区间离散度进行硬性统计断言,确保 Jitter 真实生效。
真实缺陷 2:概率性穿透的取消测试(1/1000000 的假通过)
- PR 声明:验证任务取消(Cancellation)时能够安全退出;
- 陪审团洞察:在并发 Go 的
select语法中,由于通道随机选择特性,即使发生代码缺陷,原测试在 20 次循环中依然有约百万分之一的极低概率全部刚好选中ctx.Done(),从而在 CI 中偶发伪造“测试通过”; - 法官修复:桩化(Stub)等待机制,在保持 Context 处于活跃状态的同时确定性报告未完成,从数学上彻底根除并发竞态的假阳性。
真实缺陷 3:用被测函数自身常量验证自己(自证清白)
- PR 声明:限制最大退避上限不超过 60 秒;
- 陪审团洞察:测试用例中的预期上限值直接引用了业务代码导出的
maxCreateBackoff变量。如果有人手滑把常量改成了 48 秒,测试依然无脑全绿通过; - 法官修复:在独立的测试契约中断言字面量常量,守住对外公布的技术契约。
6. Code Jury 详细使用指南与全场景实战案例
Code Jury 使用纯 TypeScript / Node.js(Node 20+)构建,全面支持本地极速运行,并提供了从本地单机自愈到企业级 CI/CD 集成的完整落地形态。
6.1 环境准备与角色探测(Preflight)
在运行审查前,首先需要安装 CLI 并确认本地环境中的智能体就绪状态:
# 全局安装 Code Jury
npm install -g @agentsdance/codejury
# 检查当前环境已安装的智能体 CLI 及其状态
jury agents
jury agents 会输出当前系统中已安装的 CLI、默认担任的角色以及沙箱安全级别:
codex OpenAI Codex ok main (judge)
claude Anthropic Claude Code ok reviewer (sandbox: plan)
agy Google Antigravity ok reviewer
grok xAI Grok ok reviewer (⚠️ no read-only mode)
droid Factory Droid ok reviewer
qwen Qwen Code ok (opt-in)
copilot GitHub Copilot CLI ok (opt-in)
...
[!NOTE] 全局主审法官持久化配置
你可以为所有仓库设定全局默认法官(保存在~/.jury/config.json中),无需每次手动加参:jury agents judge codex # 将 Codex 设为全局默认法官 jury agents judge # 查看当前生效的默认法官 jury agents judge --reset # 恢复系统默认设置
6.2 实战案例一:本地未提 PR 前的“自测自愈”模式(日常开发高频)
很多开发者在本地完成了一项重要特性的开发,在 git push 并提 PR 之前,希望能先让 AI 陪审团给自己的代码把把关,并让法官自动修复潜在的低级并发漏洞与测试盲区。
执行命令:
# 在当前 Git 仓库根目录执行,基准分支为 main,禁止推送到远端
jury --dir . --trunk main --push=false \
--jury claude,droid \
--judge codex
工作流全景:
- 零远程依赖:无需创建 GitHub PR,系统自动计算
git merge-base HEAD origin/main,提取当前本地分支相对于main主干的精准变更; - 就地质辩:Claude 与 Droid 作为陪审团并发扫描变更,提出 Finding;
- 主审法官就地动手术:Codex 调查 Finding,就地编写复现脚本并追加回归测试,然后修复业务逻辑;
- 保留本地成果:所有修复直接作为干净的本地 Git Commit 沉淀在当前分支上,开发者可人工 review 后再行推送。
6.3 实战案例二:GitHub 远程 PR 全自动自治审查与推流
当团队收到外部开源贡献者或同事提交的 PR,需要快速完成端到端的多模型会诊与自动化打补丁时使用。
执行命令:
# 挂载 Claude 与 Google Antigravity 作为陪审团,Codex 作为法官,开启自动推流
jury review https://github.com/my-org/core-service/pull/128 \
--jury claude,agy \
--judge codex \
--push=true
底层执行流程:
flowchart TD
Start["执行 jury review <pr-url>"] --> FetchPR["调用 gh cli 获取 PR Base 与 Head"]
FetchPR --> IsolateWorktree["在 ~/.jury/checkouts 创建独立隔离工作树<br/>(完全不污染你当前 IDE 正在编写的代码)"]
IsolateWorktree --> OpenWeb["后台启动 127.0.0.1:3080 控制台推流"]
OpenWeb --> MultiRound["进入陪审团质辩 -> 法官举证修复循环"]
MultiRound --> Converge{"所有 Reviewer 输出<br/>NO NEW FINDINGS?"}
Converge -- 否且未达上限 --> MultiRound
Converge -- 是 --> CommitPatch["法官生成语义化 Git Commit"]
CommitPatch --> FastForwardPush["Fast-forward 推送至 PR 源分支"]
FastForwardPush --> CleanWorktree["自动销毁隔离 Worktree,保留审计日志"]
6.4 实战案例三:跨微服务多仓库协同 PR 联合评审(Multi-PR Review)
在微服务架构中,一次接口重构通常需要前端仓库与后端仓库、或者 SDK 仓库与 API 服务仓库同时提 PR(例如 api/pull/12 与 client/pull/34)。传统的单 PR 审查工具无法看到跨端契约,极易漏判字段兼容性。
执行命令:
jury review \
https://github.com/acme/auth-api/pull/12 \
https://github.com/acme/web-client/pull/34 \
--reviewer claude --reviewer grok \
--judge codex \
--push=false
关键运作细节:
- 统一视图映射:系统自动检出两个仓库,在根上下文中映射为
PR1/和PR2/; - 跨端语义审查:陪审团能够同时检视服务端的 Protobuf/OpenAPI 变更与前端客户端的调用代码,严查两端契约漂移;
- 精准归属提交:法官修复跨端问题后,能够识别代码属于哪一个子项目,并将 Commit 准确生成并推送到对应的来源 PR。
6.5 实战案例四:API 限流、超时中断后的“断点续审”(Resume 灾备)
大模型审查往往单次耗时数分钟,如果中途遇到 API 额度超限(Rate Limit)、网络波动或某些智能体临时超时,从头重跑将白白浪费昂贵的 Token 和时间。
执行命令:
# 第一步:列出已保存的审查历史记录与 Slug 标识
jury runs --dir ""
# 第二步:指定 --resume 标志无缝接续上次会话
jury review https://github.com/my-org/core-service/pull/128 \
--resume 2026-09-16-core-service-128 \
--reviewer claude \
--push=false
增量续审的优势:
- 复用已沉淀的
settled.md:此前各轮次已达成共识的 fixed、rejected 和 deferred 列表直接保留,智能体绝不会重新提出老问题; - 支持更换评审员:如果上一次某个 CLI 挂掉,续跑时可随时切换为其他可用的智能体继续审理。
6.6 实战案例五:项目级工程配置定制(jury.config.json)
对于团队内部仓库,可以在仓库根目录下提交一份 jury.config.json,团队成员只需敲入 jury review <pr-url> 即可自动套用项目规范。
{
"agents": [
{ "name": "codex", "role": "main" },
{ "name": "claude", "role": "reviewer", "expectSeconds": 600 },
{ "name": "agy", "role": "reviewer" },
{ "name": "grok", "enabled": false },
{
"name": "internal-security-linter",
"role": "reviewer",
"argv": ["python3", "scripts/sec_review.py", "--target", "{{worktree}}", "--prompt", "{{promptText}}"],
"cwd": "worktree",
"promptDelivery": "argv",
"report": "whole",
"expectSeconds": 180
}
]
}
- 统一角色分工:固定 Codex 为主审,Claude 和 Antigravity 为陪审团,禁用未采购的企业服务;
- 支持私有审查工具集成:支持通过
argv将团队内部的自研安全审计脚本、合规检查器包装为标准的陪审团成员参与质辩。
6.7 实战案例六:本地可视化控制台与回放(Console & Audit)
Code Jury 默认在本地启动轻量 Web 服务器(绑定 127.0.0.1:3080),你可以通过浏览器实时查看每一位 Reviewer 与法官的完整交互流。
# 场景 A:仅打开 Web 控制台查看历史审查记录(不触发任何智能体运行)
jury --web-only --dir "" --run 2026-09-16-core-service-128
# 场景 B:在无图形界面的 CI 服务器或纯终端环境下运行(关闭 Web 控制台)
jury review <pr-url> --web=false --push=false
归档产物目录结构(~/.jury/runs/<slug>/):
~/.jury/runs/2026-09-16-core-service-128/
├── events.jsonl # 唯一真理源:按时间追加的全量事件流
├── settled.md # 各轮次动态生成的已决议问题列表
├── prompt-round-1.md # 第一轮发给评审员的完整渲染 Prompt
├── codex.raw.txt # 法官原始输出与复现单测日志
└── claude.raw.txt # 评审员原始 Token 流与分析报告
6.8 CI/CD 自动化流水线集成示范(GitHub Actions)
在生产环境中,可以将 Code Jury 作为高价值 PR 的强制合并门禁(Merge Gate)。以下是一份标准的 GitHub Actions 工作流配置示范:
# .github/workflows/codejury-gate.yml
name: Code Jury Verification Gate
on:
pull_request:
types: [opened, synchronize, reopened]
jobs:
jury-review:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- name: Checkout Code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22'
- name: Install Code Jury & Agent CLIs
run: |
npm install -g @agentsdance/codejury
npm install -g @anthropic-ai/claude-code
npm install -g @openai/codex
- name: Run Autonomous Review Gate
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# 在无头模式下运行,由 Claude 审查、Codex 复现并提交修复
jury review ${{ github.event.pull_request.html_url }} \
--reviewer claude \
--judge codex \
--web=false \
--push=true
- name: Upload Jury Audit Artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: jury-audit-logs
path: ~/.jury/runs/
7. 架构启示录:多智能体软件工程的未来走向
从单纯依靠 Prompt 祈祷 AI “写好代码”,到构建起具备自我纠错与证据审理能力的自治系统,Code Jury 给我们带来了极其深刻的工程启示:
- 权限隔离是自治收敛的前提:绝不能给所有智能体平等的写权限。负责挑刺的必须“剥夺动刀工具”,负责动刀的必须“独自承担举证压力”。
- 机械门禁远胜提示词工程:任何声称缺陷已被修复的宣称,如果不能在代码库中拿出一个在撤销修复时能够真实飘红的回归测试,都是空中楼阁。
- 分歧透明化而非强行达成共识:允许不完美,记录合理的争议(Deadlock),比为了盲目收敛而任由模型胡乱修改代码更具生产价值。
当大模型从“单兵写代码”逐步演进到“协同工程流水线”,这套陪审团查证、主审官举证、机械门禁把关的严谨范式,无疑为我们在 AI 时代的软件可靠性交付探索出了一条坚实可信的破局之路。