Output Spec Judge · 输出规格裁定(量级 L1–L5 × 载体 C1–C3)
定位
这是一把量「输出规模与形态」的尺子。
服务对象是 Agent。Agent 在动手产出之前,先定下三件事:
| 该定的 | 具体是 |
|---|---|
| 输出形式 | 一句答复?一张清单?一张对照表?一篇专项成文?一份完整方案? |
| 篇幅 | 多长?几个一级章节?多少内容块? |
| 内容量 | 覆盖多宽?涉及几个专业视角、几个内容域? |
本 Skill 回答这三件事,并固化成一份可执行的 输出规格(output_spec),Agent 直接照着写即可。
判断对象:输出结果本身的规模与形态。
职责边界:不估工作量、不排工期、不排日程、不分配人力、不评估现实中的成本与风险体量。
适用 Agent 类型与触发条件(普适)
本 Skill 与 Agent 的职能类型无关。任何类型的 Agent,只要下一步产出物的规模与形态未定,就应先走本 Skill:
| Agent 类型 | 典型触发 | 判定对象示例(L / C) |
|---|---|---|
| 编程助手 | 写代码 / 改代码 / 评审代码 | 内联修复(L1·inline)→ 评审意见清单(L2)→ 技术方案文档(L4·single_file)→ 重构方案 + 代码 + 迁移说明(L5·multi_artifact) |
| 研究分析 | 调研结论、分析报告 | 一句话结论(L1)→ 要点速览(L2)→ 对比明细表(L3)→ 专项研究报告(L4)→ 报告 + 数据表 + 汇报件(L5) |
| 任务执行 | 执行计划、操作手册、结果报告 | 步骤答复(L1)→ 检查清单(L2)→ 参数核对表(L3)→ 实施方案(L4)→ 多产物执行包(L5) |
| 文案 / 内容创作 | 版本明确的内容产出 | 标题短句(L1)→ 文案要点(L2)→ 结构化文案稿(L3)→ 单篇成稿(L4)→ 内容矩阵(L5) |
| 编排 / 多 Agent 协作 | 上游(编排器 / 工单 / 上游 skill)交来结构化需求 | 按 structured_requirement 判定,来源不限 |
触发口诀:拿到需求后、动手产出前,问一句「该给多大规模、什么形态?」——答不了或要靠猜,就调本 Skill。
不触发:需求已显式指定交付规格(「只要一句话」「给我完整方案」「直接给代码」)时跳过判定,尊重显式规格,并在产出中按该规格执行。
两级判定模型(别混)
| 轴 | 判什么 | 取值 | 依据 |
|---|---|---|---|
| 量级 L1–L5 | 写多长、分几节 | 单点答复 / 要点清单 / 结构化明细 / 专项方案 / 完整方案 | 内容量当量主轴 + 视角/章节升档触发器 |
| 载体 C1–C3 | 落几个产物、落在哪 | 对话内直答 / 单文件交付 / 多产物交付 | 独立轴,可显式指定或按量级默认 |
两轴独立:L4 可以是单文件,也可以是(经确认的)多产物;L5 默认多产物但也可单文件成文。载体不参与量级判定。
档位定义、判据、适用范围、非适用场景的完整说明见 references/output_scale_tiers.md。
触发场景
- Agent 收到需求,需要在动手写之前确定交付规格(量级 / 载体 / 篇幅 / 内容量)
- 判断该需求应输出「对话内直答」还是「成文方案」,以决定是否落盘、落几个文件
- 需要一份可审计的输出提纲:先讲哪块、每块占多少篇幅、要覆盖哪些内容域与视角
输入契约
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
structured_requirement |
dict | 是 | 上游结构化需求,来源不限(用户消息解析、上游 skill、编排器、工单系统、issue 均可),只要字段语义完整;原样回显到输出的 requirement |
output_name |
str | 否 | 该输出的名称,用于输出命名与(可选)结构图标题/文件名 |
artifact_form |
str | 否 | 交付载体:inline / single_file / multi_artifact。缺省按量级默认推断。别名:chat/answer→inline,file/single→single_file,multi/package/bundle→multi_artifact |
output_rules |
dict | 否 | 输出规模阈值,缺省用 DEFAULT_RULES(见下) |
render_outline |
bool | 否 | 是否生成输出结构图 HTML(可选产物,默认 false)。等价于 CLI 的 --emit-outline-html,且仍需同时提供 --output-dir 才会落盘 |
force_level |
str/int | 否 | 显式指定量级:"L1"–"L5",也接受 l4 / 4 / " l4 " / "level4" / "lv4"。非法值四段式报错,不猜、不回落 |
force_form |
str | 否 | 显式指定载体:inline / single_file / multi_artifact,别名同 artifact_form。优先于 artifact_form |
force_reason |
str | 否 | 显式指定的理由,仅回显进输出,不参与判定 |
显式指定(备选方案)的边界——三条硬口径:
| 口径 | 说明 |
|---|---|
| 只覆盖结果,不跳过判定 | force_level 只决定最终量级;主轴判定、升档触发器、特征校验照常全跑。指定值与规则判定不一致时,两方都写进 notes |
| 偏差必报警,绝不静默 | 指定值与规则判定不符 → notes 出 ⚠ 提示(含"量级偏大易注水 / 偏小易覆盖不全");指定量级与内容量当量差距悬殊 → 追加 ⚠ 提示。同时输出 forced 块记录 level_by_rules 与 overridden |
| 不支持强制内容块数量 | 内容块由 Step 1 的 MECE 穷举决定,不能靠指定数字绕过——那会让判定退化成"照抄输入"。force_level 只能改档位,不能改内容块清单 |
> level 是泛词,刻意不做同义映射。 只有 forcelevel / forceform 这类收窄写法会被归一为 force_level / force_form;裸写 "level": "L4" 不会被当成显式指定(仍按规则判定),避免误吞无关字段而静默改变量级——红线:宁可报错,不可猜错。
output_rules 可选键:
| 键 | 默认 | 含义 |
|---|---|---|
l1_max_weight |
4 | 当量低于此 → L1 |
l2_max_weight |
10 | 高于 l1_max_weight 且低于此 → L2 |
l3_max_weight |
20 | 高于 l2_max_weight 且低于此 → L3 |
l4_max_weight |
45 | 高于 l3_max_weight 且低于此 → L4;再高 → L5 |
l4_min_perspectives |
3 | 覆盖视角 > 此 → 量级 ≥ L4 |
l5_min_perspectives |
5 | 覆盖视角 > 此 → 量级 ≥ L5 |
l4_min_sections |
5 | 覆盖章节 > 此 → 量级 ≥ L4 |
l5_min_sections |
7 | 覆盖章节 > 此 → 量级 ≥ L5 |
边界必须严格递增,否则脚本直接报错——档位出现空洞或重叠会静默错判,比报错危险。此校验刻意保持严格,不提供任何自动纠正。
输入容错(不必严格照标准格式写)
引擎对输入做分层容错:能归一的不报错,猜不出的必报错,每一处自动改动都写进 notes。
| 容错层级 | 处理内容 | 是否写 notes |
|---|---|---|
| JSON 预清洗 | BOM / 零宽字符 / // 与 /* */ 注释 / 尾逗号 / 全角标点 / 单引号(仅当原文无双引号时) |
写 stderr 的 [INFO] 行 |
| 键名归一 | 大小写、首尾空格、-/./空格、驼峰 → snake_case;同义表(contentWeight→content_weight、role→perspective、stage→section、content-weight→content_weight 等) |
是(「已自动归一…」) |
| 值域归一 | output_name/goal/artifact_form/dimension/section 的首尾空白与全角空格清理;载体别名映射 |
是 |
| 形态归一 | depends_on 传单个字符串 → 自动转列表 |
是 |
| 内容域模糊纠正 | dimension 与标准内容域相似度 ≥ 0.8 且唯一命中 → 自动纠正 |
是(「已自动纠正内容域…」) |
| 非标准域兜底 | 纠正不了的非标准 dimension → 归入兜底域/章节,不报错 |
是(⚠ 提示) |
| 未知字段提示 | 多余的顶层字段 → 忽略但提示 | 是(⚠ 提示) |
必须明确报错、绝不猜测的情况(猜错会直接改变判定结果):
| 情况 | 为什么不能猜 |
|---|---|
subtasks 缺失或为空 |
无法判定量级 |
content_weight 缺失或非数值 |
它是量级判定的主轴,猜 0 会让整份交付规模偏小 |
id 缺失或重复 |
它是依赖图的锚点 |
depends_on 指向未知 id |
静默丢依赖会错排行文顺序,且掩盖真实的顺序环 |
title / perspective 缺失 |
无法确定该块讲什么、覆盖谁 |
output_rules 边界非严格递增 |
档位空洞/重叠 → 静默错判 |
| 清洗全部尝试后仍非法 JSON | 已尽力,必须交回人工 |
报错格式为四段式:位置(行/列 + 上下文 + ^ 指位)、期望、实际、修正(可直接复制的示例)。
--strict / strict=True:关闭全部容错(含键名归一与模糊纠错),任一偏差直接走四段式报错。供上游是严谨系统、需要暴露任何字段偏差时使用。唯一例外:值域首尾空白清理(纯字符层,无语义歧义)在 strict 下仍执行。
执行步骤
Step 1 · 穷举输出内容块(MECE)
读取 structured_requirement,从八个互不重叠、完全穷尽、与行业领域无关的通用内容域穷举该输出应覆盖的内容块:
背景与目标 / 现状与依据 / 方案与路径 / 资源与成本 / 风险与合规 / 执行与协作 / 度量与迭代 / 结论与建议。内容块的子轴与视角池见 references/dimension_taxonomy.md。
行业专属名词(岗位名、流程名、平台名)只进 title,不进 dimension——内容域本身不预设任何赛道。
要求:
- 每块只归一个内容域(跨域则拆两块)
- 标注 id、title、dimension、perspective(该块需覆盖的专业/读者视角,非人名)、content_weight(内容量当量)、depends_on、section(可选,所属输出章节)
> content_weight 的经验锚点见 references/output_scale_tiers.md 第七节,标完建议回做一次同档自检。
Step 2 · 排列章节展开顺序
为每块标注 depends_on(必须先讲哪块,这块才讲得通)。这是输出的行文顺序,不是执行先后。
确保顺序图无环(脚本会校验,有环直接报错)。
Step 3 · 判定量级(L1–L5)
汇总内容块数与内容量当量,结合覆盖视角数、覆盖章节数判定:
1. 主轴:内容量当量总量落在哪个区间,就先落哪档
2. 升档触发器:覆盖视角 / 覆盖章节各自命中门槛,把量级下限顶高
3. 最终量级 = max(主轴档位, 触发器档位)
4. 特征校验:核对该量级的内容块特征(见 output_scale_tiers.md 第三节)是否吻合;数字与特征冲突时以特征为准,并把冲突原因写进 notes
5. 显式指定覆盖(若给了 force_level):最终量级改用指定值,但第 1–4 步全部照跑;指定值与规则判定不一致时,双方都写进 notes,并在输出 forced 块标记 overridden: true。特征校验在最终档位上跑——所以指定 L4 时会立刻收到"当量仅 4、成文可能空洞"的 ⚠ 提示,而不是被静默放过
命中同档上限以外的(视角/章节超出该档建议承载)不自动升档,而是在 notes 提示人工复核。
Step 4 · 判定载体(C1–C3)并确定交付层级
- 输入显式给了
artifact_form或force_form就用它(force_form优先);否则按量级默认:L1/L2 →inline,L3/L4 →single_file,L5 →multi_artifact - 载体与量级不匹配时必须报警(写入
notes),不静默吞掉 - 交付层级:L3 及以上给出「输出结构图」数据(章节序位 + 每块相对篇幅权重);L1/L2 输出按行文顺序排列的内容清单(checklist)
- 结构图 HTML 是按需渲染的可选产物,默认不生成。它只是
outline数据的可视化投影——只表达顺序/长度/内容域,不表达章节分组与depends_on,作为默认交付物是负价值。确需给人快速对齐结构时,显式加--emit-outline-html(须同时给--output-dir);未生成时notes会说明原因
Step 5 · 产出规格 JSON(引擎调用为可选项,算法本身与环境无关)
本 Skill 的判定算法(Step 1–4)是纯确定性规则,命令行引擎只是它的可执行实现之一,不是唯一入口:
- 有命令执行环境的 Agent(本地助手、带沙箱的运行时):组装 JSON 调引擎,保证可复现、可审计:
python scripts/plan_task.py --input plan.json --output-dir ./out
# 或:cat plan.json | python scripts/plan_task.py
# 需暴露任何字段偏差(关闭全部容错):加 --strict
# 需显式指定量级/载体:写进输入 JSON 的 force_level / force_form,**不提供 CLI 参数**
# —— 显式规格必须随输入文件一起留档才可追溯,临时命令行参数会绕过存档
- 无命令执行环境的 Agent(纯对话 Agent、托管平台内无 shell):严格按 Step 1–4 的同一算法手工执行——当量求和 → 查区间定主轴档 → 触发器取 max → 特征校验 → 载体推定 → 按下方输出格式组装 JSON。手工结果必须与引擎口径一致;拿不准的边界写进
notes,不静默。
单文件交付的具体文件格式由调用方环境与需求决定(Markdown 成文 / 表格 / 代码文件 / HTML 页面 / 演示件等),本 Skill 只裁定「落几个产物、各产物承载什么」,不绑定文件类型。
脚本完成校验、量级判定、载体推定、章节顺序排布、结构图/清单生成,并打印最终 JSON 到 stdout。
结构图 HTML 默认不落盘;仅当显式传 --emit-outline-html --output-dir <目录>(或输入 "render_outline": true)时,才额外写出 <name>_outline.html。
输出格式(JSON)
{
"output_name": "…(输出的名称,不是项目名)",
"goal": "…",
"requirement": { "...上游 structured_requirement 原样..." },
"level": "L4",
"level_name": "Focused Report",
"level_name_zh": "专项方案",
"classification": "Full Deliverable",
"classification_zh": "完整方案输出",
"classification_note": "deprecated:由 level 确定性投影而来,仅供旧下游平滑迁移,不代表独立判定",
"output_spec": {
"form": "专项方案(Focused Report)",
"format": {
"level": "L4",
"level_name": "专项方案",
"level_name_en": "Focused Report",
"band": "长",
"estimated_chars": "约 4,000–10,000 字(单域成文,分 4–7 节)",
"sections": 6,
"content_blocks": 11
},
"artifact_form": "single_file",
"artifact_form_zh": "单文件交付",
"artifact_plan": ["结构化报告(Markdown)", "(同文件内的)内容块明细清单"],
"coverage": {
"perspectives": 4,
"domains": 3,
"perspectives_list": ["…"],
"domains_list": ["背景与目标", "现状与依据", "方案与路径"],
"sections_list": ["…"]
},
"writing_guide": "单域成文:背景与结论先行 → 依据与数据 → 风险与边界 → 下一步动作;可含 1–2 张表。",
"must_cover": ["S1 …", "S2 …"]
},
"scale": {
"content_block_count": 11,
"total_content_weight": 28.0,
"distinct_perspectives": 4,
"distinct_sections": 6,
"perspectives_list": ["…"],
"sections_list": ["…"]
},
"rules_applied": { "l1_max_weight": 4, "l2_max_weight": 10, "l3_max_weight": 20, "l4_max_weight": 45,
"l4_min_perspectives": 3, "l5_min_perspectives": 5,
"l4_min_sections": 5, "l5_min_sections": 7 },
"forced": {
"force_level": "L4",
"force_form": null,
"level_by_rules": "L2",
"overridden": true,
"note": "显式指定仅覆盖量级/载体结果;判定与特征校验照跑,偏差见 notes"
},
"notes": [
"内容量当量 28 落在量级边界内 -> 主轴判定 L4(专项方案)",
"升档触发器命中(覆盖视角 4 > 3)-> 量级下限顶至 L4(专项方案),最终取 L4",
"载体按量级默认推断:L4 -> single_file(单文件交付)"
],
"subtasks": [
{ "id": "S1", "title": "…", "dimension": "背景与目标", "perspective": "决策与审批者",
"content_weight": 4.0, "depends_on": [], "section": "背景",
"start_slot": 1, "end_slot": 1, "slots": 1 }
],
"report": {
"level": "outline | checklist",
"outline": [ "…" ],
"total_slots": 17,
"outline_html_path": "(可选字段)./out/xxx_outline.html",
"checklist": [ "…" ],
"checklist_text": "[ ] S1 …"
}
}
字段口径速查(别混用)
| 字段 | 是什么 | 不是什么 |
|---|---|---|
level / level_name_zh |
权威量级档位 L1–L5 | 不是工作量分级 |
classification |
由 level 确定性投影的分类标签(L1/L2→Brief Output,L3–L5→Full Deliverable) |
不是独立判定,量级以 level 为准 |
artifact_form |
交付载体 C1–C3(落几个产物) | 不是量级 |
content_weight |
内容量当量:该内容块的信息量与撰写成本,仅用于横向比较内容量大小 | 不是工时、不是工期 |
perspective |
该内容块需覆盖的视角,视角越多输出越需要分层 | 不是执行人、不是岗位编制 |
section |
输出中的一级章节名 | 不是业务环节、不是流程节点 |
slots / start_slot / end_slot |
输出结构图上的相对篇幅刻度 | 不是天数,不含任何时间含义 |
report.level |
报告形态:outline(条目化提纲数据)/ checklist(清单) |
不是判定的量级档位,也不代表「有没有生成 HTML」 |
report.outline_html_path |
可选字段:仅显式要求渲染结构图时才出现 | 不是默认交付物 |
Resources
scripts/plan_task.py
确定性引擎:输入容错与校验(JSON 预清洗 / 键名归一 / 内容域模糊纠错 / 四段式报错)→ 规则校验 → 量级判定 → 载体推定 → 章节顺序排布 → 结构图/清单生成 → 输出 JSON。
结构图 HTML 按需渲染(--emit-outline-html),默认不落盘——它只是 outline 数据的可视化投影,且丢章节分组,不作为默认交付物。
--strict 关闭全部输入容错,任一偏差直接报错;预清洗生效时通过 stderr 的 [INFO] 行告知(stdout 始终只有 JSON,管道消费不受影响)。
所有「算」的事交给它,保证可复现、可审计;所有「想」的事(MECE 内容块穷举、视角与章节标注、特征校验)由 Agent 在调用前完成。
scripts/qa_tiers.py
回归测试脚本(40 个用例:15 个档位判定 + 14 类输入容错专项 + 11 类显式指定专项)。
覆盖 L1–L5 各档、升档触发器、载体冲突、字段名兼容、非法规则报错、档内超上限提示;输入容错(预清洗救回 / 必错项四段式报错 / 键名归一 / 模糊纠错 / --strict 行为);显式指定(force_level 各写法与大小写、与规则判定一致/不一致、force_form 及其别名、level 泛词不被吞、非法值四段式报错)。
改引擎或改档位后必须跑它:
python scripts/qa_tiers.py --skill <本skill目录> --profile master --label 母版
# 派生版 cross-border-output-spec-judge 用 --profile cbx,同一套断言
用例里的 dimension / perspective 写成槽位占位符 @D1/@P1,由 --profile 映射到各版内容域与视角池——因此同一套断言可跑母版与派生版,用于证明两者口径一致(双 profile 输出应逐行相同)。
两版 qa_tiers.py 须字节级一致,改完直接 cp 覆盖,勿分别手改。
⚠ 改 main() / CLI 参数后必须额外做 CLI 冒烟测试:
python scripts/plan_task.py --help # 确认无 argparse 参数冲突
echo '<一份最小 JSON>' | python scripts/plan_task.py # 确认 stdout 纯净可 json.load
原因:qa_tiers.py 用 importlib 加载模块后直接调 plan(),完全不经过 main()——CLI 层的参数冲突(如重复 add_argument)回归用例测不出来。(2026-09-28 实际踩过:--input 被重复添加,29 个用例全绿但 CLI 直接崩。)
references/output_scale_tiers.md
分档依据与适用范围的权威说明:分档结构总览、L1–L5 定义、硬闸 + 特征校验双判据、载体三档、各档适用/不适用场景、明确不适用范围、边界灰区处置原则、内容量当量锚点表。
references/dimension_taxonomy.md
通用八内容域子轴、视角池、章节全集、字段约定,供穷举时对照,确保内容域不重不漏、视角/章节统计口径一致。内容域与行业领域无关,领域专属名词只进 title。
与相邻 Skill 的分工(有则路由,无则自守边界)
下表所列相邻 Skill 若存在于当前运行环境则按表路由;不存在时,本 Skill 按同一边界自行拒判超范围请求,并在 notes 说明原因,不静默越界:
| 事项 | 归谁 |
|---|---|
| 输出该多大规模、什么形态、覆盖多宽 | 本 Skill |
| 谁去干、什么时候干、要几个人 | 不归本 Skill(现实执行排期,超出职责) |
| 需求本身够不够清楚、缺哪些字段 | 上游 requirement-analysis(如存在) |
| 把内容块路由给具体执行 Agent | task-dispatcher(如存在) |