feat(core): AI 生成 Agent 化 — 多模型流式脚本 agent + 可插拔 Provider + gpt-image-2 参考图 + 模特库

- 后端·可插拔 Provider 层:通用 OpenAICompatibleProvider(tokenssr 等中转站,base_url+api_key,零改代码换站)+ ModelProvider.api_key
- 后端·脚本 agent:结构化 ScriptDraft 契约 + 加载电商 skill + 出稿/改稿一体对话 agent(3模式/多模型)+ 流式 SSE 端点(DRF SSE renderer)
- 后端·图像:gpt-image-2 参考图出图 + 故事板 @图1@图2@图3 多锚点合成(锁脸锁商品);Seedance 打开 generate_audio
- 后端·模特库:gpt-image-2 生成器(9:16氛围图→16:9白底三视图)+ seed_demo_models 管理命令
- DB·迁移:tokenssr 中转站 + 多模型 seed(豆包/GPT-5.5/Gemini + gpt-image-2);ScriptSegment 结构化字段
- 前端·脚本趴:接真 SSE(工具卡 + 思考流)+ 模型下拉 + 3模式 + 改稿;agentScriptStream
- skills/ecommerce-video-script 电商脚本技能(运行时依赖)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
seaislee1209
2026-06-17 03:12:03 +08:00
co-authored by Claude Opus 4.8
parent a0ffb6fc8e
commit 6464001f84
32 changed files with 9294 additions and 54 deletions
+261
View File
@@ -0,0 +1,261 @@
# AirShelf · AI 生成 Agent 化落地方案
> 目标:把【脚本生成】升级为「多模型可选 + 出稿/改稿一体」的对话式 agent,并打通后续图片/故事板/视频 SOP。
> 用户定位:不懂视频制作的电商小白,点按钮就出"能吸睛、能转化"的带货短视频,提示词全替用户包好。
> 本文整合 2026-06-16 多轮讨论结论,作为开工 SSoT。
---
## 0. 一句话现状
5 阶段流水线(商品 → 脚本 → 图片 → 故事板 → 视频)页面已搭好,生成链路能跑,但:**脚本是一次性散文+正则解析、无 agent、无多模型;图片"平台套图"是装饰;参考图生成断线;Seedance 音频被关。**
---
## 1. 现状核查(已验证,带 file:line)
### 1.0 模型与中转站(最终方案,均已实测 200)
**主力中转站 = `tokenssr`(`https://king.tokenssr.com/v1`,一把 key 通吃 90 模型,见 .env `TOKENSSR_API_KEY`)。**
| 用途 | 模型 | 端点/调法 |
|---|---|---|
| 脚本·豆包 | doubao-seed-2.0-pro | 火山 ARK chat(本地直连) |
| 脚本·GPT | `gpt-5.5` | tokenssr `chat/completions` |
| 脚本·Gemini | `gemini-3.1-pro-preview` / `gemini-3.5-flash` | tokenssr `chat/completions` |
| 纯文生图 | `gpt-image-2` | tokenssr `images/generations` |
| **参考图/编辑** ⭐ | **`gpt-image-2`** | **tokenssr `images/edits`(multipart `image[]`,1~多张参考图,返回 b64)** |
| 视频 | seedance-2.0 | 火山 ARK(本地直连) |
- 多图参考(故事板 @图1@图2@图3)实测 200;`gemini-3-pro-image-preview`(chat 多模态)留作图像备选/风格选择。
- YunQi 那家分组割裂、gpt-image-2 渠道残废 → 已弃用,仅留历史参考。
- token 用量正常返回,对齐"按实际 token 扣费"。
### 1.1 模型与 fallback
| 类型 | 实际模型 | Provider | Fallback |
|---|---|---|---|
| 脚本 text | Doubao-Seed-2.0-Pro | 火山 ARK(写死) | ❌ 无 |
| 图片 image | **GPT-Image-2 / YunQi 网关**(Seedream 被 disabled) | YunQi | ❌ 无 |
| 视频 video | Seedance-2.0 | 火山 ARK(写死) | ⚠️ 仅"丢参考图退纯文生视频" |
- 默认选模型 = 该能力下最早创建的 active 行 [services.py:33-39](core/backend/apps/ai/services.py#L33-L39)
- 生图按 provider 分流(yunqi/火山) [services.py:42-46](core/backend/apps/ai/services.py#L42-L46)
- YunqiProvider 继承火山,`chat_completion` 现成 → **文本接多模型很便宜** [yunqi.py](core/backend/apps/ai/providers/yunqi.py)
### 1.2 脚本生成(无 agent)
- 系统提示词:4×15s、强制 `镜头N/旁白/画面` 格式 [services.py:53-77](core/backend/apps/ai/services.py#L53-L77)
- **正则**抠字段 [services.py:81](core/backend/apps/ai/services.py#L81)
- **第二次** LLM 调用抽 人物/场景 JSON [services.py:116](core/backend/apps/ai/services.py#L116)
- 全是一次性调用,无循环/无工具/无自检
### 1.3 图片(平台套图是空壳)
- 三种模式提示词模板在前端 [ai-tools.tsx:387](core/frontend/src/routes/ai-tools.tsx#L387)
- 平台卡/模特卡选择 `pickedIds` **只做高亮,不拼进 prompt、不发后端** [ai-tools.tsx:1195](core/frontend/src/routes/ai-tools.tsx#L1195)
- 提交只发 `{prompt, mode, count}` [api.ts:342](core/frontend/src/api.ts#L342);后端 `mode` 只决定任务类型/分类/命名,不加工 prompt [services.py:1067](core/backend/apps/ai/services.py#L1067)
### 1.4 视频
- 视频提示词织入风格锚点+旁白+画面 [services.py:621](core/backend/apps/ai/services.py#L621)
- 已传参考图给 Seedance [services.py:870-897](core/backend/apps/ai/services.py#L870-L897)
-`generate_audio` 写死 False [volcano.py:129](core/backend/apps/ai/providers/volcano.py#L129)
---
## 2'. 开工就绪状态(2026-06-17 全部核实)
| 卡点 | 状态 |
|---|---|
| 电商 skill | ✅ 已写好 `skills/ecommerce-video-script/`(SKILL.md+5 references),**输出契约与 §3 完全对齐**(还多了 aspect_ratio + 四档时长) |
| 参考图出图 | ✅ tokenssr gpt-image-2 `images/edits` 实测(含多图) |
| 火山审核+绿/红标 | ✅ **AirDrama 有整套现成**:`video-shuoshan/backend/utils/assets_client.py`(建组/传素材/查审核)+ AssetGroup/Asset 模型(status: processing→**active=绿标 / failed=红标**)+ 轮询接口。照搬即可。策略:**一团队一素材组**(火山确认单组可放 500 万素材),后台 API 静默自动上传,前端不显示组、只显示绿/红标;红标提示"未通过审核,请改提示词重生" |
| 模特库 | ✅ 由 agent 用 gpt-image-2 预生成 2-3 个(先 9:16 正面氛围图 → 以其为参考出 16:9 白底三视图)。提示词见 §阶段4 |
| 前端结构 | ✅ routes 齐全,不用大动,主要接线+结构化渲染+聊天框+badge |
| 多模型 | ✅ 豆包/GPT/Gemini 实测可用 |
### ★ 架构原则:Provider 可插拔(不写死中转站)
**除火山(ARK/Seedance,官方直连)外,其余全走中转站且随时可换** → 设计成:
- **一个通用 `OpenAICompatibleProvider(base_url, api_key)`** 覆盖所有中转站(tokenssr/yunqi/未来任意家),按 `ModelConfig.provider``base_url`+`api_key` 实例化。
- **换中转站 = 改 DB 里 Provider 的 base_url+api_key,零改代码**;加新家 = 加一行(格式兼容则复用同一 provider 类)。
- `VolcanoArkProvider` 专管火山官方(文本/图/Seedance)。
- 新增 `ModelConfig.api_key`;key 全部走 .env / DB,**不写死代码**。
## 2. ⚠️ 前置硬伤 / 必须先决策
### GAP-1 参考图生成 —— ✅ 已解决(2026-06-17 实测,换中转站 tokenssr)
**结论:换到中转站 `tokenssr`(base `https://king.tokenssr.com/v1`)后,gpt-image-2 直接支持参考图(含多图)。** 之前 YunQi 是渠道残废,不是 gpt-image-2 本身不行。
- **一把 key 通吃 90 个模型**(无 YunQi 那种分组割裂):gpt-image-1 / gpt-image-1.5 / **gpt-image-2** / dall-e-3 + 全套 Gemini 文本&图像模型 + gpt-5-nano 等。
- **gpt-image-2 传参考图,两条路实测 200:**
- **A·`images/edits`(标准 OpenAI 格式,推荐)**:multipart,`image[]`**1 张或多张**参考图 + `prompt` + `model=gpt-image-2` + `size`;返回 `data[0].b64_json`。**多图参考(2张)实测 200** → 故事板 `@图1@图2@图3` 成立。
- **B·`images/generations` + `image`(base64)**:返回 `data[0].url`(`r2.sysrv.net/...png`,直接是托管 URL)。
- 参考图来源:角色/场景/商品图在 TOS(URL)→ 取字节走 edits 的 `image[]`,或 base64 走 generations;出图落 TOS。
- **需新增 `TokenssrProvider`**:`image_generate()`(文生图)/`image_edit(model,prompt,ref_bytes[],size)`(参考图,multipart image[])。比之前 Gemini-chat 解析 markdown 的方案**更干净**(标准 OpenAI 格式、data[] 直接拿图)。
- 备选:同站的 Gemini 图像模型(`gemini-3-pro-image-preview`)走 chat 多模态也可用,留作 fallback/风格选择。
- **这是图片/故事板/视频趴的前置依赖,现已具备。**
### GAP-2 Seedance 音频被关
- 你的设计:Seedance 直接出画面+音效+人声,不走 TTS。
-`generate_audio=False` 写死 [volcano.py:129](core/backend/apps/ai/providers/volcano.py#L129) → 需打开;音色一致性(audioReference,Seedance-2.0 支持 [catalog.py:67](core/backend/apps/ai/catalog.py#L67))二期再接。
### 决策清单
1. **图片参考图模型**(已定·实测解决):用 **tokenssr 的 gpt-image-2**(`images/edits` multipart `image[]`,多图已验证);YunQi Gemini 图像模型留可选 fallback。
2. **计费粒度**(已定):**按实际 token 消耗,每次调用扣一次费**。含义:agent 自检循环每跑一轮都扣 → 循环要克制(≤2-3 轮),内部调用尽量精简,避免空转扣费。
3. **平台套图(独立图片工具)**(已定):暂不管,本方案聚焦视频项目流水线。
4. **多 key 管理**(基本解决):换 tokenssr 后,一把 key 通吃 90 模型,不再有 YunQi 分组割裂问题。后端仍加 `ModelConfig.api_key` 字段(留作多 provider 共存:tokenssr / 火山本地)。
---
## 3. 数据契约:结构化脚本 `ScriptDraft`(全链路地基)
把脚本从"散文+正则"改成**结构化输出**(JSON/tool-calling),模型无关,一次喂饱全下游。
```jsonc
{
"hook": "前3秒主打钩子(一句话)",
"tone": "种草|测评|剧情|痛点",
"aspect_ratio": "9:16", // 不写死,可 16:9/1:1/4:5,透传下游
"total_duration": 60, "segment_count": 4, // 时长 15/30/60/90 四档,每15s一镜→1/2/4/6镜
"entities": [ // 角色/场景/商品,全脚本共享 → 保证4镜同一角色同一张脸/同一音色
{ "id": "c1", "type": "character|scene|product", "name": "女主",
"visual_prompt": "给图模型的生图提示词(AI自动生成,小白不打字)",
"ref_index": 1,
"voice_ref": "可选·角色音色参考(二期锁音色)" }
],
"segments": [
{ "index": 0, "duration": 15,
"role": "钩子|痛点|卖点|CTA", // 电商脚本的灵魂
"narration": "本镜要说出来的台词/旁白,≤55字(Seedance 15秒内直接发声,字数=可懂语速上限)",
"speaker": "可选·指向角色entity的id;null=画外旁白",
"visual": "画面描述",
"product_exposure": "商品露出方式(手持/特写/使用中)",
"entity_refs": ["c1"] }
]
}
```
**它如何驱动全下游:**
- 图片趴:直接读 `entities[].visual_prompt` 预填出图卡(小白不打字)
- 故事板趴:按 `entity_refs` + `ref_index``@图N`
- 视频趴:`narration`(发声)+ `visual` + `@图N` 参考 → Seedance
- 一致性:同一 entity 全程一份图/一份音色
> 从 AirDrama **保留**:结构化思维、entity 层(一致性)、segment role。**砍掉**:三流、5 种 beat、est_sec、Section 嵌套、质量词三层 fork。
---
## 4. 分阶段落地
### 阶段 0 · 电商剧情 skill —— ✅ 已完成
- 产物在 `skills/ecommerce-video-script/`(SKILL.md + 5 references:methodology/hook-library/category-playbook/platform-tone/checklist)。
- 输出契约 = §3 ScriptDraft(并扩展了 aspect_ratio + 15/30/60/90 四档时长);3 模式路由、输出前自检、写作红线、渐进披露齐全。
- agent(阶段2)运行时加载它作为领域知识。**无需再做。**
### 阶段 1 · 结构化契约 + 多模型管子(后端 ~1d)
-`ScriptDraft` 类型(§3);脚本输出从正则改 **tool-calling/JSON**
- 文本 provider 分流(照搬生图)或全走 YunQi 网关;`/api/ai/models/` 已能列模型,生成时透传 `model_config_id`
- DB:加 **GPT-5.5** + **Gemini-3.5-flash/3.1-pro**(均 YunQi 已实测可用)文本模型设 active;按模型配各自 key(决策4)
- **验收**:同一商品,豆包 / GPT-5.5 / Gemini 三家都产出合规 `ScriptDraft`,字段不崩
- 依赖:无 ‖ 可与阶段0并行
### 阶段 2 · 对话式脚本 agent(出稿+改稿一体)(后端 ~2-3d)
- **同一个 agent 跑在带状态会话上**:第1轮=出稿(3模式 seed),第N轮=改稿(带上轮草稿)
- Session 状态:当前 `ScriptDraft` + 消息历史 + 商品上下文 + 选定模型/调性
- 工具:`get_product / load_skill / validate / emit` + `edit_segment(index,instruction)` / `patch_draft`(`build_segment_rerun_prompt` [services.py:353](core/backend/apps/ai/services.py#L353) 升级为工具)
- 有界循环 ≤2-3 轮:读(草稿+用户话)→ 判(整篇重生/改某镜/答疑)→ 执行 → validate → emit
- 一个 endpoint:`(session_id, 可选消息, 当前草稿) → (新草稿, agent回话)`
- 计费:**按实际 token、每次调用扣**(决策2)→ 循环 ≤2-3 轮、内部调用精简,避免空转扣费
- **验收**:点按钮 ~10-20s 出 4 镜结构化脚本;聊一句能精准改某镜;旁白≤55字、结构齐、entity 一致
- 依赖:阶段0 + 阶段1
### 阶段 3 · 前端脚本趴(前端 ~1.5d)
- 模型下拉(豆包/GPT/Gemini)
- 3 种出稿输入(全自动/一句话/自带脚本)
- 4 镜结构化渲染(钩子/痛点/卖点/CTA 标签 + 旁白/画面/商品露出)
- 聊天框(改稿)+ 每镜快捷按钮(重跑/改活泼/加钩子=预设改稿指令)
- **验收**:设计师视角点按钮出稿、看得到分镜结构、能对话改 / 点按钮改单镜
- 依赖:阶段2
### 阶段 4 · 图片趴(后端+前端)
- **前置·新增 `TokenssrProvider`**:`image_generate()`(文生图)/ `image_edit(model,prompt,ref_bytes[],size)`(参考图,`images/edits` multipart `image[]`);新增 `ModelConfig.api_key`
- **三视图**(商品创建即可生,视频项目内可补):prompt + 上传商品图(正/侧/背多参考)→ **gpt-image-2 `images/edits`** 出三视图;无则用原图
- **实体出图**:直接读脚本 `entities[].visual_prompt` 预填卡,小白只点生成(不打字);不满意可改 prompt
- **模特库**(预生成 2-3 个电商模特,流程:① gpt-image-2 出 9:16 正面氛围图 → ② 以①为参考图出 16:9 白底三视图,提示词:`参考图1角色,生成角色三视图,从左往右依次为:胸像特写,全身正面,全身侧面,全身背面,白色背景`)+ 自定义模特/场景(gpt-image-2 生)
- 出图落 TOS,大图预览
- **火山审核**(照搬 AirDrama `utils/assets_client.py` + AssetGroup/Asset 模型 + 轮询接口):一团队一素材组,后台静默自动上传(前端不显示组),轮询 status → **active=绿盾标 / failed=红标**(红标提示"未通过审核,请改提示词重生");env 复用 TOS_ACCESS_KEY/TOS_SECRET_KEY + ASSETS_API_ENABLED + PROJECT_NAME
- **验收**:小白零输入出齐角色/场景/商品图;三视图可参考原图;盾牌 icon 正确
- 依赖:阶段2(脚本 entities)
### 阶段 5 · 故事板趴(依赖阶段4)
- 拼装系统提示词 + 角色图/场景图/商品图(三视图优先)+ 本段 15s 脚本 → **gpt-image-2 `images/edits` 多图 `image[]`** 出导演故事板(多图实测 200)
- 提示词骨架:`制作导演故事板指导seedance / @图1角色 @图2场景 / 分镜脚本(15s) / 规则:景别·运镜·画面·角色动作·情绪·对白旁白·灯光`
- 每帧场景/角色必须回溯脚本文字(靠 `entity_refs`)
- **验收**:每镜一张故事板,角色/场景跟回脚本,可指导视频
- 依赖:阶段4
### 阶段 6 · 视频趴(依赖阶段5)
- 分镜图+角色图+场景图+商品图+文字脚本 → Seedance(火山,参考图走 TOS URL,已在用)
- v1 固定模板:`【设定】@图1是X角色,@图2是X场景,@图3是X商品 【分镜】根据@图4分镜图生成X商品视频 【脚本】…`(后续可做视频优化 skill)
- 打开 `generate_audio`(GAP-2);二期接 audioReference 锁音色
- 火山审核盾牌 icon 同图片趴
- **⚠️ Seedance 出片慢:正常 5-10 分钟/段,凌晨可能 3-4 分钟**。轮询超时要放长(≥15 分钟),测试时别误判失败;若实测耗时太长,视频趴只到"提交成功+轮询机制验证",标注成熟度交接。
- **验收**:四镜成片、画面跟故事板、音画自带、审核 icon 正确
- 依赖:GAP-2 + 阶段5
---
## 5. 全链路数据流
```
商品(信息+图) ──┐
├─→ [脚本 agent] → ScriptDraft(hook/entities/segments)
前置条件(调性/平台)┘ │
├─ entities[].visual_prompt ─→ [图片趴] 角色/场景/商品图(三视图优先)
│ │
├─ entity_refs + 15s脚本 ──────────────→ [故事板趴] 导演分镜图
│ │
└─ narration + @图N + 分镜图 ──────────→ [视频趴] Seedance 成片(自带音)
全程:同一 entity = 同一张脸/同一音色 ;火山审核盾牌 icon
```
---
## 5'. 执行须知(compaction-safe resume 锚点 · 2026-06-17 夜)
> 压缩/换会话后,从这里 + 下面的 checklist 直接续干,不必重读全部代码。
**凭证(都在 `core/backend/.env`):**
- `TOKENSSR_API_KEY` / `TOKENSSR_BASE_URL`(`https://king.tokenssr.com/v1`)= 主力中转站,一把 key 通吃 90 模型。
- `FEISHU_APP_ID` / `FEISHU_APP_SECRET`(机器人「小毛球」,文件上传权限已开)。
- 火山:`VOLCANO_ARK_API_KEY``TOS_*``VOLC_TTS_*` 已就绪。
**已验证可用模型(tokenssr,均 200):** 文本 `gpt-5.5`/`gemini-3.1-pro-preview`/`gemini-3.5-flash`;图编辑 `gpt-image-2`(`images/edits` multipart `image[]`,1~多张参考图,返回 b64)+ `images/generations`(文生图);Gemini 图像 `gemini-3-pro-image-preview`(chat 多模态,备选)。豆包/Seedance 走火山 ARK 本地。
**关键代码事实(已读):**
- `ai/models.py`:`ModelProvider`(name/base_url/metadata,**需加 `api_key` 字段+迁移**)、`ModelConfig`(provider FK/name/capability/endpoint/status,默认选 `get_default_model`=该能力最早 active)、`AITask`(idempotency_key 必填唯一、status 机、request/response_payload、estimated/actual_cost)。
- `ai/services.py`:`create_ai_task``reserve_credit`;`charge_reserved_credit`/`release_credit`(billing/services/ledger.py,幂等带行锁);`get_image_provider` 按 provider.name 分流;`build_*_prompt` 系列;`generate_project_script`(改结构化输出落 `ScriptVersion.metadata`)。
- `providers/`:`base.py`(AIProvider Protocol)、`volcano.py`(VolcanoArkProvider:chat_completion/image_generation 带 `image` 参/create_video_task 有 `generate_audio=False` **需开**)、`yunqi.py`。**要新增 `OpenAICompatibleProvider(base_url,api_key)`** 覆盖所有中转站 + tokenssr 的 `image_edit`(images/edits multipart image[])。
- `projects/models.py`:`ScriptVersion`(content+metadata)、`ScriptSegment`(narration/visual_prompt/duration,**需补 role/product_exposure/entity_refs/speaker 或塞 metadata**)、`BaseAssetGroup`(kind: product/person/scene,adopted/candidate assets)、`StoryboardVersion/Frame``VideoSegment/Version`
- `assets/models.py`:`Asset`(category: person/scene/product_image/…)+`AssetFile`(object_key/bucket/preview_url)。出图落 TOS 已有链路。
- 前端 routes 齐全:`pipeline.tsx`(五阶段主)、`projects.tsx``ai-tools.tsx``api.ts``types.ts`。不大改,只接线+结构化渲染+按钮+绿红标。
**火山审核复用(照搬 AirDrama,有 4 个坑已处理):**`video-shuoshan/backend/utils/assets_client.py`(create_asset_group/create_asset/get_asset)+ AssetGroup/Asset 模型(status active=绿/failed=红/processing)+ 轮询。策略:一团队一素材组,后台静默上传 TOS URL,前端只显示绿/红标。
- **坑1·SDK**:AirShelf `requirements.txt``volcengine`(只有 boto3+requests)→ 加 `volcengine` 依赖装上(或用 requests 手写火山签名)。
- **坑2·密钥**:AirDrama 用 `settings.TOS_ACCESS_KEY/TOS_SECRET_KEY`;AirShelf 改用**独立 env** `ASSETS_API_ACCESS_KEY/ASSETS_API_SECRET_KEY`(已写入 .env,**暂借 AirDrama 已邀测开通的 AK/SK** `AKLTNGJi…`)。搬代码时把读 key 处改成读这俩。
- **坑3·配置**:`.env` 已加 `ASSETS_API_ENABLED=true` + `ASSETS_API_PROJECT_NAME=int_dev_Airlabs`(assets_client 里 PROJECT_NAME 常量改读这个 env)。
- **坑4·权限(用户已拍板)**:AirShelf 自有火山账号没开通人像素材库邀测 → **先用 AirDrama 的 AK/SK 跑通**;**交接 MD 必须标红**:张业昌待办 = AirShelf 火山账号开通人像素材库后,把 .env 的 `ASSETS_API_ACCESS_KEY/SECRET` 换成自己的(独立两行,不动 TOS_*)。
**模特库提示词:** ① gpt-image-2 出 9:16 正面氛围电商模特 → ② 以①为参考:`参考图1角色,生成角色三视图,从左往右依次为:胸像特写,全身正面,全身侧面,全身背面,白色背景`(16:9)。
**收尾:** 推 dev 分支;飞书小毛球发交接 MD 给 **张业昌 13725102796** + **尹雨萱 15915987827**(测试号 13811803069 已验证可发文件)+ 附言(署名 Claude + 用户),让他们明早接手。飞书流程:token→batch_get_id(mobile→open_id)→ 上传文件(/im/v1/files,file_type=stream)→ 发文件消息(msg_type=file)。
**skill:** `skills/ecommerce-video-script/`(SKILL.md+5 references),输出契约 = §3 ScriptDraft(+aspect_ratio + 15/30/60/90 四档),agent 运行时加载它。
## 6. 关键路径
- **阶段 0(skill)+ 阶段 1(契约/多模型)并行先启** = 整条线地基
- **GAP-1 已解决**(tokenssr gpt-image-2 参考图实测可用),图片/故事板/视频不再被阻塞
- 阶段 2 是把 skill+契约粘起来的执行器;阶段 3 让设计师能用
- 图片/故事板/视频(4/5/6)在脚本跑通后顺序推进
- 唯一待你拍板:**决策4(多 key 管理方式)** —— 不阻塞阶段 0/1,可边做边定