README.md 12 KB

工序提取 SKILL · 总览

这道 skill 做一件事:读一篇 AI 创作教程/案例,把它背后的"做法"还原成一张工序表,存成 workflow.json,再渲染成一个网页

本文是总览。具体操作和字段规则在 extraction/ 子目录的三个阶段文件里,按阶段读即可。


本目录是一个自包含的 skill:跑提取流程时需要的所有说明都在这里。外部的案例原文(input/case-N-raw.json)和你产出的成果(outputs/case-N/)不算 skill 的一部分。

输入 / 输出

输入:任意一篇创作案例——公众号 / 小红书 / 推文 / 博客(正文 + 配图)、视频教程(带转写)、或你自己的工作复盘。

输出:一个网页 outputs/case-{N}/case-{N}-<slug>.html


概念速览

读懂这几条,就能看懂工序表在表达什么。

工序表把"一步操作"拆成几个层面(对应 workflow.json 里的字段):

层面 通俗讲 在 workflow.json 里
数据类型 这份数据算什么角色(参考图/提示词…) 输入输出的 type
用的工具 哪个具体产品(manus/nano_banana…) 步骤的 via
做的动作 干了什么(生成/反推…) 步骤的 action
工序位置 处在流水线哪个环节(预处理/主体生成…) 步骤的 effect
内容实质 这步本质上涉及什么(人物/场景/观念…) 步骤的 substance
呈现形式 内容怎么组织(光影/构图/叙事…) 步骤的 form
工序模板 一整套可复用的做法 一个 procedure
实际内容 这次具体填进去的真实值 输入输出的 value
目的 一句话概括这步在干嘛 步骤的 intent

一篇案例可以有多个工序:比如一篇文章同时讲"简单做法"和"进阶做法",那就是两个工序,放在顶层 procedures: [] 数组里(只有一个时也用长度 1 的数组)。

自造的类型要"挂靠":类型词表里没有的词,要在这个工序的 type_registry 里写明它"算作"哪个标准词,例如 主角图 挂靠 参考图。这样既能自由起名,又不弄乱标准词表。

命名约定:类型名、动作名用中文;工具品牌名用英文(nano_banana_pro);每个输出都要有不重复的编号(如 s2o1)供后面引用。其中"作用 / 实质 / 形式 / 动作 / 目的"是整步一个,"类型 / 值 / 来源 / 编号"是每个输入输出各一个

三个分类词表(作用/动作/类型 要对到它们):作用 = effect.json、动作 = action.json、类型 = type.json实质/形式 没有词表——读懂步骤后直接提炼,不查词表。


目录里有什么

操作流程(extraction/ —— 分三阶段,按阶段读)

文件 内容 什么时候读
extraction/phase1-skeleton.md 第一阶段:搭骨架(判断有几个工序 / 切步骤 / 连数据流);含第一阶段字段说明 第一阶段
extraction/phase2-normalize.md 第二阶段:归类标注 + 填目的列;含第二阶段字段说明 第二阶段
extraction/phase3-finalize.md 第三阶段:检查 + 渲染出网页 第三阶段

格式契约(format/)

文件 内容
case-data.schema.json 给机器看的字段清单(必填项/可选值的最终裁判)

分类词表(taxonomy/ —— 作用/动作/类型 三个受控词表)

文件 维度 规模 怎么用
effect.json 作用 9 个词 第二阶段读,把每步的作用对上
action.json 动作 30+ 个词 同上
type.json 类型 50 个词 同上;自造类型写进 workflow.jsontype_registry
type_suggestions.md 新类型登记 只增不改 第三阶段跑 lint-case.py工具自动登记,不用手写

实质/形式 没有词表:第二阶段直接提炼,不查词表。

工具(tools/)

tools.md 是各脚本(建骨架/批量改 wf-patch · 原文捞引 quote-source · 渲染 render-case · 检查 lint-case)的接口手册。脚本本身不用读源码,会用就行;渲染网页的样式(renderer.py/styles.css/script.js)也不用碰。


🛠 运行时约定(开工前必看)

通用(所有执行引擎)

  • workflow.json 全程用 wf-patch.py,绝不手写 / edit 改它(手写嵌套 JSON 易漏逗号崩、edit 在 p1/p2 重复结构上会撞「多个匹配」):
    • 建骨架:写一份扁平 patch([{"path":...,"value":...}]),proc/step 头 + 每个 step 的 inputs[i]/outputs[i] 的 type、value、anchor 都写进同一份,跑 wf-patch.py --patch <清单>——缺的 procedure/step/IO 默认自动建(upsert)、output 的 id 自动补、文件不存在也从空建。路径统一用 id 式 p1.s1.inputs[0].type(下标式 procedures[0].steps[0].inputs[0].type 工具也接受)。--set 别用单引号包参数(cmd.exe 不剥 → 路径会带 ';值含空格用双引号,或写进 --patch 文件)。
    • 填 / 改字段:wf-patch.py --set 'path=值'--patch <清单>。缺路径默认自动建,所以填 IO 不会撞「越界」;想严格抓路径 typo,加 --no-create(纯填已存在结构时用)。
  • 填真实 value/directive:你只挑锚点,工具取原文——把值写成 @quote|<起锚>|<止锚>(或 @quote|<关键词>),patch 时带 --resolve-quotes --source <原文json> --ocr <case_dir>/_scratch/ocr.txt,工具自动把标记换成原文 / 配图 OCR 里的真实内容。别自己读原文、粘长内容。
    • 文本类 value(提示词/数据/报告/JSON)必须是【完整逐字】真内容——整段 prompt / 整段 JSON 原样搬全,别概括/截断/只填一句(长内容用 @quote|<起锚>|<止锚> 框整段, 工具逐字回填)。⚠️ 第三阶段 render-case.py 见到文本类 <占位> value 会拒绝出 HTML。原文确实没有 → value 写成 <占位>(原文未提供)(或标 inferred:true)即可放行;媒体类(图/视频/音频)用 <具体描述> 不受此限。
  • 分阶段读:每进一阶段先读对应 phase 文件(phase1/2/3),别只读本总览 + tools.md 就开干(操作细则都在阶段文件里)。
  • 第一阶段别碰归类:type 随便起个描述标签即可(不查词表、不注册 type_registry);作用/动作/类型归类 + 自造类型挂靠 type_registry 是第二阶段的活(那时才读三张词表)。

仅 Cyber Agent 引擎(执行引擎是 Claude Code 则跳过本节)

  • 工具名:Read→read_file · Write→write_file · Edit→edit_file · Bash→bash_command · Glob→glob_files · Grep→grep_content · 看本地图 read_images
  • bash_command 是 cmd.exe:一条命令一次调用;别用 ; 串(要串用 &&);别加 | cat / ; type ... / $? 这类尾巴(返回已含 stdout+stderr+exit code);路径用正斜杠、含空格的值用双引号。
  • goal 规划工具:focus 只认计划里的纯数字序号(goal(focus="4"),不是标题);goal(done="总结") 完成当前焦点(须先 focus 成功)。报错只改成纯数字重试一次,别反复换写法(会死循环烧回合)。
  • 路径:cwd 是 procedure-dsl/(不是 spec/),spec 文档里的相对链接(extraction/x.md)读取时补 spec/ 前缀。read_file 有 2000 字/行、50KB/次 上限会静默截断长内容,长文本用 quote-source.py(读全文件)别 read_file 通读。

操作流程

整个流程围绕一个文件 workflow.json 滚动演化——从第一阶段搭好骨架,后面每阶段都在它上面就地补字段,不另存新文件。

第一阶段 · 搭骨架
   1.0 读懂案例 → 调 plan_procedures 工具交计划(工序/每工序步骤展开/章节认领)
           (Cyber 引擎: 工具校验完整性后自动生成 workflow.json 骨架; 其他引擎: 写 understanding.md 再建)
   1.1 在骨架上填 value/directive(别增删工序/步骤)
   1.3 把步骤间的数据流连起来      → 改 workflow.json(补"来源/去处")
第二阶段 · 归类标注
   · 作用/动作/类型 归到分类词表
   · 实质/形式 直接提炼元素点(不查词表)
   · 自造类型登记 → 写进 type_registry
   · 每步填目的列(intent)
第三阶段 · 检查收尾
   · 跑 lint-case.py 检查
   · 跑 render-case.py 渲染出网页

起手(只做一次)

把本文读一遍,之后别再回头读它——需要某阶段细节时直接读对应的阶段文件。再把 tools.md 读一遍(后面要调的脚本接口都在那),也别重读。

重要:读过的文件别重复读

上下文是累积的,你读过的文件内容会一直留在记忆里不要因为某处写了"详见 tools.md"就又去读一遍;不要进了第二阶段又去重读阶段文件。需要时从记忆里翻,别重复 Read——那会白白浪费预算。

第一阶段 · 搭骨架(新读这些)

要做的事:通读案例 → 想清楚有几个工序、每个工序怎么走 → 切步骤 → 填骨架 → 把数据流连起来。

该读(还没读过的) 干嘛用
extraction/phase1-skeleton.md 第一阶段具体怎么做 + 字段填写规则
input/case-{N}-raw.json 案例原文(你的素材)

产物(写到 outputs/case-{N}/):workflow.json——先调 plan_procedures 工具交计划(几个工序 / 每工序步骤展开 / 每工序认领哪些 0N 章节),Cyber 引擎据此自动生成骨架;再用 wf-patch.py 在骨架上填 value/directive、补"来源/去处"(别增删工序/步骤)。 过关条件:workflow.json 自查通过(数据流都连上了、类型一致)→ 进第二阶段。

第二阶段 · 归类标注(新读这些)

要做的事:把"作用/动作/类型"归到分类词表;把"实质/形式"直接提炼成元素点;填每步的目的列。

新读 干嘛用
extraction/phase2-normalize.md 第二阶段怎么做
taxonomy/effect.json / action.json / type.json 三张分类词表

产物:用 wf-patch.py(--set/--patch)在 workflow.json 上补 作用/动作/类型 + 实质/形式 + 自造类型登记 + 目的列。别 edit/手写改它,也不要另存新文件。 过关条件:每步的作用/动作都命中标准词、每个类型要么命中词表要么登记了挂靠、每步该有的实质/形式都提炼好、每步都有目的列 → 进第三阶段。

第三阶段 · 检查 + 渲染(新读这些)

要做的事:跑检查 → 渲染出网页(脚本自动组装,不另存中间文件)。

新读 干嘛用
extraction/phase3-finalize.md 检查清单 + 脚本命令
format/case-data.schema.json 字段的机器清单(最终裁判)

脚本命令:

# 1. 检查 + 自动登记新类型(轻量, 不卡流程); 带 --source 才查「章节覆盖」+「value 逐字」
python spec/tools/lint-case.py --workflow outputs/case-{N}/workflow.json --case-id {N} \
    --source input/case-{N}.json --ocr outputs/case-{N}/_scratch/ocr.txt

# 2. 渲染网页(脚本在内存里组装好数据直接出 HTML)
python spec/tools/render-case.py \
    --workflow outputs/case-{N}/workflow.json \
    --source-input input/case-{N}-raw.json \
    --page-title "Case {N} · <主题>" \
    --case-id {N} \
    --out outputs/case-{N}/case-{N}-<slug>.html

产物:outputs/case-{N}/case-{N}-<slug>.html(唯一产物)。

每次 Read 前自查

  • 这个文件之前读过吗?读过就别再读。
  • 只想确认"提没提过某概念"?用 Grep,别整篇 Read。
  • 只想看"目录里有啥"?用 Glob。
  • 中断后接着做:用户可能改过workflow.json(及 understanding.md 草稿,若有)要重读;spec 没变,不用重读。

卡住了怎么办

某阶段的过关条件过不去 → 别硬闯下一阶段,回当前阶段修。修两次还过不去 → 在产物里挂个 inferred: true, inferred_reason: "反复过不去, 需人工看" 标记,再往下走。