syntax.md 7.4 KB

Procedure DSL · 概念模型

DSL 的概念模型 —— 给 Agent 建立"这是个什么世界"的心智框架:数据怎么分类型、动作怎么抽象、工序怎么组织、目的怎么分层。

实际产物是 workflow.json(结构化)+ HTML(可视化)。本文讲模型与思路;字段提取细节 → extraction/fields.md,控制流建模 → extraction/control-flow.md,字典树 → taxonomy/,workflow.json 契约 → format/case-data.schema.json。不含手写 DSL 文本的逐构造语法(那是已降级的 .md 交付物用的)。


§1 五层架构

DSL 表达分 5 层, 职责不同, 演化速度不同。

是什么 类比 演化 在 workflow.json 里
L0 类型库 数据类型(字典树叶子)+ 属性 type library stdlib 慢, case 扩展 IO item 的 type
L1 外部函数 绑定具体 tool 的稳定调用契约 syscall 只增不改 step 的 via(工具名)
L2 抽象动作 抽象能力(动作 kind), 由 L1 实现 interface + impl 可演化 step 的 action(动作树路径)
L3 工序模板 由动作组合的可复用工序 函数 / 类 高频迭代 一个 procedure
L4 工序实例 具体 case 的 inputs + 实际值 + trace 调用记录 每 case 一份 step 的 value 回填

L1 vs L2 是关键区分:L2 是工序内直接调用的抽象能力("反推提示词"),L1 是绑定具体工具的实现("via manus")。impl A via B 声明这层映射——同一个抽象动作可由多个工具实现(impl 生成图像: via nano_banana / via seedream)。workflow.json 里每 step 记选定的 via + action;若有备选实现 / 选型理由,写进 memo


§2 类型系统

type = 数据的"制作角色",不承担调用情境或步骤属性。

  • 一个 type = 类型字典树 的一个叶子名(按功能角色分类:程序控制 / 数据复用 / 内容 / 知识)。
  • case-specific 类型(不在叶子里)写在 workflow.jsonprocedures[i].type_registry,格式 {extends: 最近的 stdlib 叶子, desc},不污染 stdlib。

2.1 实质 / 形式 二分

每个 IO 的内容素材再按两个正交维度标注(这是内容"长什么样"的描述,与 type 的"角色"正交):

  • 实质 = 内容是什么(人物 / 场景 / 道具 / 观念 / 事件 …)
  • 形式 = 内容怎么呈现 / 组织(光照 / 色调 / 构图 / 运镜 / 叙事 / 修辞 …)

取值来自外部词表(分类库导出_{实质,形式}_*.json,走 taxonomy-lookup.py 查,不进 context)。标注对象是变量的 value(具体素材),不是变量名 / 类型 —— 例:变量"主角图"代表的那张具体图(女主特写)才是被标注对象,标 实质:/表象/视觉/人物 + 形式:/呈现/视觉/特写 (对复杂素材支持多路径标注,以 + 连接,在 workflow.json 中保存为 JSON 数组,如 ["/表象/视觉/人物", "/表象/视觉/空间"])。

2.2 PromptBlock(prompt 的结构化思路)

一段 prompt 不是单串文本,可看作有序的,每块有倾向:实质 | 形式 层 + 开放 tags + 角色 role(main / constraint / trick / style_preset …)。workflow.json 的 IO value 存完整 prompt 文本;这套分层思路帮你:(a) 判断该 IO 的 实质/形式 标注,(b) 把长 prompt 拆解理解。trick = 附着在某能力上、相对默认调用被验证有效的命名化偏离。


§3 动作模型

一个 step 的"怎么做"拆成正交字段(取值都受字典树 / 受控词约束):

字段 含义 取值
via L1 外部工具 具体名 nano_banana_pro / 占位 <llm> / human / 控制块用 -
action L2 动作 kind 动作树 根→叶路径,e.g. 提取/化学提取/反推
effect 在工序链中的位置 作用树 叶子,e.g. 主体生成
feature 执行特征 随机 / 幂等 / 人工 / 本地 / 写外部 / 读外部
control 控制流 并行 / 遍历 / 分支 / 请求 / 等待;普通 step 留 -(详见 control-flow.md)

caller-side 修饰(抽样 N 选 1 / 重试 / 缓存)不改动作本身,挂在 step 的 instruction 里:@采样(n=4, pick=人工) / @重试 / @缓存。同一动作在不同 caller 处可挂不同修饰。


§4 工序结构(L3 / L4)

  • L3 工序模板 = 一个 procedure:头部(name / purpose / category / platform / author)+ declarations(inputs 调用方传入 / resources 跨 case 长期资产 / returns)+ steps。一篇 case 可含多个 procedure(procedures: [])。
  • L4 工序实例 = 具体 case 的实际值:每个 IO 的 value 逐字回填(prompt 原文 / 工具配置 / N 选 1 结果);.md 输出按 inputs / bindings / extracted_values / trace 分块(见 md-structure §11)。
  • 控制流(循环 / 并行 / 分支)展开成 block + nested 结构,不要拍平——详见 control-flow.md
  • 跨 case 长期资产(resources)用 知识库 类型声明;读写不是独立标注维度,就是普通 step —— 写入 = action:存储/沉淀/入库 + feature:写外部,召回 = action:获取/查询/调取 + feature:读外部

§5 目的链 (Purpose Chain)

"目的"不是单一属性,是按稳定性 / 颗粒度分层的链,各层不同载体:

实体 持有方式 颗粒度 稳定性
L3 工序 purpose + 子维度 category 顶层产品意图 全局稳定
L2 抽象动作 docstring("能干啥") 接口契约 跨 caller 不变
L3 块(并行/遍历) intent + 子维度 作用 中间策略 块内稳定
L3 step intent + 子维度 作用 此次调用情境 因调用而变
变量声明 名字(+ 可选说明) 数据角色 工序全程稳定

MVP 最小集:工序头 purpose + 每个 step(或块)至少一个 intent


§6 标注原则

  • caller-side vs callee-side:step 的 intent / 输入 / 输出caller(这次调用)的;动作的 effect / action / featurecallee(动作本身)的,跨 caller 稳定。
  • tags / type 解耦:标注不重复 type 名已表达的领域语义(生成图像 上不再挂 模态:image)。
  • 值 vs 来源分离:value 写数据本身的内容;上游引用 / 下游去向归 anchor
  • #输入 / #输出 列具体子项,不写"全维"(列 实质·人物 + 实质·场景 …,不偷懒)。

§7 命名规范

元素 选择
类型名 / 动作名 / 关键字 中文 参考图 / 反推提示词 / 工序 / 输入 / 返回
变量名 type + 工序中的稳定角色(不带步骤属性 / 工具 / 状态) 参考视频 / 正向提示词 / 主角图 / 分镜序列
子维度 key:value 中文受控词 作用:预处理 / 特性:随机
工具品牌名 英文保留 manus / nano_banana_pro / seedream_4_5

变量命名归一:同一概念在不同 step 必须用同一名(lint 校验)。


字典树简称:其余文档里的 §A.1 作用 = effect.json、§A.2 动作 = action.json、§A.3 类型 = type.json(完整叶子 + 各节点 分类说明 以这三个文件为 canonical,本文不附录)。