上一章用一支 AI MV 解释“长任务怎样拥有不会随进程消失的执行身份”。这一章换成九十秒动画解释视频《城市如何在夜间醒来》,
因为 OpenMontage 的 animated-explainer manifest 完整展示了 research、proposal、script、scene plan、assets、compose 与 publish。
两个案例承受同一类长周期生产压力,却不假装走同一条业务 pipeline。这里把镜头推近到制作现场:coding agent 怎样在仓库里读规则、
产出结构化工件、调用工具、接受审批并留下恢复点。
阅读契约。 全文始终跟踪“九十秒《城市如何在夜间醒来》动画解释视频”。读完后,应当能复述一次制作如何从 pipeline 与 manifest 进入 preflight, 再逐阶段读取 director skill、交接 artifact、按策略写 checkpoint,最后走到 render runtime 与 final review;还要能指出哪些约束由 Python 强制, 哪些只是 agent 必须遵守的仓库契约。
证据边界。 本文固定在 c36e412 源码快照。 YAML manifest 与 Markdown skills 是给 agent 的可读执行契约;只有文中明确链接到 Python 的 schema 校验、gate 拒绝、 文件写入、工具发现和 render routing 才称为代码强制。仓库里没有另一个 Python orchestrator 在后台自动扮演制片人。
一、一句 prompt 为什么不是生产系统
如果把任务直接写成“做一支九十秒《城市如何在夜间醒来》动画解释视频”,模型当然可以马上开始:先写几段旁白,再调图片或视频 API,最后拼成 MP4。 但生产过程里最贵的错误往往早于渲染发生:主题理解错了、三个创意方向其实只是同一个方向换标题、环境没有配置所选 provider、 用户以为会得到真实运动画面,系统却在失败后静默退化成图片平移。
先不要急着看源码名。把用户刚刚交来的任务想成一张还很粗糙的制作卡:输入只有题目、目标观众、几张霓虹城市参考图, 以及“解释电力、交通与夜间经济怎样让城市逐层亮起来”;输出希望是九十秒、有旁白、有字幕、能公开发布的横屏视频。 预算有限,引用的数据必须有来源,真正的运动画面不能在失败后悄悄变成静态幻灯片。 这张卡还不足以开工,因为它没有回答方向由谁确认、每一阶段交什么、哪项能力在当前机器上真实可用,以及什么证据能证明成片守住了承诺。
任务:九十秒《城市如何在夜间醒来》动画解释视频
已有输入:题目、目标观众、参考图、目标平台
用户承诺:有依据的解释、真实运动感、旁白、字幕、可发布
尚未决定:创意方向、provider、render runtime、成本
不可静默越过:提案、脚本、场景、素材、发布批准
1.1 先把五个高频词说成人话
Pipeline 是制作路线,例如“从零生成一支动画解释视频”,而不是某个模型。 Manifest 是这条路线的清单:先做什么、每一步读什么、交什么、能用哪些工具、什么时候必须停下来等人。 Director skill 是某一工种的工作手册,告诉 agent 怎样研究、提案、写脚本或审片。
Artifact 是阶段交接用的正式工件,例如研究简报、提案包、脚本、场景计划和素材清单;它们是文件中的项目事实,不是对话里一句稍后可能忘掉的承诺。
Checkpoint 则是进度记录:现在做到哪一阶段、状态是制作中、等待人还是已完成、这一步对应哪些工件。
如果 checkpoint 标着 awaiting_human,所谓 gate 就是“不收到批准便不能把它改成 completed”的那扇门。
1.2 真正要补齐的是责任,而不是 prompt 长度
| 一句 prompt 没有表达的责任 | 一旦缺失会发生什么 | OpenMontage 放在哪里 |
|---|---|---|
| 当前阶段与输入工件 | 返工时不知道该退回脚本、场景还是素材。 | pipeline_defs/*.yaml |
| 创作决定与备选项 | 换 provider、声音或渲染器后,只剩最后结果,没有原因。 | proposal_packet 与 decision_log |
| 人工批准 | 昂贵素材已经生成,用户才发现方向不对。 | manifest gate 与 checkpoint 状态 |
| 真实能力 | 计划建立在未安装 runtime 或缺失 API key 上。 | ToolRegistry preflight |
| 交付承诺 | render 成功被误当成产品完成。 | final_review 与 publish gate |
OpenMontage 的 Rule Zero 先把入口收紧:所有制作必须选择 pipeline、读取 manifest、完成 preflight,再逐阶段读取对应的 director skill。 这条规则不是为了制造更多文件,而是把“模型临场发挥”改造成“agent 在显式生产合同中做判断”。
接下来只要一直追踪四个问题,密集的文件名就不会把主线冲散:
- 这一刻,agent 正在替谁做什么决定?
- 决定之前读了哪个工件,之后又写出哪个工件?
- 推进条件只是 Markdown 里的工作纪律,还是 Python 会拒绝违规状态?
- 如果会话现在消失,下一次从哪里知道已经做过什么?
二、核心心智模型:Agent 是控制平面,Python 是工具与持久化
仓库的 项目上下文 把架构写得非常直接:agent 承担编排、创作决策、review 与阶段推进;Python 负责可调用工具和持久化。 所以这里的 executive producer、director、reviewer 首先是 Markdown 中的角色协议,不是常驻 Python service。
OpenMontage 本身不是一个在后台自动转动的制片网站。典型操作现场是:用户把仓库交给一个能够读文件、调用工具的 coding-agent 会话,
agent 根据 AGENT_GUIDE.md 打开 YAML 与 Markdown,显式调用 Python tool 和 checkpoint utility。
如果没有这样的 agent 主动推进,仓库里的文件不会自己从 research 跑到 publish;换一个会话后,新 agent 也必须先读项目目录才能恢复上下文。
“控制平面”在这里不是什么抽象云计算术语。它只是说:agent 决定下一步该读哪份规则、该让用户在什么地方做选择、该调用哪件工具, 以及一个失败应该返工还是升级给人。真正生成图片、合成音频、渲染视频和写入 checkpoint 的动作由 Python 工具完成。 agent 不需要亲自实现视频编解码,Python 也不替用户判断“城市逐层亮起”是不是比“追踪一个夜班司机”更适合解释这个题目。
AGENT_GUIDE.md
-> 选择 animated-explainer
-> 读取 pipeline_defs/animated-explainer.yaml
-> ToolRegistry preflight,展示真实能力
-> 读取当前 stage 的 director skill
-> 产出 schema-valid artifact
-> reviewer skill 自查
-> checkpoint utility 持久化并执行 gate
-> 进入下一 stage 或等待人工批准
把这段流程放回霓虹城市解释视频:agent 先从 manifest 看见当前是 proposal,于是读取 proposal director;
director 要求它拿研究结果做出至少三个真正不同的方案,并把当前可用的 provider、成本和 runtime 说清楚。
agent 产出 proposal_packet,reviewer 检查三个方案是否只是换标题,checkpoint utility 再验证结构并把状态写成
awaiting_human。用户选择“电力、交通与夜间经济依次接管画面”之后,agent 才能把 proposal 重写为 completed 并进入 script。
这是一种很适合 coding agent 的分层。稳定规则可以版本化、review、被人和模型共同阅读;变化很快的 provider 通过工具注册表暴露; 只有“不能靠自觉”的部分才落到代码。代价也同样明确:如果 agent 没有读取规则、上下文漂移或平台不支持可靠的工具调用, Markdown 本身不会像进程内 orchestrator 那样主动夺回控制权。
2.1 固定合同与运行时现实必须分开
| 层 | 回答什么 | 典型文件 |
|---|---|---|
| 生产合同 | 必须经过哪些阶段,哪些工件与关口不可省。 | AGENT_GUIDE.md、pipeline_defs/ |
| 工作方法 | 当前角色应如何研究、提案、写脚本、审片。 | skills/ |
| 能力现实 | 这台机器此刻有哪些 provider、runtime 与依赖。 | tools/tool_registry.py |
| 项目事实 | 用户批准了什么、已经做完什么、产物在哪里。 | projects/<id>/ 下的 artifacts 与 checkpoints |
2.2 一次阶段推进,其实只有六个动作
- 定位:从 checkpoint 找到第一个未完成阶段。
- 装载:读取 manifest、当前 director skill,以及上游已经批准的工件。
- 判断:由 agent 在工作手册约束下提出创意或执行选择。
- 执行:需要外部能力时,通过 registry 中的 Python tool 产生真实副作用。
- 取证:把结果写成 schema-valid artifact,并让 reviewer 对照本阶段标准检查。
- 交接:遵守 manifest 的 checkpoint 策略;需要持久化就写状态,有 gate 就等待人,否则进入下一阶段。
这六步也给出了系统的失效边界。前三步依赖 agent 忠实阅读并遵守仓库契约;artifact schema、checkpoint gate、原子写入和 render routing 才是 Python 能强制的部分。把所有 Markdown 都删掉,工具仍会存在,却没有制片方法;把所有 Python 都删掉,文字规则仍在,却没有可靠的验证、持久化和媒体执行面。
三、Manifest 不执行视频,它定义一条可审计的路线
对这支动画解释视频,主线就是
animated-explainer.yaml。
它把制作拆成 research → proposal → script → scene_plan → assets → edit → compose → publish,
并为每个阶段声明输入工件、产出、可用工具、review focus、success criteria 与人工批准策略。
3.1 先按真实顺序走完整条路线
深挖某个类或字段之前,先把一次生产按时间顺序走完。下面每一行都回答同样四件事:这一站收到什么、agent 做什么、留下什么、 凭什么进入下一站。Preflight 发生在创意承诺之前;后面的章节再分别展开 checkpoint 与渲染边界。
| 时刻 | Agent 此刻做什么 | 留下的项目事实 | 推进条件 |
|---|---|---|---|
| 选择路线 | 把明确的动画解释请求匹配到 animated-explainer,读取 manifest。 | project.json 标记项目与 pipeline。 | 路线与目标一致。 |
| Preflight | 发现真实工具、provider 配置与 composition runtime。 | 给人看的 capability menu;尚未承诺创意。 | 缺失能力被说明或补齐。 |
| Research | 研究现有内容、数据、受众问题与可讲角度。 | research_brief。 | 来源、数据点与角度达到 manifest 标准。 |
| Proposal | 把研究与能力现实变成三个不同方案、成本和生产计划。 | proposal_packet、decision_log。 | 用户批准 concept c2、provider 与 runtime。 |
| Script | 把已批准方向写成九十秒、有时间与旁白表演提示的脚本。 | script。 | 用户批准措辞、时长与叙事。 |
| Scene plan | 把脚本段落变成连续镜头与所需素材。 | scene_plan,包含 scene-04。 | 用户批准 storyboard。 |
| Assets | 按 scene 调用图片、视频、TTS、音乐工具并记录成本。 | asset_manifest 与局部 checkpoint。 | 素材存在、风格一致,用户批准 filmstrip。 |
| Edit | 用 asset ID 排时间线、字幕、音乐与转场。 | edit_decisions。 | 无空档、引用有效、承诺被带到 compose。 |
| Compose | 按批准的 runtime 渲染并检查真实输出。 | render_report、final_review、MP4。 | 输出通过规定检查。 |
| Publish | 准备视频、元数据与缩略图概念的交付包。 | publish_log。 | 用户最后批准发布。 |
这里最值得借鉴的不是阶段数量,而是每次交接都变成了有名字的 artifact。proposal 不是聊天里一句“就走方向 B”,
而是必须带至少三个 concept、production plan、成本估计和批准状态的 proposal_packet;
compose 也不是只返回文件路径,而要同时产生 render_report 与 final_review。
下游读工件,不必依赖 agent 还记得上百轮聊天里的隐含决定。
3.2 Stage director 是“怎样做”,schema 是“至少长什么样”
Manifest 只告诉 agent 现在要产出 proposal;具体怎样给出互相不同的方向、怎样解释成本与质量权衡,
由 proposal director skill 指导。另一方面,
proposal schema
把最低结构变成机器可验证条件,并要求显式记录 render_runtime。
三层在一次 proposal 里这样协作:manifest 声明输入必须有 research_brief、输出必须有 proposal 与 decision log、而且这一站要等人;
director skill 进一步要求方案在 hook、叙事结构和视觉方式上真正不同;schema 只检查结构与枚举值,不能判断三个标题是否只是同义改写。
最后并不是“仓库里放了一个 schema 文件”就自动安全:
validate_checkpoint()
在写 checkpoint 时调用 artifact validator,缺少必需工件或字段才会实际被拒绝。
{
"selected_concept": {
"concept_id": "c2",
"rationale": "用电力、交通与夜间经济三层解释城市怎样醒来"
},
"production_plan": {
"pipeline": "animated-explainer",
"renderer_family": "cinematic-trailer",
"render_runtime": "hyperframes",
"composition_mode": "atelier",
"delivery_promise": {
"promise_type": "motion_led",
"motion_required": true,
"tone_mode": "cinematic",
"quality_floor": "presentable"
}
},
"approval": {
"status": "approved"
}
}
这是教学用缩略形状,不是可直接提交的完整 artifact。关键在于把“方向”“技术 runtime”“创作方式”和“交付承诺”拆成不同字段: 后面如果 renderer 发生变化,就能判断它是合理实现调整,还是偷偷改变了用户批准的作品性质。
3.3 跟着同一个镜头穿过工件链
只看阶段名称仍然容易把 pipeline 想成一排互不相干的待办。更好的办法是盯住一个具体镜头。
假设研究发现电力、交通与夜间消费并不是同时启动,脚本把“城市分层醒来”写进第三段旁白;scene plan 再把这段旁白变成
scene-04,要求低机位、霓虹边缘光和向前推进的镜头。到了 assets,场景需要的背景、运动片段和旁白各自得到 asset ID;
edit 只引用这些 ID 排时间线,compose 才把引用解析成文件并渲染。
research_brief
-> 依据:城市夜间活动由多套系统分层支撑
script.sections[s03]
-> 旁白:城市不是同时醒来,而是一层层点亮
scene_plan.scenes[scene-04]
-> 18s–27s,neon,dolly_in,需要运动背景
asset_manifest.assets[neon-04]
-> scene_id=scene-04,记录路径、provider、成本
edit_decisions.cuts[cut-04]
-> source=neon-04,进入时间线
final_review
-> 抽查中段画面、音轨、字幕与 motion promise
上面是帮助理解的 lineage,不是仓库里的真实项目记录;字段关系则来自 script、 scene plan、 asset manifest 与 edit decisions。 有了这条链,返工不再只是“我不喜欢这一段”:团队可以指出是研究依据不对、旁白不对、场景语言不对、素材失败,还是剪辑引用错了。
如果脚本改了,后面的场景和素材会自动作废吗?
当前快照没有展示一个自动计算工件依赖并级联失效的构建图。
get_next_stage()
只按 manifest 顺序寻找第一个没有 completed checkpoint 的阶段。若用户批准后又改脚本,agent 必须根据 send-back 规则重做受影响工件并重写 checkpoint;
history/ 会保留被替换的正式版本。也就是说,它提供可追踪的返工材料,但不是自动依赖失效引擎。
四、Checkpoint 把昂贵创作变成可恢复的项目状态
init_project()
先建立项目目录与 project.json;需要持久化或设置 gate 的阶段再写 checkpoint_<stage>.json。
是否必写由 manifest 的 checkpoint_required 决定:这条 pipeline 的 research 是 false,proposal、script、scene_plan、
assets、edit、compose 与 publish 是 true。状态可以是 in_progress、awaiting_human 或 completed,
长阶段还可以把已完成场景写进 partial progress。
history/ 保留阶段重做与批准转换的旧版本。
4.1 先回放一次做到一半的中断
素材阶段最适合看 checkpoint 的价值,因为它既慢又贵。agent 进入 assets 时先写一份 in_progress;
每完成一个重要场景,就把已经完成的 scene ID 和尚未成为正式 artifact 的草稿放进 metadata.partial_progress。
如果生成到 scene-04 时会话消失,磁盘上至少留下“前四个场景已经成功”的事实,而不是只剩聊天窗口里一句“正在生成”。
进入 assets
-> checkpoint_assets = in_progress
完成 scene-01 ... scene-04
-> 刷新 partial_progress.completed_scene_ids
Agent 会话中断
-> 新会话读取 get_next_stage(),仍得到 assets
-> 读取 partial progress,跳过已完成场景
完成全部素材并通过 review
-> checkpoint_assets = awaiting_human
用户批准 storyboard / filmstrip
-> checkpoint_assets = completed
-> 才进入 edit
这里恢复的是项目语义:哪些场景已经有可用素材、下一步应从哪里继续。它不保证某个进行中的云端生成请求能被原样接管; provider 是否已经扣费、是否接受了请求、回执是否丢失,仍需要工具自己的 operation ID、幂等策略或账本。 checkpoint 解决“下一个 agent 应该相信哪些项目事实”,不能替外部服务发明它没有提供的恢复语义。
恢复时真正读到的不是抽象的“进度”,而是类似下面这样的缩略记录:
{
"project_id": "night-city-explainer",
"pipeline_type": "animated-explainer",
"stage": "assets",
"status": "in_progress",
"human_approval_required": true,
"human_approved": false,
"artifacts": {},
"metadata": {
"partial_progress": {
"completed_scene_ids": ["scene-01", "scene-02", "scene-03", "scene-04"]
}
}
}
这是 shape-level 示例。正式 artifact 尚未完整时,checkpoint protocol 要求把草稿放在 metadata.partial_progress;
如果把一个已知 artifact 名写进 artifacts,即便状态仍是 in progress,它也会接受对应 schema 校验。
新会话先读 stage 与 status,再决定是继续局部工作、重新展示人工关口,还是寻找下一个阶段。
4.2 人工 gate 不只是 prompt 里的提醒
Animated explainer 的 proposal、script、scene_plan、assets 与 publish 都在 manifest 中声明人工批准。
write_checkpoint() 的 gate enforcement
会重新读取 manifest:如果一个 gated stage 没有 human_approved=True 却要写成 completed,代码直接抛错。
这就是“指令驱动但关键边界 fail closed”的具体例子。
“等待人工”也不是页面上的一行提示。正确协议是先写 awaiting_human,展示工件摘要、review 结果与已花成本,然后结束当前交互;
只有用户下一次明确批准,才能带着 human_approved=True 重写为 completed。这样“我本来准备问”与“用户真的批准过”在持久化状态里不会混成一件事。
proposal = in_progress
-> proposal_packet 完成并通过结构校验
proposal = awaiting_human
-> 展示三个 concept、runtime、成本与 reviewer 发现
用户要求修改
-> 重写 proposal,decision_log 追加选择理由,再次 awaiting_human
用户明确批准
-> proposal = completed, human_approved=true
-> get_next_stage() 返回 script
若 agent 跳过等待直接写 completed
-> CheckpointValidationError: GATE VIOLATION
-> 项目仍停在 proposal,不会得到一份伪造的批准状态
4.3 原子写入、历史版本与 decision log 各自解决不同问题
当前 checkpoint 先序列化到临时文件,再通过
os.replace
原子替换;被覆盖的非 in_progress checkpoint 会复制进 history/。
与阶段状态分开的
decision_log
则保存每个重要选择的备选项、选中项、理由和用户批准。前者回答“做到哪里”,后者回答“为什么这样做”。
三者不要混用:原子替换防止一次写盘只写出半截 JSON;history/ 保存被正式状态覆盖的版本与 gate 转换;
decision_log 则是跨阶段累积的选择账本。频繁刷新的 in_progress 是心跳和局部进度,不会每次都塞进 history,
否则生成一百个场景就会制造一百份没有审计价值的中间版本。
projects/night-city-explainer/
project.json
decision_log.json
checkpoint_proposal.json
checkpoint_script.json
checkpoint_assets.json
history/
checkpoint_proposal_....json
artifacts/
assets/
renders/
final.mp4
get_next_stage()
会按 pipeline 顺序寻找第一个未完成阶段。新的 agent 会话因此能读取项目文件继续;但“能读文件继续”与“执行系统自动 replay”仍然是两种承诺,
第八节会专门把它们拆开。
五、Preflight 先问“真实能做什么”,再承诺创意
视频工具变化很快。同一个能力可能有本地模型、云 provider、多个价格与依赖;静态列一张工具表,很快就与机器现实脱节。
OpenMontage 的
discover()
遍历 tools package,注册实际存在的具体工具;selector 按 capability 聚合 provider,而不是让 director 绑定一个固定品牌。
给人看的入口不是原始工具 dump,而是
provider_menu_summary():
它汇总每类 capability 的 configured/total、可用与不可用 provider、setup offer、runtime warning,以及
Remotion、HyperFrames、FFmpeg 的可用性。这样 agent 可以在花钱之前告诉用户“当前能做什么、缺什么、降级会改变什么”。
ToolRegistry.discover()
-> provider_menu_summary()
composition_runtimes
capabilities[]
setup_offers[]
runtime_warnings[]
-> proposal_packet.production_plan
-> 用户批准 provider / cost / runtime
-> proposal -> script -> scene_plan -> assets
5.1 能力菜单怎样真实改变创意方案
provider_menu_summary() 的价值在于把工具注册表翻译成能做生产决定的菜单。下面不是作者机器的实时输出,
而是一份保持源码字段含义的缩略例子;configured/total 表示某类工具中有多少当前报告可用,
setup offer 指出可以通过配置解决的缺口,runtime warning 则解释为什么某个看似存在的执行器还不能开工。
composition_runtimes
remotion: true
hyperframes: false
ffmpeg: true
capabilities
image_generation: configured 1 / total 3
tts: configured 1 / total 4
video_generation: configured 0 / total 5
setup_offers
video_generation: add provider API key
runtime_warnings
hyperframes: required runtime not resolvable
假设提案原本想让每个城市街区都用真实生成视频,但 preflight 发现当前只有图片生成可用,视频 provider 没有配置; 同时 Remotion 可用,可以让静态素材在合成层产生排版、镜头和图形运动。agent 不能继续把“真实生成运动”写进承诺, 也不能偷偷把它解释成 Ken Burns。它要么帮助用户配置视频 provider,要么把方案改成以 motion graphics 为主,并明确说明作品性质、成本和质量会怎样变化。
创意需要:真实运动镜头 + 旁白 + 字幕
当前能力:图片可用,TTS 可用,视频生成不可用,Remotion 可用
不能做:按原承诺直接进入 assets
可以选:
A. 配置视频 provider,保留 motion-led 承诺
B. 改成 motion-graphics-led,重写承诺与成本
推进条件:用户看见差异并批准其中一条
Preflight 也有边界。discover() 能证明某个工具类被注册,工具报告的 status 能说明依赖或配置是否满足;
它不能保证远端 provider 此刻没有限流、账户有额度、生成内容一定合格。前者是开工前的能力事实,后者仍要在真实调用、ToolResult、
cost log 与 reviewer 中观察。把“可发现”写成“必成功”,只是把另一种静默假设搬进了系统。
六、先锁定渲染承诺,失败时也不准静默换引擎
OpenMontage 把三件常被混在一起的事拆开:delivery_promise 说作品答应交付什么;
renderer_family 说创作语法;render_runtime 说真正运行 Remotion、HyperFrames 还是 FFmpeg。
composition_mode 又独立描述是用可复用模板,还是为单支作品手工搭建 atelier composition。
把它们翻成四个用户问题会更直观:最终答应我看到真实运动还是图文动画?画面采用电影预告、数据解释还是别的创作语法? 哪个技术引擎实际负责把时间线算成 MP4?这次是复用模板快速生产,还是为单支作品手工写一套 composition? 四个答案相关,却不能互相代替。尤其是 runtime,只是技术执行者;选择了 Remotion 并不自动保证作品具有运动感,也不自动证明它符合批准过的 visual approach。
仓库契约要求在 proposal 阶段把可用 runtime 摆给用户,并记录选择。
到真正渲染时,
video_compose._render()
拒绝缺失或未知的 render_runtime,然后严格路由到对应实现。明确选择 FFmpeg 时不会自动“升级”;
Remotion 失败时也不会悄悄退到另一条路径。
6.1 渲染失败之后,正确流程是什么
假设用户批准的是 Remotion atelier:每个场景为这支解释视频手工编排,而不是套用库存卡片。渲染时 Node 依赖缺失,
最省事的代码当然可以自动退到 FFmpeg,把静态图做平移缩放;但这样虽然更容易得到 MP4,却破坏了用户批准的运动语言。
_render()
的选择是返回失败和可选路径,把产品决定交还给 agent 与用户。
Remotion render 失败
-> 不生成“看起来成功”的 FFmpeg 替代品
-> 说明失败原因:依赖、工具 bug 或作品设计
-> 展示选项:修复 Remotion / 明确降级 / 改用另一 runtime
-> 解释每个选项对运动、成本、时间的影响
-> 用户批准新路径
-> decision_log 追加同一决策主题的新记录
-> 更新工件并重新渲染
注意最后两步不是“把旧字段改掉”。decision_log 是追加历史;当 runtime、provider 或声音选择改变时,
新记录要沿用相同的 category 与 subject,让旧选择成为可见的被替代方案。这样 final review 才能判断实际运行的 runtime 是获批修订,还是无人知情的漂移。
6.2 为什么“可播放”仍然不是“可交付”
Render 前,工具会验证 cut、asset 与 scene plan;Render 后,
同一入口触发 final review。
final_review schema
要求记录容器与音轨、抽帧检查、音频抽查、字幕覆盖,以及实际 runtime 是否保持 proposal 的承诺。
如果 review 为 fail,ToolResult 也会失败,不能把文件包装成完成品。
机器实际采集了哪些证据
当前 Python 路径先用 ffprobe 读取容器、视频流、音轨、时长、分辨率与 codec;再在全片 10%、35%、65%、90% 的位置抽四帧,
用非常粗的文件大小启发式提示黑帧;音频检查通过 volumedetect 寻找近乎静音与可能削波;字幕检查则看字幕流,
或确认用于烧录的字幕源文件仍然存在。最后,它比较 proposal 与 edit 中的 runtime,并计算 delivery promise 的 motion 比例。
这些检查擅长抓“没有视频流”“完全无音轨”“时长离谱”“runtime 被换掉”一类可观测故障,却不等于 Python 真正看懂了作品。 例如 MP4 没有音轨会留下明确 issue;但如果音乐把旁白压得听不清,只要总体音量不低,简单统计仍可能通过。 人物是否变形、字幕是否挡住主体、节奏是否有情绪,也需要 reviewer agent 看抽帧或转录,最终仍应由人观看成片。
6.3 四种“成功”必须分开
一次 provider 调用成功,只说明它返回了结果;render 成功,只说明输出文件存在且通过了合成入口的技术流程。
final_review 的 pass 才表示技术探测、开中结尾抽帧、音频、字幕和承诺保持都没有阻断问题;
最后的 publish gate 还要等待用户决定是否采用并发布这份成片。
| 状态 | 已经证明什么 | 还不能声称什么 |
|---|---|---|
| 工具返回 success | 某次素材或处理调用产生了结果。 | 整支视频已经成立。 |
| Render output 存在 | 时间线被执行,得到可探测的媒体文件。 | 画面、声音、字幕与批准承诺都合格。 |
| Final review pass | 真实输出通过了规定的自动取证与规则检查。 | 语义质量完美,或用户已经采用并允许发布。 |
| Publish gate completed | 用户批准交付,发布工件也已形成。 | 外部平台永远不会转码、拒绝或下架。 |
这里还有一个值得保留的实现细节:schema 把 final review 分成 pass、revise、fail;
其中 revise 表示发现可修问题,按 agent contract 也不能包装成完成品,而 fail 会让当前 ToolResult 直接失败。
所以“代码自动阻断”与“agent 必须遵守 review 结论”仍然是两层约束,不能因为都叫 final review 就混为一谈。
七、这套设计真正聪明的地方:把判断放在正确的一侧
| 判断 | 更适合放在哪里 | 原因 |
|---|---|---|
| 哪个创意更适合这个题目与观众 | Agent + proposal director + 用户。 | 需要语义、品味与协商,难以写成稳定 Python 分支。 |
| 提案至少包含哪些字段 | JSON Schema。 | 结构完整性可以确定验证。 |
| 当前机器有哪些视频 provider | ToolRegistry。 | 这是运行时事实,不能靠文档猜。 |
| 一个人工 gate 能否被标记完成 | Checkpoint utility。 | 不能把不可越过的边界只写成建议。 |
| 素材风格是否一致 | Reviewer skill + 人。 | 需要对作品做语义与视觉判断。 |
| MP4 是否有音轨、时长与字幕证据 | Renderer + final review artifact。 | 可以对真实产物取证。 |
这也解释了为什么 OpenMontage 不是“用 Markdown 代替代码”。它真正做的是把约束分级: 创作方法保留为可以进化的指令,结构合同放进 schema,环境事实交给 registry,越权风险交给 Python 拒绝, 最后再把真实输出送回 review。优雅之处不在于少写了一个 orchestrator class,而在于每种责任都有合适的证据形状。
7.1 为什么不能把所有约束都塞进同一种媒介
如果一切都写进 prompt,创作方法很好改,但字段完整、审批和写盘安全只能依赖模型自觉;如果一切都写成 Python 状态机, 结构更硬,却会把“这个镜头是否诚实”“三个方案是否真的不同”也伪装成确定分支。OpenMontage 的分层标准不是“能不能编码”, 而是“这个判断需要哪一种证据,失败时谁有权阻断”。
这也给普通 agent 项目一个检查方法:凡是会花钱、产生不可逆副作用、越过人工授权或改变用户承诺的动作,都不应只靠文字提醒; 凡是依赖语义、品味和上下文协商的判断,也不应为了看起来工程化而硬塞进布尔条件。中间的 artifact 让两侧可以交接: agent 给出有理由的选择,schema 与工具验证它能验证的部分,人再决定是否采用。
八、与 Temporal 的边界:文件恢复不是持久化执行
最关键的结论。 OpenMontage 当前快照没有使用 Temporal,也没有展示一个跨进程自动调度 stage、重放控制流、分发 task queue 的服务。 它的 checkpoint 让项目工作可恢复、可审计;Temporal 的 Event History 让执行控制流可由新的 Worker 重建。
8.1 同一次中断,两套系统各自记住什么
23:14 scene-04 素材生成完成
23:15 Agent 进程退出,下一场景尚未调用 provider
OpenMontage 留下:
checkpoint_assets.json = in_progress
partial_progress.completed_scene_ids = [scene-01 ... scene-04]
已生成素材与选择理由
Temporal 留下:
Workflow Event History 中已经调度、开始、完成或等待的事件
Service 继续拥有 Workflow Execution
新 Worker 可由历史重建控制流并继续取任务
OpenMontage 的下一会话要主动打开项目、解释 checkpoint,然后决定如何继续;没有会话时,文件不会自己调度 scene-05。 Temporal 则让 Workflow 在调用方和 Worker 都不在线时仍由 Service 持有,并在 Worker 回来后重建执行。 反过来,Temporal 的历史不会自动替视频团队保存“为什么选方案 B”“scene-04 的美术意图是什么”;这些仍属于业务 artifact 与 decision log。
| 故障或暂停 | OpenMontage 文件协议能提供什么 | Temporal durable execution 额外提供什么 |
|---|---|---|
| Agent 会话结束 | 下一会话读取 checkpoint、artifacts 与 decision log,继续下一个未完成阶段。 | Workflow Execution 独立于任何会话持续存在。 |
| 素材做到 scene-04 时失败 | in_progress partial progress 可记录已完成 scene,agent 据此跳过。 | Activity attempt、retry、timer 与完成事实由服务保存并重新调度。 |
| 人工批准等待一夜 | awaiting_human 文件保留关口,下一会话重新展示。 | Workflow 可持久等待消息,不需要业务自己唤醒会话并解释文件。 |
| 同一个外部生成调用回执丢失 | 仍需 tool/provider 的幂等键与业务账本。 | Activity 也仍需外部幂等,但重试与执行历史由 durable runtime 管理。 |
8.2 组合时要先选择 durable unit
两者最自然的组合不是把 OpenMontage 的 director 改写成 Temporal 内部 DSL,而是保持层次: Temporal 或其他 durable controller 拥有整次制作的业务生命;OpenMontage agent 在某个 Workflow/Activity 边界内完成一段生产语义; provider 与对象存储拥有外部副作用和大文件。具体要把 durable unit 设成整支制作、一个 stage,还是一个昂贵 scene, 取决于重复成本、人工等待与可观测要求。
如果整支制作只是一个 Activity,接入简单,但九十秒解释视频的内部进度对 durable runtime 几乎不可见;如果每个 scene 都变成 Activity, 重试和并发更细,却要处理更多幂等键、媒体引用和状态转换。常见折中是 Workflow 持有阶段与人工等待,Activity 执行一次可重试的工具或生产单元, OpenMontage artifact 作为业务输入输出,checkpoint 继续服务 agent 恢复与人工审计。这个组合是设计建议,不是当前 OpenMontage 快照已经实现的主路径。
九、从 OpenMontage 带走的七条规则
- 先选择生产合同,再调用生成工具。入口必须落到 manifest,而不是临时脚本。
- 每次阶段交接都交 artifact。下游依赖结构化工件,不依赖长对话里的隐含记忆。
- 把人类批准写成状态,并在代码层拒绝越权。“记得问一下”不算 gate。
- 创意承诺必须建立在 preflight 的真实能力上。provider 与 runtime 是运行时事实。
- 重要决定保存备选项与理由。只记录最后选择,无法审计 fallback 是否改变了产品。
- 渲染器失败不能静默改变作品。runtime、composition mode 与 delivery promise 要分别锁定。
- 把生成、验证、采用、发布拆成不同状态。文件存在只是验收链的开始。
9.1 用一口气复述完整流程
用户带着题目、受众和目标平台来,agent 先选择 pipeline 并做 preflight;研究工件把题目变成有依据的角度,proposal 把角度、成本、provider、 runtime 与交付承诺摆给用户选择。批准后,script 把选中方向写成有时间的语言,scene plan 把语言变成可生产镜头, asset manifest 记录每个真实素材的来源、路径与成本,edit decisions 用 asset ID 组成时间线。renderer 只能按批准过的 runtime 执行; checkpoint 在每个关口保存状态,decision log 保存为什么;final review 检查真正生成的 MP4,publish gate 最后才允许交付。
如果在这条复述里删掉任何一环,都能说出一个具体代价:没有 preflight,创意可能建立在不存在的能力上;没有 artifact,阶段交接依赖聊天记忆; 没有 checkpoint,中断后不知道做到哪里;没有 decision log,fallback 只剩结果没有理由;没有 final review,可播放文件会冒充可交付作品。 这就是 OpenMontage 比“长一点的 prompt”多出来的系统性。
OpenMontage 最值得看的,不是它能连多少个模型,而是它给 coding agent 一间有账本、有工序、有门禁、有工具盘点、有验片室的工作室。 这套结构仍然依赖 agent 忠实执行指令,也还没有替代 durable runtime;但它把“做视频”从一次不可追溯的模型行为, 推进成了一条人和 agent 都能检查、暂停、恢复与修正的生产路线。