作者构建了两个从相反方向解决 LLM 判断可靠性问题的系统,发现两者的共同盲点在于架构本身无法覆盖的认知边界,需要结合代码契约与结构化协议之外的东西。
两个项目,同一个问题——PlannerCritic 和 AdversarialDebate 各自在什么地方犯了错
今年我构建了两个系统,它们从相反的方向试图解决同一个问题。
PlannerCritic 在一个确定性门控层中放入一个 LLM 批评者,让它们形成循环。门控层拥有安全契约,批评者只提供建议。规划器将目标分解为一份带类型的计划,批评者审查每一个子任务,计划被反复修订直到获得批准——或者升级给人类处理。
AdversarialDebate 将两个 LLM 置于一场结构化的辩论中。协议拥有独立性,模型本身就是证据。两位评审员各自分析同一份制品,互不查看对方答案,逐点辩论各自的结论,最终产出趋于一致的决策——或者保留分歧的结构化分歧报告。
两个系统都在回答同一个问题:如何知道 LLM 的判断是错的?
我以为答案在于架构。构建正确的结构,在模型不可信的地方放入代码,系统就会变得可靠。这是两个项目的共同论点。PlannerCritic 押注代码,AdversarialDebate 押注结构。
我只对了一半。架构确实奏效了,系统是可靠的。但两者都有同一个盲点,而我花了数月才意识到——因为这个盲点让各项指标看起来更好,而不是更差。
PlannerCritic 押注的是代码优于模型。决策路径是一个 blocker 合格家族的 frozenset——unsafe_sequencing、weak_rollback、unverified_dependencies、feasibility。LLM 批评者可以将发现标记为 blocker,但若该家族不在 frozenset 中,系统就会将其降级为警告。模型的 severity 标签只是装饰性的,而家族才是承重结构。
AdversarialDebate 押注的是结构优于共识。Revelation gate 确保两位评审员在提交前看不到对方的输出。辩论协议要求逐点回应——CONCEDED、REBUTTED 或 CARRIED。收敛分数衡量的是动向而非一致。两个模型若未经真正交锋就达成一致,得分就会很低;两个模型若真正彼此挑战,得分就会很高。
从纸上来看,这些赌注是互补的。代码防止结构性低估。辩论防止共同幻觉。两者结合,覆盖面比各自单独运作更广。
但每个赌注都有一个失败模式,而另一个系统的设计本可以立即捕获它。然而两个系统都没有捕获自己的失败模式——因为那个失败让仪表盘看起来像是情况在好转。
在 PlannerCritic 中,确定性门控拥有安全责任。它们解析计划的结构——排序、前置条件、回滚、验证——并拦截任何不符合契约的内容。截至 v0.2.2,在全部 183 个目标的扫表中,blocker 计数由结构化家族主导:unsafe_sequencing 有 226 个 blocker,unverified_dependencies 有 185 个,weak_rollback 有 86 个。
这些数字让人感觉这证明了门控在发挥作用。
后来一位名叫 Artjoms Stukans 的社区读者留下了一条评论,重新定义了我对整个系统的看法:
"如果某个 blocker 类别在一次重构后停止触发,你的数字只会看起来更好。226 变成 40,看起来就像是计划变得更安全了。"
他描述了一次 Kubernetes 事故:连续四个版本从未真正运行过。一个旧的 ReplicaSet 保持一个 pod 处于 Running 状态。所有健康检查都通过了,所有冒烟测试都是绿的。没有一个字提到出了问题——因为那个 pod 仍然处于"健康"状态,尽管部署已经坏了。
这正是 PlannerCritic 问题的形状。一个沉默地停止触发的门控会产生更好的指标。blocker 计数下降,仪表盘显示为安全性提升,而方差信号——label_flip_rate、evidence_drift_rate——正是项目用来暴露批评者问题的那些指标——恰好在安全契约移动的地方消失了。批评者被监视着,门控被信任着。
被信任的层不会为自己的失败做广告。这是陷阱所在。
AdversarialDebate 已经有捕获这类问题的模式了。每次辩论都会产生一份转录稿,capitulation detector 读取那份转录稿来识别失败的形态,而不是信任聚合的收敛分数。它不问"辩论收敛了吗?"它问"有一方在第一轮就放弃所有论点而没有任何反驳吗?"这是两个不同的问题,而且只有第二个问题能捕获那个失败。
PlannerCritic 没有等价物。它在构建时测试门控,但没有在运行时监控它们。
修复方案是 Gate Canary——十个 fixture 对,每个门控类一个,每个都配有一份已知良好的计划和一份已知不良的计划。CLI 命令 plancritic gates canary --check 以低于一秒的执行时间和零 LLM 成本运行它们,如果任何门控在其不良计划上停止触发则退出 1。这是一个简陋的检查,一个便宜的检查,它精确捕获了那个在系统产生的所有其他指标中都不可见的失败模式。
它随 v0.2.3 发版。
在 AdversarialDebate 中,按收敛分数最强的组合是 DeepSeek + Mistral:平均收敛度 0.982,判决率 97%,在 41 场辩论中共有 2,352 次让步。现场测试报告中的所有指标都指向这个组合作为最佳生产默认配置。
然后我读了那些转录稿。
65% 的那些辩论是投降级联——一方在第一轮就放弃所有论点,零反驳。那对组合完美收敛,但几乎对对抗性审查毫无用处。
指标看到的是收敛。转录稿看到的是投降。
PlannerCritic 本可以捕获这个问题。其确定性门控不能被说服去批准一份计划。一份通过了所有聚合检查的投降级联,在检查各个前置条件和回滚步骤的门控看来,呈现出完全不同的结构。辩论指标衡量的是模型是否同意。PlannerCritic 的门控衡量的是计划是否安全。这不是同一个问题,而且只有第二个问题能捕获那个失败。
AdversarialDebate 没有确定性底层。协议是好的,组合是差的,指标无法区分这两者。
修复方案是 capitulation detector——独立于收敛分数的转录稿级检查。但这是一个在第一次意外之后添加的检测机制,而不是在此之前设计的健康检查。
然后 v0.2.2 走得更远。noise-floor baseline 通过 bootstrap 重采样给每个指标一个已知的置信区间——GPT+Mistral 与 DeepSeek+Mistral 的差距(0.536 对 0.572)是 1.8 sigma,真实但狭窄。置换控制对 claim-to-ground-truth 配对进行了 500 次随机打乱以构建零分布——LLM judge 的 87.4% 匹配率比词汇底限高出 77.8 个标准差。Shared RLHF priors 设计笔记记录了 Mistral 效应可能同样多地由非 Mistral 模型互相背书所驱动,而非 Mistral 独有的训练。
每个修复都是一个独立的测量层,因为前一层无法看到那个失败而被添加。
两种失败有相同的解剖结构:
一个你信任的层沉默地失败了,而系统将那个沉默解读为改进。
在 PlannerCritic 中,一个坏掉的门控看起来像更少的 blocker——安全性提升
在 AdversarialDebate 中,一个投降的组合看起来像更高的收敛度——辩论质量提升
两种情况的修复方案是同一个模式:一个二次检查,审查输出的形态,而不仅仅是其聚合值。PlannerCritic 需要 gate canary。AdversarialDebate 需要 capitulation detector。没有哪个检查是昂贵的,没有哪个是聪明的,两者都是那种在指标第一次对你撒谎之后才会添加的东西。
关于这件事我最感到不安的是:我构建这两个系统恰恰是因为我不信任 LLM 的判断。我将安全契约移入确定性代码,构建隔离协议,测量非确定性。然后我如此完全地信任那个确定性层,以至于停止监视它。我构建的监控是针对 LLM 的——label_flip_rate、evidence_drift_rate、capitulation_cascade。而实际持有契约的那个层——门控、辩论协议——根本没有监控。
确定性安全层并不会消除监控问题,它只是转移了问题。
在 gate canary 之前,PlannerCritic 监控批评者的非确定性。修复之后,监控还必须覆盖门控本身——不是它们的聚合输出,而是它们持续触发的能力。
在 capitulation detector 之前,AdversarialDebate 监控协议合规性——完成的轮数、解决的论点。修复之后,监控还必须覆盖协议是在产生真正的交锋还是程序性的投降。
当你信任确定性层时,监控目标会转移。这是两个项目都遇到的盲点。而且我认为这是目前大多数 agent 基础设施都有的盲点——我们都在构建确定性 guardrail,然后就走开了。
两个项目的修复都在 2026 年 8 月下旬发版。修复是真实的,经过测试的,已在生产环境运行。
PlannerCritic v0.2.3(发布说明,现场测试报告):
Gate Canary:开发环境和 Docker 中 10/10 门控 fixture 通过
Transit-integrity 检查:边界运行中 0 损坏事件——数字 JSON 字段在脱敏后完好无损
DecisionContext 已填充:试验记录携带 model_id、version、temperature、timestamp,来自 provider spec 而非模型的自述
Approving_authority 强制执行:PermissionError 现在从 CLI、HTTP 和 MCP 触发——不再仅限于测试
183 个目标重新运行:0 错误,与 v0.2.2 的 approval/escalation 分布相同
AdversarialDebate v0.2.2(发布说明,现场测试报告):
Noise-floor baseline:每对组合 10,000 次 bootstrap 重采样,每个指标都有 95% 置信区间
Permutation control:500 次打乱,零分布含 z-score
Shared RLHF priors:记录了 Mistral 效应的竞争性因果机制
21 个新测试,零新 LLM 调用,$0.00 成本
两个项目现在都有了能够捕获本文所述失败类别的测量基础设施。但那套基础设施是在失败被发现之后构建的——通过阅读转录稿,通过社区评论,通过运行基准测试并得到一个我不想看到的数字。
如果我要构建第三个系统——或者为构建第一个系统的人提供建议——我会从两个项目都错过的那个东西开始。
一个跨系统不变式检查器。不是功能,不是门控。是一个笨拙、便宜、独立的工具,在每次评估之后运行,断言输出是在诚实条件下产生的。它不需要理解领域,它需要知道输出的形态,并检查那个形态是否仍然是正确的形态。
对于 PlannerCritic,这意味着:每个门控类仍然在其 canary fixture 上触发。脱敏层没有损坏数字。决策上下文不是"未知"。
对于 AdversarialDebate,这意味着:噪声底限已测量,报告的差异超过它。置换控制零分布是稳定的。没有辩论超过投降阈值。
同一个检查器,不同的项目配置。对不信任自己输出这一承诺的共同坚守。
两个项目构建时间相隔数月,架构不同,用例不同。PlannerCritic 关于规划安全——计划是否能通过结构检查?AdversarialDebate 关于审查质量——第二意见是否真正挑战了第一意见?
但它们得出了相同的工程教训,而这是我会挂在墙上的一条:
你最信任的层,是你最可能停止监视的层。
修复方案是无论如何都要监视它——用一个独立的、更便宜的、更笨的检查,它存在的唯一目的是告诉你那个昂贵的层是否还活着。不是因为昂贵的层不可靠。是因为当指标变绿、仪表盘显示"改进"时,你不可靠。
这就是 gate canary 为 PlannerCritic 所做的事。这就是 capitulation detector 为 AdversarialDebate 所做的事。而这是我会在下一个系统中首先构建、而不是最后构建的东西——在第一次现场测试之前,在第一次发布之前,在指标第一次对我撒谎而我没有注意到之前。
因为第一次总是会发布的那一次。
前期 AdversarialDebate 文章
I Thought My Multi-Agent Debate Engine Was Broken. The Real Bug Was the Prompt.
The Best Model Pair in My Field Test Was Also the Least Trustworthy
Most AI Second Opinions Are Fake. I Built a Two-LLM Review Engine to Prove It.
Most AI Second Opinions Are Theater. I Built a System That Actually Fights Back.
PlannerCritic: https://github.com/deghosal-2026/planner-critic-engine
PlannerCritic v0.2.3 release notes: https://github.com/deghosal-2026/planner-critic-engine/blob/main/docs/reference/release-notes-v0.2.3.md
PlannerCritic v0.2.3 field test report: https://github.com/deghosal-2026/planner-critic-engine/blob/main/docs/field-test/v0.2.3/FIELD_TEST_REPORT.md
AdversarialDebate: https://github.com/deghosal-2026/adversarial-debate
AdversarialDebate v0.2.2 release notes: https://github.com/deghosal-2026/adversarial-debate/blob/main/docs/reference/release-notes-v0.2.2.md
AdversarialDebate v0.2.2 field test report: https://github.com/deghosal-2026/adversarial-debate/blob/main/docs/field-test/v0.2.2/FIELD_TEST_REPORT.md
Gate Canary (PlannerCritic): #278
F-20 deterministic-corruption (PlannerCritic): #296
F-14 approving_authority (PlannerCritic): #297
Noise-floor baseline (AdversarialDebate): #165
Permutation control (AdversarialDebate): #164
Shared RLHF priors (AdversarialDebate): #166
Capitulation detector (AdversarialDebate): https://github.com/deghosal-2026/adversarial-debate/blob/main/docs/field-test/v0.1.0/FIELD_TEST_REPORT_small_corpus.md
Artjoms Stukans comment (Kubernetes parallel): https://dev.to/artyomsv/comment/3dlpo