## 控制流与结构建模 (workflow.json) > 源里出现**循环 / 并行 / 分支 / 抽样 / 多返回**时,**不要拍平成单个标记步** —— 用 workflow.json 的 block/nested 结构把这套"程序结构"如实表达出来。schema + renderer 都支持,渲染成带层级的工序表。`kind` / `control` / `group` 在 **Phase 1.2 切片**时定,anchor 在 **1.3 闭合**。 ### 控制块 = `kind:block` 父步 + `kind:nested` 子步 源里的 `遍历 / 并行 / 分支` 是一个**控制块**: - 父步 `kind:block` + `control:遍历|并行|分支`,`via` 用 `-`(块不调工具) - 块体里每一步 `kind:nested` + `group=父步id`;id 用点号(父 `s5` → 子 `s5.1`) - **块本身带自己的 `inputs/outputs/intent`** —— 表达"高层意图"(这个循环整体在做什么),子步表达"每次具体执行" `遍历` 完整例子(对应原 DSL 文本 `遍历 场景 ∈ 分镜序列: { 分镜图 = @采样(n=4){生成图像(...)}; 分镜图列表.追加(分镜图) }`): ```json { "id": "s5", "kind": "block", "control": "遍历", "via": "-", "intent": "遍历每个场景生成分镜图", "inputs": [{"type": "分镜脚本", "name": "分镜序列", "anchor": "← s4.分镜序列"}], "outputs": [{"type": "分镜图", "name": "分镜图列表", "anchor": "→ s6"}] } { "id": "s5.1", "kind": "nested", "group": "s5", "via": "nano_banana", "action": "生成/元素生成", "effect": "主体生成", "inputs": [{"type": "提示词", "name": "场景提示词", "anchor": "← 分镜序列[i]"}, {"type": "参考图", "name": "主角图", "anchor": "← 分镜图列表[-1]"}], "outputs": [{"type": "分镜图", "name": "分镜图", "anchor": "→ 分镜图列表.追加"}], "instruction": [["decorator", "@采样(n=4, pick=人工)"]] } ``` ### 容器与索引 (走 `anchor` 字符串) - 循环取元素:input anchor `← 分镜序列[i]`(正索引)/ `← 分镜图列表[-1]`(取上一项,做链式参考) - 累加进容器:output anchor `→ 分镜图列表.追加` - 取子部分(属性访问):`← s1.正向提示词.人物`(引用某变量的子块 / 字段,而非整体) - 普通上下游:`← sN.var` / `→ sN` ### caller-side 修饰 (抽样 / 重试 / 缓存) 不改动作本身,挂在 step 的 `instruction` 里: - `["decorator", "@采样(n=4, pick=人工)"]` —— 抽 N 个候选按策略挑一个;`pick` ∈ `人工 / judge_fn / first` - `@重试(max=3)` / `@缓存` / `@限流`(留 placeholder) ### 多返回值 一步产出多个东西 → 多个 `outputs[]` 项(如 反推提示词 同时出 `正向` + `负向` 两个 `type:提示词`),不要合并成一项。 ### 边界 - 控制流 minimal:无 exception / continuation / coroutine;分支用 `control:分支`。 - 一个 step 自己就是控制(非块,无子步)时可直接挂 `control`,不强制建块;但**有循环体 / 并列体时务必展开成 block + nested**,别拍平成单标记步。