## 第一阶段 · 搭骨架 ### 步骤 | 小步 | 做什么 | 产出 | | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------- | | **1.0 计划 (understanding)** | **先想清楚再动手**:通读原文(含配图),把这篇拆成一份**工序计划**:(a) 有**几条独立做法**(几个工序);(b) 每个工序的**步骤序列逐条展开**(每步:用什么工具·对什么输入·做什么动作·得什么输出,**别压成单步**,详细度见 §1.1);(c) 每个工序**覆盖原文哪些 `0N` 章节**(原文每个章节都要被某个工序认领,别整段漏抽)。**Cyber 引擎**:调用一次 `plan_procedures` 工具把这份计划交上去——它校验完整性(有章节没认领→报错让你补;工序单步→警告),通过后**自动据计划生成 workflow.json 骨架**。**其他引擎**:把这份计划写进 `understanding.md`,再据它建骨架。 | 工序计划 + `workflow.json`(骨架版,结构按计划锁定) | | **1.1 填骨架** | **在已生成的骨架上填内容**(别增删工序/步骤、别 write_file 重写整个 workflow.json):逐步用 `wf-patch.py` 填每个输入/输出的 `value`(文字类用 `@quote` 拽**完整逐字**原文;**提示词建成 `type=提示词` 的 IO value,别塞 `directive`**,见下)。结构已按计划定死,你只补血肉。 | `workflow.json`(填好 value) | | **1.3 连数据流** | **把数据流连起来** —— 给每个输入输出补上"来源/去处":输入写 `← 上游某输出的编号`(如 `← s2o1`)、`← 工序输入`、`← 某编号[i]`(循环里逐个取);输出写 `→ sN`、`→ 某列表.追加`。连完自查:每个输入引用的编号都能在前面找到对应输出。连错就回改。几十处要连时用 `wf-patch.py` 一次过(见下),别写脚本硬塞。 | `workflow.json`(补好"来源/去处") | | **1.4 IO 校验(强制)** | 填完后、进 Phase 2 前,**必须跑 `python spec/tools/verify-io.py --workflow --source input/case-N.json --ocr `**:它逐项校验 ①每个**文本类** input/output 的 `value`、②每个**生成步**的 `directive`(提示词)是否在原文里**逐字且完整**(媒体类 IO 不要求对应;directive 改写/截断都会被点名)、③每个工序的 `declarations`(inputs/resources/returns)是否补全。报 ✗ 就回去修(**此时可重新读原文**;提示词用 `@quote` 把整段**提全**,别缩写/只取第一层),修完重跑直到通过。 | `workflow.json`(文本 value/提示词逐字完整、declarations 补全) | --- ## workflow.json 整体结构 一个 `workflow.json` 描述一篇案例,里面可以有一个或多个工序(比如一篇文章同时讲了"简单做法"和"进阶做法",那就是两个工序)。 ``` { "source": 原帖信息, # 平台/作者/日期/标题/摘要;正文和配图由 --source-input 自动补 "procedures": [ 一个或多个工序 ] # 只有一个工序时也用长度为 1 的数组 } # page_title 不写进文件,由第三阶段 --page-title 命令传入 ``` 每个**工序**长这样: ``` { "id": "p1", "name": 工序名字, "purpose": 一句话说明这个工序在做什么, "category": 类别(产物创造 / 资产建设 / 自动化 / 分析 / 学习), "platform": 平台, "author": 作者, "declarations": 这个工序需要哪些外部输入和长期资源,最后返回什么, "type_registry": 这个工序自己造的类型词(没有可不写),第二阶段归类时填, "steps": [ 一步步的操作 ], "return_row": 表格最后一行,写明最终交付什么(可不写) } ``` --- ## 第一阶段要填的字段 每个工序填:`id` / `name` / `purpose` / `category` / `platform` / `author` / `declarations` / `steps`。 ### 步骤级字段 | 字段 | 什么意思 | 怎么填 | 别这样 | | ----------- | ------------- | ---------------------------------------------------------------------------- | ------------------------- | | `id` | 第几步 | `s1`、`s2`;控制块子步用点号 `s6.1` | — | | `kind` | 步骤类型 | 普通步写 `step`;控制块用 `block` / `nested`(见下) | — | | `via` | 用了哪个具体工具/产品 | 写工具标准名:`manus`、`nano_banana_pro`、`human`(人工);原文没点名就括号占位 `(AI 生图工具)`;控制块写 `-` | 写一句话描述(那是 `directive` 的活) | | `directive` | 给工具的**元指令**(不是提示词本身)| 只放"怎么用工具"的简短指示,如"严格反推,别发挥"、"比例 2:3"、"保持主角一致";多数生图步**留空**即可 | **别把提示词原文塞这里**——提示词是**数据**,归 `type=提示词` 的输入/输出 `value`(见下) | ### 输入 / 输出的字段 | 字段 | 什么意思 | 怎么填 | 别这样 | | ---------- | ------------------- | --------------------------------------------------------------------------- | ------------------------- | | `type` | 这份数据是什么角色(参考图?提示词?) | **Phase 1 起个描述性标签即可**(如 `复刻图片`、`视觉风格分析`),不必查词表、不校验;**对到标准叶子 / `type_registry` 挂靠是 Phase 2 归类**时做(那时才读 type.json) | Phase 1 就去查类型词表、注册 type_registry(那是 Phase 2 的活)| | `value` | 数据内容本身 | **文字类(提示词/JSON/报告/文案…)→ 填原文里那段的【完整逐字内容】**:整段 prompt、整段 JSON 都要**原样搬全**,别缩写/概括/截断/凭记忆改写。**推荐用 `@quote\|<起锚>\|<止锚>`(或 `@quote\|<关键词>` 落 JSON 块)标记 + `wf-patch --resolve-quotes` 让工具把那整段从原文/OCR 逐字回填**——长内容你只写两个短锚点,不用手抄。图片/视频用尖括号写**具体**描述 `<一张穿冲锋衣的登山者暴雨场景图>` | 把整段 prompt/JSON **缩成一句概括**;写"见上一步"引用;写"参考图"这种笼统空壳 | | `anchor` | 来源 / 去处 | 输入写来源:`← 工序输入`、`← s2o1`、`← s2o1[i]`(循环逐个取);输出写去处:`→ s7`、`→ 某列表.追加`、`→ 返回 X` | 在这里描述内容(那是 `value` 的活) | | `id`(输出专属) | 输出的编号 | 工序内唯一,如 `s2o1`;只有一个输出时 `s2` 也行 | 重复编号 | > 🔑 **提示词是数据,不是指令——建成 `type=提示词` 的 IO**(这是最容易建错的地方)。标准范式(对齐参考实现): > - 一个 `human`「写提示词」步:输入 `type=描述`(用户的需求阐述)→ 输出 **`type=提示词`**,`value` = 原文那段**整段、逐字、完整**的 prompt(所有分层/要素都要:主题+核心要素+输出要求,或视觉层+技术层+氛围层…别只取第一段)。 > - 下游生成步(`via=nano_banana` 等):输入 **`type=提示词`**(`anchor: ← 上游那个提示词输出`,`value` 同样填整段)→ 输出 `type=样图/成品图`。 > - **`directive` 留空**(提示词不在这里)。原文没给详细 prompt 的步(如"生成符合调性的背景图"只一句),才在 `value` 写那一句或标 `inferred`。 > - 第三阶段 `verify-io.py` 会检查:生成步**必须有 `type=提示词` 输入**、`directive` 里**不准**装提示词原文、提示词 `value` 不准截断——建错会被打回。 > ⚠ **值一定要写真实内容**:哪怕某个输入就是上一步输出原样传过来的,"值"里也要把内容**完整抄一遍**,不能写"(同上)""见 s2o1"。嫌麻烦的话:只在源头填一次真内容,其余地方把"来源"写对,然后跑一次 `wf-patch.py --resolve-passthrough`,它会顺着编号自动把内容抄过去。 **输入不用编号**——没人会反过来引用一个输入。 ### 命名约定 - 类型名用**中文**;工具品牌名用**英文标准写法**(`seedream_4_5`,不要写成 `ByteDance-Seedream-4.5`)。 - 每个输出都要有编号(工序内不重复),供后续步骤按编号引用。 - 自造的类型要挂靠:在工序的 `type_registry` 里写明它"算作"哪个标准词 + 一句说明,例如 `"主角图": {"extends": "参考图", "desc": "本案例的女主肖像"}`。 --- ### 1.1 怎么判断"有几个工序" ⚠ 跟原文的章节标题无关:不管原文把某段叫"案例示范"还是"进阶玩法",只要满足下面三条,就算一条独立工序。**判断的单位是"一条完整的 输入→最终产物 链",不是原文的段落结构。** **怎么扫**:以原文里**每一张出现的成品图**(或明确写出的最终产物)为起点,逐个看它有没有对应的"输入→做法"链条。有就记为一个候选工序,再用下面三条筛。**别按段落扫。** > 🔒 **扫完做一次「章节覆盖」交叉核对**(结构强制,防整段漏抽):原文常按 `01 | … 02 | … 03 |` 分章。逐章节过一遍,确认**每个章节的核心内容都落进了某个工序或它的某个步骤**。"按成品图扫"最容易漏掉**没有独立成品图的方法论/框架章节**(如"结构化 Prompt 框架""更多案例欣赏")——这种章节本身就是一条工序(讲一套做法)或要拆成多个子步骤,**不能因为它没配一张独立成品图就跳过**。核对结论简记成"章节 0N → 工序 pX / 步骤 sY"对照;有章节对不上任何工序,回去补。**Phase 3 `lint-case.py --source` 会按章节覆盖率把漏抽的章节抓出来**,到时还得回这一步补,不如一次做全。 1. 有明确产物:这条链能产出一个看得见的结果(图、素材、成品)。 2. 有具体做法:链条里有可操作的方法(提示词、框架、流程)。 3. 产物或做法有差异:跟别的工序比,产物不同 **或** 做法不同,满足一条即可。哪怕产物类型一样(都是场景图),只要提示词不同,就算两个工序,**不能合并**。 边界判断: - 同一条链内部的中间步骤,归进这条工序,不单拆(比如做海报时先生成背景图,背景图是中间步骤,不是独立工序)。 - 只展示了成品、完全没讲输入和做法的,不算工序。 - 产物类似但做法不同 → 算两个工序。**不能**因为"产物类型相同""方法论相似"就合并。 ### 1.1 计划(understanding)要想清楚到什么程度——这就是你交给 `plan_procedures` 的内容 下面这些就是 §1.0 那份"计划"的全部内容——**它直接决定 workflow.json 切几个工序、每工序几步**。想得越细,workflow 步骤越完整,**别压成单步**。**核心是第 3、4、6 条**(多工序判断 + 每工序逐步展开 + 章节认领),它们一对一变成 `plan_procedures` 的 `procedures[]`(每工序的 `steps[]` 四要素、`source_sections`)。Cyber 引擎把它作为工具参数交上去;其他引擎写进 `understanding.md`: 1. **原文信息**:标题 / 来源平台 / 作者 / 发布时间。 2. **内容概述**:2-4 句说清这篇在教什么、分几大板块(→ 工具的 `summary`)。 3. **多工序判断**:以每个成品图 / 最终产物为起点列一张扫描表(产物 | 有无独立做法 | 有无完整 输入→输出 链 | 判断),最后给"共 N 个工序"的结论。 4. **每个工序一节**,每节都要有: - **终态产物**:这个工序最后交付什么(→ `final_product`)。 - **工艺类型**:产物创造 / 资产建设 / 自动化 / 分析 / 学习(→ `category`)。 - **步骤逐条展开**:不要只写"4 步",要把每一步**列出来**,每步讲清「用什么工具 · 对什么输入 · 做什么动作 · 得到什么输出」(→ 每个 step 的 `tool/input/does/output` 四要素,input/output 写**短标签**会变成步骤的输入/输出 type;`does` 只是自由描述、**不是** taxonomy 动作词);有循环 / 并行的,点明"对每个 X 重复""同时跑 N 路"。 - **关键工具**:这个工序用到的具体工具 / 产品名。 - **隐含工艺规约**:原文没明说但工艺上必然存在的前置 / 约定(如"生成要带参考图""多模型并行降随机性")——这是第二阶段补 `inferred` 输入的依据。 5. **关键发现**:3-5 条这篇最值得记的方法论 / 工具选型 / 工序结构洞察。 6. **章节认领**:原文每个 `0N` 章节,判断它归哪个工序(独立做法→单独工序;纯展示/补充→并进相邻工序)——**每个章节都要被某工序的 `source_sections` 认领**,这是工具卡"整段漏抽"的依据。最易漏:**没有独立成品图的方法论/框架章节**(如"结构化 Prompt 框架""更多案例"),它们也是工序,别因为没配成品图就跳过。 > **颗粒度对照**:一步要写成"用豆包对〔题材思路〕生成〔剧本大纲+分集剧情+台词〕"这种程度(工具+输入+动作+输出俱全),而不是"写剧本"这种一个词。多步时各步侧重不同,别都写成一个模子。 ### 1.2 哪些"没写出来"的要主动补 真实教程经常会省略一些理所当然的中间产物。比如某步要"自己写动作序列",原文没提它得先有一张主角图当参考——但工艺上这张图必不可少。这种**该有却没写出来**的输入/输出,要主动补上并标注推断原因;某个字段实在判断不出就留空,**不要硬编一个假的**。 原文常省略的几类: - **工具常识**:生成模型一般要带模型/参数;召回要有检索依据;视频生成要有主角图/分镜图当参考。 - **前后对不上**:下游用到了 X 但上游没产出 X → 是不是漏抽了?某个输出后面没人用 → 是不是漏了使用它的步骤? - **工艺常识**:短剧 = 分镜图 → 视频片段 → 拼接;建素材库 = 收集 + 入库 + 建索引。 补出来的输入输出标上 `inferred: true` 和原因(让后面复核),别悄悄塞进去: ```json { "type": "参考图", "value": "<一张主角肖像>", "anchor": "← s2o1", "inferred": true, "inferred_reason": "原文只说'自己写动作',没提主角图;但写动作序列需要它当角色参考" } ``` - ✅ **该补**:工艺上必然需要的中间产物;原文用了复数("这些素材库")但只列了一个,把其余补全。 - ❌ **不用补**:归一化分类(那是第二阶段的常规活);只是把原文换个说法;原文细节确实没写全(那是信息缺失,不算"推断")。 - ⚠ 推断标记只能加在**步骤的输入/输出**上,不要加在工序的 `declarations` 上(那里只收 `type`/`name`/`desc` 三个字段)。 ### 1.2 有循环/并行/分支怎么切 原文里如果有"对每个 X 重复""同时做几个版本""分情况",切步骤时要展开成**控制块 + 子步**,别硬压成一个步骤: - **块本身**(`"kind": "block"`):`via` 写 `-`,块的输入输出表达"整个循环在做什么"。 - **块里的每一步**(`"kind": "nested"`,并写上 `"group": "块的编号"`):编号带点号(块是 `s5`,子步就是 `s5.1`),表达"每一次具体怎么做"。 ```json { "id":"s5", "kind":"block", "via":"-", "inputs": [{"type":"分镜脚本","value":"...","anchor":"← s4o1"}], "outputs":[{"id":"s5o1","type":"分镜图列表","value":"...","anchor":"→ s6"}] } { "id":"s5.1", "kind":"nested", "group":"s5", "via":"nano_banana", "directive":"按场景提示词生成,保持主角一致", "inputs": [{"type":"提示词","value":"...","anchor":"← s4o1[i]"}, {"type":"参考图","value":"...","anchor":"← s5o1[-1]"}], "outputs":[{"id":"s5.1o1","type":"分镜图","value":"...","anchor":"→ 分镜图列表.追加"}] } ``` - **循环里取数据**:来源写 `← s4o1[i]`(逐个取)、`← s5o1[-1]`(取上一次的产出,做"接力"参考)。 - **往列表里攒结果**:去处写 `→ 分镜图列表.追加`。 - **一步产出好几样东西**:就写好几个输出(每个都有自己的编号),别合并成一个。 - 抽样、重试这类小修饰,直接写进 `directive` 里说明即可。 ### 1.3 连数据流时自查这几条 - 每个输入的"来源"(`← 某编号`)都能找到已存在的输出编号,或是 `← 工序输入`、字面量。 - 输入的类型,和它"来源"指向的那个输出的类型一致。 - 循环索引用在合理位置(`[i]` 在循环里,`[-1]` 指最近一项)。 - 接力/链式引用关系正确。 - **逐个输入/输出按模态查 value**:文本类(提示词/数据/报告,或 `type_registry` 挂靠到它们的 case 类型)必须填**从原文匹配到的【完整逐字内容】**——整段 prompt / 整段 JSON 都要原样搬全,**别概括、别截断、别只填一句**(用 `@quote|<起锚>|<止锚>` 框出整段 + `wf-patch --resolve-quotes` 让工具从原文/OCR 逐字回填,长内容你只写两个短锚点);原文确实没有 → value 写成 `<占位>(原文未提供)`(或标 `inferred: true` + 原因);媒体类(图/视频/音频)用 `<具体描述>`。 - 🔒 **值强制(防"开头逐字后就缩写")**:一段真·逐字 value 应该是原文里**一整段连续文本**。最常见的偷懒是**抄了开头第一句、后面用原文小标题拼盘**——比如原文提示词是「主题:…登山者…。人物:一名年轻的登山者,表情坚毅…。产品:…水珠滚落…压胶细节…。环境:…乌云密布…」整整 ~350 字,却写成「主题:…登山者…。核心要素:人物、产品、环境、视觉风格」。后半「人物、产品、环境…」这些词单看都在原文里,但**连起来不是任何一段原文**——逐字细节全丢了。这种**必须用 `@quote|主题|<止锚>` 把整段拽进来**。**Phase 3 `lint-case.py --source` 会算"最长连续命中原文"比例,<80% 判缩写并报出**,到时还得回来用 @quote 重填。 - ⚠️ **第三阶段 `render-case.py` 对文本类 `<占位>` value 会直接拒绝出 HTML**——必须回填真内容、或标「原文未提供」/inferred 才放行(媒体描述不受限)。 ### 1.3 怎么批量连(重要) `workflow.json` 由你**直接演化,绝不写 Python 脚本去生成/批改它**(脚本拼 JSON 容易踩转义坑、把文件弄坏)。几十处"来源/去处"用 `wf-patch.py` 一次搞定: 1. 把要改的清单写到 `_scratch/anchors.json` —— `[{"path":"p1.s1.inputs[0].anchor","value":"← s0o1"}, ...]`,**每条都是你的判断**(连到哪个编号是语义决定,不是机械套用); 2. 跑 `python spec/tools/wf-patch.py --workflow workflow.json --patch _scratch/anchors.json`。 工具负责安全写 JSON + 检查格式(有一条不合法就整批不写),你从不直接碰 JSON 文本。零星单处改,用 Edit 就行。路径写法见 [tools.md](../tools.md)。 ### 1.3 内容自动抄写 "来源"连好后,跑一次 `python spec/tools/wf-patch.py --workflow workflow.json --resolve-passthrough`。对那些"原样接收上游输出"的输入(来源是 `← 某编号`),你**不用手抄上游内容**——只在源头那个输出里填一次真内容,工具会顺着编号把它逐字抄到所有引用处("值"先留空即可)。**别把"(同上)"这种引用当最终内容留着**(检查会报)。 ### 输出格式要求 > **Cyber 引擎**:骨架由 `plan_procedures` 工具**自动生成**,你不用手建——工具按你的计划把 procedures/steps(含 id、via、输入/输出 type 标签)都搭好了,你只在它上面用 `wf-patch.py` 填 `value`/`directive`/`anchor`。下面模板只是让你看清生成出来的结构长什么样。 **其他引擎(无 plan 工具时)用 `wf-patch.py --create` 建骨架**:把下面模板里要填的字段写成扁平 `[{"path":...,"value":...}]` 清单(如 `p1.s1.inputs[0].type` / `p1.s1.outputs[0].anchor`),一条 `--create --patch` 命令拼成合法 JSON(缺的 procedure/step/IO 自动建、output 的 id 自动补;见 tools.md §1)——**扁平清单好写、不会漏逗号崩 JSON**。下面模板供参考结构,也可直接复制 Write(但手写长嵌套 JSON 易出错)。 ```json { "source": { "platform": "<填:原文平台 e.g. wechat-gzh>", "author": "<填:原文作者>", "date": "<填:发布日期 e.g. 2026 上半年>", "url": "<填:原文 URL>", "title": "<填:原文标题>", "excerpt": "<填:摘要 1-3 句>" }, "procedures": [ { "id": "p1", "name": "<填:工序名 e.g. 产品场景图生成>", "purpose": "<填:一句话目的>", "category": "<填:产物创造|资产建设|自动化|分析|学习>", "platform": "<填:平台>", "author": "<填:作者>", "declarations": { "inputs": [{ "type": "<填:类型>", "name": "<填:声明名>", "desc": "<填:说明 (可选)>" }], "resources": [], "returns": { "type": "<填:返回类型>" } }, "steps": [ { "id": "s1", "kind": "step", "via": "<填:工具名 e.g. human / nano_banana / (AI 生图工具)>", "directive": "<填:给工具的 prompt 文本 (可选;人工/控制流步留空)>", "inputs": [ { "type": "<填:类型>", "value": "<填:数据内容本身>", "anchor": "<填:← 工序输入 / ← s1o1>" } ], "outputs": [ { "id": "s1o1", "type": "<填:类型>", "value": "<填:数据内容本身>", "anchor": "<填:→ s2 / → 返回 X>" } ] } ] } ] } ``` 有循环 / 并行 / 分支时,用控制块写法(无则不需要): ```json { "id": "s1", "kind": "block", "via": "-", "inputs": [{ "type": "<填:类型>", "value": "<填>", "anchor": "<填:← 上游 id>" }], "outputs": [{ "id": "s1o1", "type": "<填:类型>", "value": "<填:累积结果>", "anchor": "<填:→ sN>" }] }, { "id": "s1.1", "kind": "nested", "group": "s1", "via": "<填:工具名>", "directive": "<填:给工具的 prompt (可选)>", "inputs": [{ "type": "<填:类型>", "value": "<填>", "anchor": "<填:← 被遍历序列 id[i]>" }], "outputs": [{ "id": "s1.1o1", "type": "<填:类型>", "value": "<填:单次产出>", "anchor": "<填:→ 累积结果.追加>" }] } ```