首页
/ LobeHub deep-review 技能输出契约深解:多 Agent 代码评审报告如何做到严谨、控噪与范围收敛

LobeHub deep-review 技能输出契约深解:多 Agent 代码评审报告如何做到严谨、控噪与范围收敛

2026-09-06 20:56:03作者:廉皓灿Ida

LobeHub 仓库内置的 deep-review Agent 技能通过"维度并行评审 → 对抗式验证 → 全局去重 → 结构化报告"的流水线产出代码评审结论,而 report-template.md 正是 Deep 模式的输出契约:它规定了每条 finding 如何定级、如何渲染、哪些必须本 PR 修复、哪些移交其他责任人,以及 PR 模式下如何给出 Merge verdict。读完本文,你将掌握该契约的完整渲染规则、决策表与报告骨架,并能结合仓库中的验证提示词与 Zod 校验脚本理解"报告字段从哪里来、为什么这么设计",从而在自己的多 Agent 评审流程中复用这套范围控制与降噪机制。

1. 模板的定位:覆盖环境默认格式的硬性输出契约

原文档开篇即声明了三条定位,这是理解整份模板的前提:

  1. 它是 deep 模式的 output contract覆盖任何环境默认的报告格式(Claude Code / Codex 等各 harness 自带的 review 输出习惯一律让位);
  2. 必须渲染完整报告,严禁把结果压缩成一条纯 finding 列表
  3. 报告语言跟随会话语言——下面的结构是契约,措辞可以翻译。

这一设计与 SKILL.md 的"两条入口模式"相呼应:Light 模式(默认)由单个独立评审者按各维度的 Quick checklist 检查,不使用 deep 报告模板,直接用环境的普通 review 格式转述(见 light-review-prompt.md 中的 "Write an ordinary markdown review, not JSON and not a structured deep-review report");只有显式触发的 Deep 模式(/deep-review)才走"维度评审 Agent → 流水线验证 → 全局整合 → 结构化报告 → 交互式修复"的完整编排,并严格套用本文模板。因此这份模板本质上是 Deep 模式"最后一公里"的渲染规范:上游各子 Agent 返回的是结构化 JSON,主 Agent 负责把它折叠成下面的人读报告。

2. 渲染规则全集(Rendering rules)

模板第一条渲染规则就规定了筛选口径:只渲染 verdict: confirmed 的 finding(外加未验证维度,见下文第 6 节)。排序规则是:severity p0 → p1 → p2;同一 severity 桶内按 SKILL.md 中维度表的表序分组;同一维度内保持评审者顺序。

以下是模板"Rendering rules"章节的全部规则,逐条继承并展开:

2.1 结构强制存在

标题、头部元数据(Scope/Background/Execution)、TL;DR、Findings、Statistics 永远渲染——即使零条 confirmed finding,Findings 也要写明 "no confirmed findings",Statistics 照常显示各项计数。空桶(空 severity 桶)则相反:整个小节标题直接省略。

2.2 两个问题决定 finding 的命运,且两个都渲染

  • 这个改动是否引入了它:对应 nature / exposure 字段;
  • 它实际触发的概率有多高:对应 likelihood

模板强调:severity 本身永远不决定某条 finding 是否阻塞合并——这是与多数"红黄绿"评审报告最大的区别。具体语义由下文 Scope 规则与降级规则共同实现。

2.3 Nature 行与 Likelihood 行

  • Nature 行nature: "introduced" 是默认值,省略该行nature: "exposed_legacy" 则必须渲染 **Nature**: legacy surfaced by this change,并按 exposure 值附加 (triggered by this diff)(bystander find)
  • Likelihood 行:在每条 confirmed finding 上强制渲染 **Likelihood**: high | medium | low,永不省略——它和 severity 一起告诉用户"这条问题值不值得再来一轮修复"。low 时还必须把 scenario 中的前置条件链以括号附在后面。

这两个字段的合法性在上游就有硬约束:review-prompt.md 要求 exposed_legacy 必须携带 exposurescenariolow likelihood 必须携带 scenario,且校验脚本会拒绝违反者(见第 7 节)。

2.4 Scope 规则:legacy 问题不在本 PR 修复

nature: "exposed_legacy" 的 finding:

  • 永不渲染 Fix options永不进入 Safe to fix now
  • 统一渲染到 Hand off to owner 小节,并附一份 Linear issue 草稿(draft,不自动创建);
  • 唯一例外exposure: "triggered" 的 P0——是这份 diff 让老 bug 开始可触发,因此它按普通 finding 进入 severity 桶,并且阻塞合并

模板给出的理由很直白:"其余 legacy 都是别人的任务,把它们拉进本 PR 正是这条规则要防的 scope creep。" 这个设计在 review-prompt.md 的 "Review scope (hard rules)" 中有对应上游约束:评审者默认只报落在 diff + 行上的问题;顺带撞见的无关老问题(bystander)除非是显而易见的 P0 生产 bug,否则根本不报。

2.5 低 likelihood 降级(Low-likelihood de-escalation)

confirmed 且 likelihood: "low"blocks_release: false 的 finding:按验证后的 severity 正常渲染,但永不进入 Merge verdict 的前置条件,改入 Follow-ups。若用户声明这是对同一 PR 的第 N 轮复核(第二轮起),则所有 low + 非阻塞 finding 不论 severity 一律压缩为 More P2 下的一行,并加前缀 [low likelihood]。模板解释了动机:修复轮次多了以后,继续追杀罕见边界的边际价值低于其带来的 churn 与回归风险——要在 TL;DR 里明说降级了多少条,而不是静默丢弃

2.6 其余字段渲染细则

  • Issue type:原样渲染 finding 的 issue_type 字段,严禁用维度名顶替
  • Blocks release:渲染 verify 子代理返回的 blocks_release(yes/no),每条 confirmed finding 必带——这是用户的 ship/no-ship 信号;同一根因合并(same-root)的条目取其中最高合并 severity 对应的值。
  • Existing implementations 行:仅 reuse-architecture 去重类 finding 渲染,且列出全部条目。
  • Rule source 行:finding 带 rule_source 时渲染。
  • Override 优先级:先应用 fix_options_override / severity_override / nature_override / exposure_override / likelihood_override,再应用全局整合映射(consolidation map)。这些 override 字段来自验证阶段的返回值,见 verify-prompt.md 的 "Optional corrections" 定义。

2.7 Same-root 合并(Same-root merge)

被全局整合 pass 映射到 same_root_as: X 的 finding 折叠进 X 的条目:不再单独立编号;在 X 条目末尾追加 **Same root**: id (location, issue_type), ...;该条目 severity 升级为合并集合中的最高值;Statistics 中合并条目只计一次

上游的合并标准定义在 consolidate-prompt.md两条 finding 共享根因当且仅当"一个具体修复能同时解决两者";仅位置相近、主题相似或同维度都不算。该 pass 只在验证后至少剩两条 confirmed finding 时运行一次,且明确"不重新验证正确性",禁止自映射、禁止编造 id、禁止成环、禁止合并需要分别修复的问题。

2.8 P2 上限(噪声控制)

confirmed 的 P2 数量 > 6 时:完整渲染前 6 条,其余折叠为 More P2 下的一行:**#n** [issue_type] summary (file:line)。挑选完整渲染的 6 条时,low likelihood 的排最后。

2.9 Hand off to owner 的渲染细节

  • 每个非 "triggered-P0" 的 exposed_legacy finding 都在这里渲染一条;
  • 不创建 Linear issue,只渲染草稿,由用户决定是否提交——一次 deep review 可能挖出多条 legacy 项,自动建 issue 既吵又会与已有 issue 重复;
  • Culprit(肇事者)直接取自 verify 的 culprit 字段原样渲染(验证者当时已打开过文件),culprit: null 渲染为 "attribution unclear" 且不给建议 assignee;
  • 渲染阶段禁止重跑 git blame

2.10 Release checks:未验证、不计入 finding

release_checks 数组(仅 release-risk 维度产出)渲染在 Pre-deploy checklist 下,位于 severity 桶之外,排除在所有 finding 统计之外。模板强调它们"设计上就是未验证的"——它们是关于生产状态的问题,而非对代码的断言;永不与 finding 合并,也永不成为 merge verdict 的前置条件;其中 blocks_deploy: true 的条目排最前,并在 verdict 的 Basis 行中作为"部署时条件"点出,而非代码阻塞项。

这一"双输出形态"的源头在 release-risk.md 维度文件:代码或 diff 本身能证明回滚风险时发 issues finding;而安全部署依赖仓库无法回答的生产/外部状态(现有行数据形状、线上配置、队列存量)时发 release_checks

2.11 未验证维度、缺失规则源与 Workflow 反馈

  • Unverified dimensionsworkflow 维度的 finding 渲染到 Processskill-freshness 的渲染到 Skill updates——均在 severity 桶外、不计入 P0/P1/P2 统计。它们使用与其他 finding 相同的 JSON schema,但每条只渲染一行:fact = summary,evidence = location(有 scenario 时附上),suggested action = 第一条 fix_options;其 severity 仅为参考性,永不渲染。这与 SKILL.md 维度表中 Verified? no 的语义一致(客观状态检查/建议项,跳过 verify pass 直达报告)。
  • Missing sources:任一评审者返回 missing_sources 时,在报告末尾追加提示,建议修复/恢复所列规则文件。
  • Workflow feedback:跨子代理合并等价建议、累积来源(如 sources: code-style, verify),渲染在报告末尾;为空则整节省略。

2.12 PR 模式的触发条件

当用户提供 GitHub PR URL 或无歧义的 PR 引用PR #123pr 123pull request 123)时渲染 Merge verdict#123 仍属歧义,不触发 PR 模式

3. Merge verdict 决策表(PR 模式,主 Agent 亲填,永不委托)

模板给出了"first match wins"的决策表,必须按顺序命中即止:

条件 判定
isDraft: true do not merge yet
mergeable: "CONFLICTING" do not merge yet
任一 check conclusion: "FAILURE" do not merge yet
in-scope P0 confirmed > 0 fix before merge
in-scope P1 confirmed > 0 fix before merge
其余(仅 P2 / 全部 out-of-scope / 干净) good to merge

In-scope 的精确定义nature: "introduced"或者 nature: "exposed_legacy"exposure: "triggered" 且 severity 为 P0。其余一切——任意 severity 的 bystander legacy、P0 以下的 triggered legacy——都是本 PR 的 out-of-scope:永不成为前置条件,一律进 Hand off to owner。模板的理由:"我们的 diff 应当按它改变了什么来评判。一个我们只是路过撞见的老 bug,不该因为我们恰好评审了附近代码就变成我们的义务——把路过问题当义务,正是专注 PR 膨胀成一周五个无关修复的方式。"

追加降级:in-scope 但 likelihood: "low"blocks_release: false 的 finding 同样不计入 P0/P1 前置条件,列入 Follow-ups

回退规则(Fallbacks)

  • mergeable: "UNKNOWN" → 按可合并处理;
  • 所有 check 都在 in progress/queued → CI pending,不阻塞;
  • 未配置任何 check → 视为 CI pass;
  • "fix before merge" 列出 in-scope 未降级的 P0/P1 编号 + 一行摘要作为前置条件;
  • "good to merge" 列出 P2 与降级 finding 作为 follow-ups;
  • 若判定为 "good to merge" 但 Hand off to owner 非空,必须用一句话点明:可以合并,留下了 N 项给其他 owner。

4. 发送前自检清单(Pre-send self-check)

模板要求发送前逐项确认,缺任何一项都必须修正后重新渲染:

  1. 标题 + 头部元数据(scope / background / 含裁剪维度及理由的执行模式)齐全;
  2. TL;DR 存在;Findings 存在(或显式 "no confirmed findings");Statistics 存在;
  3. 每条渲染在 severity 桶中的 confirmed finding 都带:issue type、location、blocks release、likelihood、core problem、evidence、fix cost、fix options、needs test。(Hand off to owner 下的条目按下一条检查——Scope 规则禁止它们出现 fix options,若这里强制要求,两条规则将互相不可满足。)
  4. 每条 exposed_legacy finding 要么是以 triggered-P0 身份出现在 severity 桶中,要么是 Hand off to owner 下的一条——两者居其一,永不同时,永不就地修复,永不进 Safe to fix now
  5. release_checks 以 checklist 形式渲染在 Pre-deploy checklist 下,永不计入 finding,永不作为合并前置;
  6. 无 out-of-scope 或 low-likelihood-non-blocking finding 出现在 Merge verdict 前置条件中;
  7. Merge verdict 仅在 PR 模式出现。

5. 报告模板骨架(完整契约结构)

以下骨架来自 report-template.md 的模板主体,占位符与省略条件均按原文保留:

# Deep Review Report

**Scope**: {如 `feat/user-batch-delete` vs 本地 `main`,8 files +240/-37,含子模块 lobehub}
**Background**: {第 0 步 scope 摘要的核心 1-2 句}
**Execution**: {N} 个维度评审者({列表})+ {M} 个验证者{+ 运行了全局整合时注明}; pruned: {维度 — 一行理由,或 "none"}

## TL;DR

{1-2 句:X 条 confirmed(P0 a / P1 b / P2 c),其中 Y 条必须本 PR 修复、Z 条移交其他 owner;最大单一风险;一个建议的下一步动作。重复评审轮次要说明降级了几条 low-likelihood finding 而非再翻案。}

> 只保留与本改动相关的 finding。两个标签驱动分诊:**Nature** 说明该问题是被本次改动引入、还是只是路过旧代码;**Likelihood** 说明该场景实际触发的频率。既存问题列在 "Hand off to owner" 而不是在这里修复——这是刻意的范围控制,不是疏漏。

📣 报告末尾有 {N} 条 workflow feedback ← 仅当 workflow_feedback 非空

## Merge verdict ← 仅 PR 模式

**Verdict**: {good to merge | fix before merge | do not merge yet}
**Basis**: in-scope P0 {x} / P1 {y} / P2 {z} confirmed | CI {pass|fail|pending} | draft {yes|no} | mergeable {ok|conflicting} | out-of-scope 移交 {h} | pre-deploy checks {c}({d} 阻塞部署)
**Prerequisites**: #{n} {summary} ← 仅 "fix before merge";只含 in-scope、未降级 finding
**Follow-ups**: #{n} {summary} ← P2 + 降级的 low-likelihood finding

---

## 📌 Findings

### 🔴 P0 ({n})

#### 1. {summary}

- **Issue type**: {issue_type}
- **Location**: `src/api/user.ts:87`
- **Blocks release**: yes
- **Likelihood**: {high | medium | low}{ — low 时附前置条件链}
- **Nature**: legacy surfaced by this change (triggered by this diff) ← 仅 exposed_legacy
- **Existing implementations**: `src/foo.ts:62-138`, ... ← 仅 reuse 去重
- **Rule source**: {rule_source} ← 存在时
- **Core problem**: {core_problem}
- **Scenario**: {scenario}
- **Evidence**: {verify 证据}
- **Fix cost**: low
- **Fix options**:
  - Option A: ...
  - Option B: ...
- **Needs test**: yes
- **Same root**: {id} ({location}, {issue_type}) ← 仅合并条目

### 🟡 P1 ({n})

...

### 🟢 P2 ({n})

...

**More P2** ← 仅当 P2 > 6,或重复评审轮次中降级的 low-likelihood finding

- **#{n}** [{issue_type}] {summary} ({file:line})
- **#{n}** `[low likelihood]` [{issue_type}] {summary} ({file:line}) ← 重复评审降级

---

## 🤝 Hand off to owner ({n}) ← 不在本 PR 修复的 exposed_legacy finding,为空则省略

> 既存问题,非本次改动引入。此处刻意不修——修了就会扩大本 PR 范围。确认后我会提交 issue。

- **#{n}** `[{severity}]` `[{likelihood}]` {summary}
  - **Location**: `file:line`
  - **Culprit**: `{commit}` (@{author}, {date}) ← verify 的 `culprit`;为 null 时写 "attribution unclear"
  - **Nature**: {triggered by this diff, but below P0 | bystander find}
  - **Issue draft**: {title} — {一行描述 + 影响}
  - **Suggested assignee**: @{author} ← 归属不明时省略

---

## ✅ Pre-deploy checklist ({n}) ← release_checks,为空则省略

> 不是缺陷——是本次改动依赖、但无法从代码确认的事项。部署前请核查。

- [ ] **{item}** ← `blocks_deploy: true` 的排最前并标 ⚠️
      {why}

---

## 🔁 Process ← workflow 维度 finding,为空则省略

- {summary} — {location}{;有 scenario 时附上}; suggested: {fix_options[0]}

## 📚 Skill updates ← skill-freshness finding,为空则省略

- {location: 过时的 skill file:line 或新提议的 skill} — {summary}; suggested: {fix_options[0]}

## Statistics

- Confirmed: {n}({k} 条 legacy-surfaced)| False positives: {fp}(含 {os} 条 over-scrutiny)| Need more context: {nc}
- Must-fix this round: {in-scope p0+p1} | Blocks release: {n} | Handed off: {h} | Deferred as low-likelihood: {l}
- Likelihood: high {a} / medium {b} / low {c}
- By dimension: {dimension: count, ...}

## 🚀 Safe to fix now ({n}) ← 为空则省略

> 单一显而易见修复、低风险、无需产品决策,可一次性批量应用。仅限本次改动引入的 finding——legacy 代码永不在此自动修复。

- **#{n}** `[{issue_type}]` {summary} (`file:line`)

## Needs your input ← 仅 need_more_context,为空则省略

- [ ] {summary} — missing: {missing}

## 📣 Workflow feedback ({n}) ← 为空则省略

> 本次运行中各子代理对评审流程本身的观察。不是行动项——用于决定是否更新 skill 文件。

- **Suggestion**: {suggestion}
  **Why**: {why}
  **Sources**: {code-style, verify}

几个骨架细节值得注意:Statistics 行中的 "Must-fix this round" 只统计 in-scope 的 p0+p1;"False positives" 单独标出其中 over-scrutiny(校准过度审查)的占比——这与 SKILL 的核心原则"按代码库既有水平校准,而非理想化标准"形成闭环;Safe to fix now 只收 can_auto_fix 语义下的"本次改动引入"问题,与 verify-prompt.mdcan_auto_fix: true 的四条件(fix_cost low、唯一显而易见修复、无需外部资源或产品决策、改动少于三个文件且不触及架构层/DB schema/外部契约/用户可见行为/路由/热键/文案/权限边界)严格对应,且明确 release-riskexposed_legacy 永不自动修复。

6. 源码印证:报告字段如何从子代理 JSON 一路抵达渲染

模板里的每个字段都不是凭空规定,上游三段式流水线(review → verify → consolidate)与一个 Zod 校验脚本共同保证了"渲染规则可执行"。

第一段:评审输出 schema。 review-prompt.md 规定每个评审子代理返回单个 JSON 对象,每条 issue 必带 iddimensionissue_typenatureseveritylikelihoodlocationsummarycore_problemfix_cost、至少一条 fix_optionsneed_test;条件字段为 exposed_legacy 时的 exposure/scenario、low likelihood 的 scenario、reuse-architecture 的 existing_implementations

第二段:对抗式验证。 验证与评审永不共用同一 Agent(防自批原则)。verify-prompt.md 要求验证者对每条 finding:打开位置读足上下文 → 追调用方/类型/校验/测试 → 先找反例(上游保证、提前返回、框架行为)→ 校验 nature/exposure/likelihood/severity,用 *_override 字段纠正评审者的误标;bystander 老问题除非是显而易见的 P0 生产 bug,否则判 false_positive 且 reason 以 out-of-scope legacy: 开头;校准过度(普遍存在且未被加剧、或用永久代码标准衡量声明过期的临时代码)判 false_positive 且 reason 以 over-scrutiny: 开头——这正是 Statistics 行中 "over-scrutiny" 计数的前缀约定来源。三分判决 confirmed / false_positive / need_more_context 取代了置信度百分比("听起来校准过的分数不可靠"),blocks_release 的判定标准(P0 必须阻塞、P2 不得阻塞、low likelihood 除非灾难性且不可逆否则不阻塞)则直接喂给模板的 **Blocks release** 行与 Merge verdict 的 Basis 行。

第三段:全局去重。 consolidate-prompt.md 返回 {"same_root":[{"id":"style-2","same_root_as":"ai-1"}]} 形式的映射,只返回"更晚出现"的重复 id,并以输入顺序中最早的一条为根。模板中 "no separate number / severity 升级 / 统计只计一次" 三条渲染规则正是该映射的消费方式。

契约的机器可执行性。 validate-output.ts 用 Zod 把三类输出固化成 schema 并做成 CLI(validate-output.ts <review|verify|consolidate> [input-file],也支持 stdin)。值得对照模板阅读的约束(validate-output.ts#L12-L60):

  • severity 仅允许 p0/p1/p2——模板的三级桶因此不可能出现第四级;
  • exposed_legacy 必须带 exposurescenariointroduced 必须省略 exposure——模板的 Nature 行渲染逻辑因此总能取到所需字段;
  • likelihood: "low" 必须带 scenario——模板"low 时附前置条件链"因此总能渲染;
  • reuse-architecture 必须带 existing_implementations——模板的 Existing implementations 行因此只在该维度出现时有意义;
  • verify 侧,非 auto-fix 的 confirmed 必须给 auto_fix_reasonsame_root 映射的 id 不可重复(validate-output.ts#L144-L161)。

validate-output.test.ts 中的测试用例(如 "requires exposed legacy findings to explain their exposure"、"rejects severity levels outside the review contract")逐条验证了上述约束;extractJsonPayload 则保证子代理回复中的 JSON 围栏可被稳定抽取(拒绝未闭合围栏、拒绝多个围栏)。

未验证维度的 schema 复用。 workflowskill-freshness 的 finding 使用同一 schema,但模板只取 summary/location/fix_options[0] 渲染单行、忽略 severity——这解释了为什么 SKILL 维度表中这两个维度标记为 Verified? no:它们是客观状态或建议项,跳过验证直通报告,同时被排除在 P0/P1/P2 统计之外。

7. 适用前提与限制

  • 本文所有规则以当前仓库 deep-review 技能 的实际内容为准;模板语言随会话语言翻译,但结构(小节名、字段行、决策表)是契约,不可裁剪。
  • Deep 模式受"逻辑需求预算"约束:同一需求/PR/分支默认最多跑一次 Deep,后续复核走 Light 模式——模板中 "重复评审轮次" 的降级渲染因此只会在用户显式再触发 Deep 的场合出现。
  • Merge verdict 仅在用户提供 PR URL 或无歧义 PR 引用时渲染;本地 diff 评审(无 PR 上下文)不会产出该小节。
  • 渲染阶段不重跑 git blame、不创建 issue、不重新验证——这些动作要么前置到 verify 阶段(culprit 归因),要么留给用户决策(Linear issue 草稿)。

小结:这份报告模板把多 Agent 评审中最容易失控的三件事——范围蔓延(legacy 移交而非就地修)、噪声(P2 上限 + low-likelihood 降级 + same-root 合并)、责任归属(culprit 归因 + 移交草稿)——全部编码成了可自检、可机器校验的渲染契约。对照 SKILL.md 的"防幻觉、防自批、规则优于模型、按代码库校准、速度即特性"五条核心原则,可以看出模板中的每一条规则都服务于其中一个:这是把工程纪律写进输出格式的典型样本。

登录后查看全文
热门项目推荐
相关项目推荐