从 PRE 到 Tree Rubrics:让 Rubric 成为可迭代的 Agent 质量门禁

作为《Rubric Is All You Need》的续篇,本文复盘 multi-agent-pipeline 如何从 PRE/EME 的平面 checklist 迭代到 Tree Rubrics,让 Rubric 从最终裁判表变成可生成、可验证、可反馈的 Agent 质量门禁。

从 PRE 到 Tree Rubrics:让 Rubric 成为可迭代的 Agent 质量门禁

上一篇《Rubric Is All You Need》讨论的是一个起点:当 AI 开始大规模写代码时,我们不能只问“它能不能跑”,还要问“它是不是按照正确的逻辑、正确的结构、正确的工程意图在实现”。传统 Test Harness 擅长守住物理正确性,Rubric 则补上语义审查与工程判断。

但这只是第一步。

当我把 Rubric 真正放进一个长程 multi-agent pipeline 里时,很快遇到第二个问题:Rubric 自己也需要迭代。它不能只是贴在审查阶段末尾的一张评分表,而应该成为驱动实现、返工、验证和再评估的控制回路。

这篇文章写的就是这次迭代:从 PRE / EME 这样的平面 checklist,走向 Tree Rubrics 这样的树状、可验证、可反馈的质量门禁。


PRE 的价值:把审查变成硬门禁

早期版本里,我采用的是 PRE(Pointwise Rubric Evaluation)风格的审查。它的思想非常直接:把代码质量拆成若干维度,每个维度都必须独立给出 pass、warning 或 fail。

multi-agent-pipeline 里,PRE rubric 覆盖了八个维度:

  • Correctness:是否满足规格和验收条件
  • Security:是否存在注入、泄露、认证授权缺失等风险
  • Performance:是否有明显的 N+1、阻塞调用、无界循环或错误复杂度
  • Error Handling:外部调用、空值、异常输入和失败路径是否处理妥当
  • Code Quality:命名、风格、抽象、重复、死代码是否符合维护要求
  • Architecture Compliance:实现是否遵守 architecture 里约定的边界和依赖
  • Test Coverage:关键路径、错误路径、复杂逻辑是否有有效测试
  • Backward Compatibility:公共 API、数据格式、旧行为是否被破坏

这个设计的优点是强约束。它迫使 reviewer 不再说“整体还行”这种模糊判断,而必须逐项回答:这一项到底过没过?证据在哪里?如果失败,具体修哪里?

PRE 还有一个重要纪律:每个评分都必须附证据。pass 也不能空口说“看起来没问题”,而要说明查了什么、对应哪段实现;warning 和 fail 则必须给出具体位置、问题描述和修复建议。

这使它非常适合作为 production review gate。尤其在安全、兼容性、测试覆盖这些领域,模糊的乐观判断最危险。PRE 的价值就在于它把“我觉得可以”改造成“这八个维度都有可辩护证据”。


PRE 的瓶颈:平面表格不适合长程 Agent

问题也在实践里暴露得很快。

PRE 本质上是一张平面 checklist。它能告诉我们“安全过没过”“测试过没过”,但不擅长表达一个任务内部的结构关系。对一个真实开发任务来说,质量并不是八个固定维度的简单并列。

比如一个搜索功能的实现,至少有几层不同深度的要求:

  • 第一层:输入能被接收,结果能返回
  • 第二层:排序、过滤、分页符合产品规格
  • 第三层:边界条件、权限隔离、性能退化路径都被考虑

这些不是三个互不相关的维度,而是同一条能力链上的深浅层次。如果第一层都没有完成,第三层写得再漂亮也没有意义。平面 PRE 很难表达这种“浅层失败会阻断深层评分”的关系。

另一个问题是任务特异性。

PRE 的八维标准很适合作为通用审查底线,但它很难自动长出“这次任务真正重要的判断标准”。不同任务的关键点并不相同:前端设计任务需要关注视觉层级和交互反馈;数据迁移任务需要关注旧格式兼容和回滚路径;并发任务需要关注锁、幂等、重试和一致性。固定八维 rubric 容易把所有任务压进同一张表。

更深的问题是反馈回路。

PRE 可以告诉执行者哪里失败,但它不天然区分“必须先补的基础节点”和“可以后续增强的深层节点”。当 Agent 收到一组 fail/warning 时,容易把它理解成一堆平行修改项,而不是一条应该分阶段修复的质量路径。

这就是我开始转向 Tree Rubrics 的原因。


Tree Rubrics:先生成评测树,再评价最终产物

当前 multi-agent-pipeline 的默认质量门禁已经从 PRE / EME 转为 Tree Rubrics。

它的核心变化不是“把表格换成树”,而是把 Rubric 变成一个可生成、可验证、可精炼、可评分的阶段化系统。

在每个 worker group 完成合并并通过 Validation 后,流水线会单独运行一组 rubric 阶段:

  • Classification:识别当前任务类型,以及是否适合做深度增强。
  • Generation:从规格、架构和 worker group 中生成初版 tree_rubrics.json
  • Verification:检查这棵评测树是否具体、端到端可判定、宽度和深度是否合理。
  • Refinement:根据验证反馈做最小必要修改,得到 tree_rubrics_refined.json

然后 orchestrator 本地生成 final-output-files.json。这个快照只包含该 group 最终交付相关的文件内容,范围来自 changed_files ∪ owned_files

最关键的一条纪律是:Tree Grading 只看最终输出文件。

三个独立 grader 收到的输入只有:

  • spec.json
  • worker_group
  • tree_rubrics_refined.json
  • final-output-files.json
  • grader id 和 iteration

它们不能看 execution report,不能看 validation report,不能看 merge report,不能看日志,不能根据“Agent 似乎努力过”给同情分。评分必须只根据最终文件内容判断。

这条规则很重要。它把过程努力和最终交付切开了。Agent 可以尝试很多次,可以经历复杂合并,可以跑过很多命令,但最后门禁只问一个问题:交付物本身是否满足这棵评测树?


宽度与深度:Tree Rubrics 真正多出来的能力

Tree Rubrics 相比 PRE 最大的改进,是把“宽度”和“深度”分开建模。

宽度代表独立维度。比如一个任务可以有 Correctness、Data Model、API Contract、User Experience、Migration Safety 等分支。每个分支都应该是相对独立的质量方向,而不是把一堆不相关标准塞进同一条链。

深度代表能力层次。同一个 branch 里的 depth 1、depth 2、depth 3 不是同义重复,而应该是逐层提高的标准:

  • depth 1:基础能力是否存在,是否满足必须条件
  • depth 2:关键边界、组合场景、主要质量要求是否成立
  • depth 3:更高水平的完整性、鲁棒性、可维护性或体验质量

这让 rubric 能表达一个很自然的工程判断:基础没过,深层不算。

在当前实现里,orchestrator 会对三个 grader 的节点评分做多数投票。每个节点原始分是 0 或 1;同一 branch 内如果浅层节点失败,更深层节点的 effective score 会自动变成 0。

权重也体现了深度差异:

  • depth 1 权重为 1
  • depth 2 权重为 2
  • depth 3 及以上权重为 3

最终通过条件是两部分同时满足:

  • weighted_score >= 0.80
  • 所有 depth 1 节点都必须通过

这比单纯平均分更合理。它既鼓励深层质量,又不允许基础能力缺失。一个实现不能靠做好几个高级增强项来掩盖最基本的需求没完成。


Rubric 从“裁判表”变成“控制回路”

Tree Rubrics 真正改变的不是评分形式,而是 pipeline 的动力学。

在旧模型里,Rubric 更像最终裁判:实现完成后,reviewer 拿一张表打分,失败就返工。但返工依据常常是平铺的:修 correctness、补 tests、处理 compatibility。它能指出问题,却不一定给出最清晰的修复顺序。

Tree Rubrics 让反馈更像一棵导航树。

如果 depth 1 节点失败,说明基础目标没完成,Execution 必须优先回到核心需求。如果 depth 1 全过但 depth 2 失败,说明实现方向正确,但边界条件、组合行为或主要质量层还不够。如果只剩 depth 3 失败,通常意味着工作已经具备可用基础,下一轮应该围绕鲁棒性、表达力或维护性增强。

因此,评分结果不只是 pass/fail,而是告诉下一轮 Execution:该补地基,还是该补结构,还是该打磨高阶质量。

当前 pipeline 的循环就是这样组织的:

Execution
  -> Complexity Hook
  -> Merge
  -> Validation
  -> Tree Rubrics Grading
  -> pass: QA
  -> fail: 回到 Execution

Validation 负责命令层证据,例如测试、构建、语言检查。Tree Grading 负责最终文件的语义质量。QA 则补上二者都难以完全覆盖的运行时或场景验证。

这三者不是替代关系,而是分层防线:

  • Validation 问:项目能不能通过可执行检查?
  • Tree Grading 问:最终文件是否满足任务特定的质量树?
  • QA 问:真实使用场景里是否还有缺口?

这样一来,Rubric 不再是最终盖章工具,而是让 Agent 系统可以持续收敛的反馈机制。


为什么这对 Vibe Coding 更重要

Vibe Coding 的问题不是“AI 不会写代码”。恰恰相反,问题是 AI 太会写代码了。

它可以在很短时间内生成大量文件、大量组件、大量看似合理的实现。人类 reviewer 面对这种输出时,很容易陷入两种极端:要么只跑测试,测试过了就放行;要么试图逐行审查,最后被规模压垮。

Tree Rubrics 提供了第三种路径:把人类工程判断预先结构化,让多个评估 Agent 基于最终产物进行独立判断,再把聚合后的失败节点送回实现者。

这不是用 LLM 替代测试,也不是用 LLM 替代人类判断。更准确地说,它把人类判断外部化成一套可执行的评估协议。

人类仍然决定什么是好的标准,系统负责在每一轮迭代里稳定执行这些标准。

这也是为什么我越来越倾向于把 Rubric 看成 Agent Harness 的核心组件。Memory 外部化长期状态,Skills 外部化过程能力,Protocols 外部化交互结构,而 Rubric 外部化质量判断。

没有 Rubric,Agent 只能“尽力完成任务”。有了可迭代 Rubric,Agent 才能知道自己离“完成得好”还差什么。


下一步:Rubric 也需要自己的学习系统

Tree Rubrics 还不是终点。

第一,classification 可以继续增强。不同任务应该触发不同的 rubric 生成策略:UI 任务、数据库任务、并发任务、文档任务、迁移任务,本来就不该共享同一套深度模板。

第二,节点可判定性需要更强约束。每个节点都必须能从最终输出文件判断,这听起来简单,实际很难。很多坏 rubric 会偷偷引入过程依赖,比如“Agent 是否充分考虑过回滚”。更好的写法应该是“代码中是否提供回滚入口、旧格式读取路径或迁移失败处理”。

第三,grader 分歧本身值得记录。如果三个 grader 经常在某类节点上分裂,说明问题不一定在实现,也可能在 rubric 表述不够清晰。分歧分析可以反过来改进 rubric generation。

第四,跨任务的 rubric 记忆值得沉淀。某些失败会反复出现:测试只覆盖 happy path、前端缺少空状态、API 缺少幂等、迁移没有旧数据样本。把这些模式沉淀为可检索的 rubric memory,可能会让后续任务一开始就生成更好的评测树。

这也是我对下一阶段 Agent 工程的基本判断:未来的关键不是让模型“一次性更聪明”,而是让系统拥有更好的外部化结构。

Spec 让目标外部化,Plan 让路径外部化,Architecture 让边界外部化,Validation 让可执行检查外部化,Rubric 则让质量判断外部化。

当这些结构形成闭环,Agent 才不只是一个会写代码的模型,而是一个能被持续纠偏、持续逼近工程标准的系统。


结语

PRE 的意义在于把 review 从主观印象推进到证据化 checklist。Tree Rubrics 的意义在于继续往前走一步:把 checklist 变成有宽度、有深度、能反馈、能迭代的质量树。

如果说上一篇文章的结论是“定义好 Rubric,比让 AI 直接写代码更重要”,那么这篇的结论是:

Rubric 不能只是标准。它必须成为系统的一部分。

在长程 Agent 开发里,真正可靠的不是某一次生成的灵光一闪,而是每一轮都能被同一套质量结构重新拉回正轨。