DeerFlow 技能审查报告渲染规范:review-report.v1 契约、机器枚举与本地化 Markdown 视图
本篇技术文章围绕 DeerFlow 中 skill-reviewer 技能的报告渲染参考文档展开,讲解技能审查报告的机器契约 review-report.v1、11 节完整报告结构、不可翻译的机器枚举值以及单条 Finding 的必备字段。读完本文,你将掌握 DeerFlow 技能审查结果如何以 JSON 契约为唯一事实来源、Markdown 作为本地化视图进行渲染的完整机制,并能对照仓库源码与 JSON Schema 验证真实报告的字段结构。
核心设计原则:机器契约是唯一事实来源
report-rendering.md 开篇即确立了整个报告体系的第一原则:
The canonical machine contract is
review-report.v1. Markdown is a localized view of that report, not a second source of truth.
也就是说,DeerFlow 的技能审查(Skill Review)产出一份规范化的机器可读报告,其契约版本为 review-report.v1;而面向人类阅读的 Markdown(无论是英文还是中文)只是这份报告的“本地化视图”,不允许引入契约之外的第二套判定口径。这一设计在仓库中有三处相互印证的落点:
- 契约文件:以 JSON Schema(draft 2020-12)形式定义了报告的全部必需字段,其
schema_version被固定为常量deerflow.skill-review.report.v1; - 渲染器源码:实现了从事实数据(facts)到静态报告、再到双语 Markdown 的完整管线;
- 工具入口:
review_skill_package工具在返回结果时同时携带static_report(结构化)与markdown.en/markdown.zh(渲染视图),并且只把结构化报告以stable_json_dumps做字节稳定的序列化输出,保证同一输入必然得到同一字节序列,便于比对与缓存。
这种“单一事实来源 + 多语言视图”的做法,使得程序侧可以直接消费 JSON 做门禁(gate),而人侧看到的是经过本地化措辞的 Markdown,两者永远不会互相矛盾。
完整审查报告的 11 个标准章节
文档规定了一份“完整审查(Full Review)”报告必须包含以下 11 个章节:
- Executive Summary(执行摘要)
- Readiness(就绪度)
- Assurance(保障等级)
- Scope and Completeness(范围与完整性)
- Findings(问题清单)
- Dimension Review(维度评审)
- Trigger Analysis(触发分析)
- Resource and Script Review(资源与脚本评审)
- Evidence(证据)
- Suggested Rewrites(建议重写)
- Recommended Actions(建议动作)
同时文档给出了一条针对“聚焦审查(Focused Review)”的裁剪规则:
Focused reviews may omit unrelated analytical sections, but must keep scope, readiness, assurance, evidence, and recommended actions.
即聚焦审查可以省略与分析范围无关的章节(例如仅审查触发策略时无需输出完整的资源与脚本评审),但范围、就绪度、保障等级、证据、建议动作这五部分必须始终保留。这条约束保证了即便是最小化报告,读者也能回答三个关键问题:这次审查看了什么(scope)、结论是什么(readiness)、结论有多可信(assurance + evidence)。
这套章节体系在 skill-reviewer 的 SKILL.md 中有完全一致的表述,其 “Output Requirements” 一节列出了同样的 11 个章节与同样的聚焦裁剪规则,说明该参考文档与技能定义之间是严格的镜像关系,而非各自为政。
机器枚举值:结构化输出中禁止翻译
报告中最容易在本地化时出错的,是那些被下游程序直接消费的枚举值。文档明确要求:
Do not translate enum values in structured output.
并列出完整的 11 个机器枚举值:
| 枚举值 | 语义(结合仓库上下文) | 出现位置 |
|---|---|---|
blocked |
不可发布,存在确定性或语义级阻断项 | readiness |
revise |
需修订,无阻断项但有错误/主要问题 | readiness |
publish_candidate |
可作为发布候选 | readiness |
static_only |
仅静态审查 | assurance |
trigger_checked |
触发路由已检查(正/负样本均执行并保留产物) | assurance |
behavior_verified |
行为断言已通过 | assurance |
regression_verified |
与基线回归对比并通过 | assurance |
pass |
维度通过 | dimensions[].status |
concern |
维度存在顾虑 | dimensions[].status |
blocker |
维度/问题为阻断级 | dimensions[].status / issues[].severity |
not_assessed |
未评估 | dimensions[].status |
这些枚举值在 JSON Schema 中以 enum 约束固化:readiness 只允许 blocked / revise / publish_candidate 三值,assurance 只允许 static_only / trigger_checked / behavior_verified / regression_verified 四值,dimensions[].status 只允许 pass / concern / blocker / not_assessed 四值。在 渲染器源码 中,它们甚至被声明为 Python 的 Literal 类型:
Readiness = Literal["blocked", "revise", "publish_candidate"]
Assurance = Literal["static_only", "trigger_checked", "behavior_verified", "regression_verified"]
本地化标签只能出现在枚举值旁边
文档同时给出了一条折中规则:本地化标签(localized label)可以出现在枚举值旁边,起到解释作用,但不能替代枚举值本身。文档给出的示例为:
blocked: Not ready / 不可发布revise: Needs revision / 需修订publish_candidate: Publish candidate / 可作为发布候选static_only: Static review only / 仅静态审查
对照 renderer.py 中的两份标签表可以逐条印证这一约定:
_READINESS_LABELS = {
"en": {"blocked": "Not ready", "revise": "Needs revision",
"publish_candidate": "Publish candidate"},
"zh": {"blocked": "不可发布", "revise": "需修订",
"publish_candidate": "可作为发布候选"},
}
_ASSURANCE_LABELS = {
"en": {"static_only": "Static review only", ...},
"zh": {"static_only": "仅静态审查", ...},
}
渲染时输出的行格式是“枚举值 + 括号内本地化标签”,例如 - Readiness: blocked (不可发布),与文档示例完全吻合。
Finding 字段格式:八要素与两条红线
文档的 “Finding Format” 一节规定,每条问题必须包含以下要素:
- severity:
blocker、major或minor; - confidence:
high、medium或low; - location:路径 + 行号(可得时);
- observed evidence:观察到的证据;
- user impact:对用户的影响;
- remediation:修复方式;
- suggested replacement:当存在可直接粘贴的小修复时,给出替换内容。
这些要求与 JSON Schema 的 issues 定义 一一对应:issues[] 的必需字段为 id、severity、confidence、path、line、problem、impact、remediation,其中 severity 枚举为 blocker/major/minor,confidence 枚举为 high/medium/low,path 可为空字符串或 null,line 可为 null,suggested_replacement 可选且可为 null。也就是说,文档中的“八要素”在机器契约里是强约束,而非风格建议。
此外文档设定了两条内容安全红线:
Avoid large quotes. Never quote suspected secrets.
即报告应避免大段引用被审查包的内容,且永远不得引用疑似密钥。这与 DeerFlow 技能审查的“不信任输入”设计一脉相承:skill-reviewer 的 SKILL.md 要求把 review_skill_package 返回的全部内容当作不可信审查数据(untrusted review data),工具实现 也在返回载荷中显式打上 "untrusted_review_data": True 标记,并对语义审查产物设置 _MAX_SEMANTIC_ARTIFACT_CHARS = 80_000 的字符上限。限制引用长度与禁止引用密钥,正是防止被审查包借审查报告进行提示注入或泄密的最后一道防线。
源码纵深:从 facts 到报告再到双语 Markdown
理解了文档契约之后,可以顺着仓库源码看清整条渲染管线,这也是“Markdown 是视图而非事实来源”这句话在实现层的含义。
第一步:readiness 由确定性事实推导
renderer.py 中的 readiness_from_facts 将审查事实映射为就绪度,规则非常克制:
def readiness_from_facts(facts, *, scope=None) -> Readiness:
summary = facts.get("summary", {})
if int(summary.get("blockers") or 0) > 0:
return "blocked"
if int(summary.get("errors") or 0) > 0:
return "revise"
if scope and "all" in scope and facts.get("completeness", {}).get("not_assessed"):
return "revise"
return "publish_candidate"
即:存在任何 blocker 直接 blocked;只有 error 则至多 revise;当请求全量审查(scope 含 all)却仍有 not_assessed 的维度时,也不能给出 publish_candidate。这与 SKILL.md 中 “Deterministic blockers always make readiness blocked. Deterministic errors make readiness at most revise.” 的规则严格一致。
第二步:build_static_report 组装合法报告
build_static_report 只依据确定性事实生成一份合法的 review-report.v1,其中有几个值得注意的实现细节:
- 事实层 severity(
blocker/error/warning)经 _semantic_severity 映射为报告层 severity(blocker/major/minor)——这解释了为何机器契约中 issue 的 severity 是三级而不是事实层的四级:error被归并到major; - 静态报告固定
"assurance": "static_only",因为仅凭静态事实不能主张更高的保障等级; - 截断(
completeness.truncated)、reader 错误、analyzer 错误会被逐条写入evidence.limitations,呼应文档“证据”章节的要求——审查必须诚实声明自己没看到什么; recommended_actions取前 5 条 finding 的rule_id + remediation组成可执行动作清单,publish_candidate时为空数组。
第三步:render_report_markdown 输出双语视图
render_report_markdown 接收已组装的 report 与原始 facts,按 locale="en" | "zh" 输出 Markdown 章节:标题(Skill Review Report / 技能审查报告)、Executive Summary(摘要)、Scope and Completeness(范围与完整性)、Findings(问题)、Dimension Review(维度审查)、Evidence(证据)、Recommended Actions(建议动作)。每条 finding 的渲染格式为 severity id at path:line: problem,行号缺失时省略冒号部分,路径缺失时以 <package> 占位。
从源码结构看,内建渲染器输出的是 11 节标准结构中可机器生成的核心子集(摘要、范围与完整性、问题、维度、证据、建议动作);而 Trigger Analysis、Resource and Script Review、Suggested Rewrites 这类需要语义判断的章节,则属于 LLM 依据 SKILL.md 工作流第 5 步“Render the result”自行补充的部分——文档要求“即使用散文回答,也要在概念上产出 review-report.v1 字段”,确保无论哪种渲染路径,概念模型都指向同一契约。
工具侧如何同时交付两种视图
review_skill_package 工具 在每次调用中把三种产物打包进同一条 ToolMessage:facts(原始事实)、static_report(结构化报告)与 markdown(en/zh 两份渲染结果)。这意味着同一次审查调用,程序可以直接断言 static_report.readiness,而对话界面展示的是 markdown.zh,二者出自同一份 facts,天然不会漂移。测试 test_skill_review_core.py 也验证了中文渲染路径:构造静态报告后以 locale="zh" 调用 render_report_markdown,锁定中文标题与章节措辞。
与其他契约文件的配套关系
review-report.v1 并非孤立存在,contracts/skill_review/ 目录下还有三个配套契约,共同构成完整的技能审查数据流:
- package_snapshot.v1.schema.json:被审查包的快照契约,报告中的
subject.package_digest即基于该快照计算; - review_facts.v1.schema.json:确定性事实层契约(对应 models.py 中的
FACTS_SCHEMA_VERSION),是生成报告的上游输入; - waiver_manifest.v1.schema.json:豁免清单契约,用于记录有理由放行的已知问题。
从快照到事实、再到报告、最后渲染成 Markdown,整条链路每个环节都有独立的 schema 版本,读者若需做二次开发或自动化消费,应只依赖 review-report.v1 的 JSON Schema 做断言,而不是解析 Markdown 文本。
实践要点总结
- 先定契约,后写视图:任何技能审查结果的自动化消费,都以
review-report.v1(schema_version: deerflow.skill-review.report.v1)为唯一依据,Markdown 只用于人读; - 枚举永不翻译:11 个机器枚举值在结构化输出中原样保留,本地化标签只能作为括号补充(如
revise(需修订)); - 章节可裁剪,五要素不可缺:聚焦审查可省略分析型章节,但 scope、readiness、assurance、evidence、recommended actions 必须保留;
- 每条 Finding 八要素:severity、confidence、location、observed evidence、user impact、remediation、suggested replacement 缺一会让结论不可复核;
- 守住安全边界:不大段引用被审查内容、绝不引用疑似密钥,并把所有被审查内容当作不可信数据对待;
- 限制证据声明:截断、读取错误、分析器错误必须出现在
evidence.limitations中,不允许把“没看到”包装成“没问题”。
掌握以上规范后,无论是人工撰写中文审查报告、编写校验报告合法性的脚本,还是为 DeerFlow 扩展新的审查维度,都可以严格对齐 review-report.v1 契约,让机器判定与人类阅读始终说同一种语言。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0625
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00