决策审计链路与 20 个 artifact 契约

2026-08-09

让 agent 替你做一堆选择,最难受的不是它选错,而是三天后你想不起来它为什么这么选。换了哪个 provider、为什么用这段音乐、那个镜头是不是被降级成静图了——问下去往往只能得到一句重新编出来的解释。

OpenMontage 对这件事的态度写在 README 的 Production Governance 一节里,开篇原文是它像对待真正的工程那样对待视频制作:每个阶段都有质量闸、审计链路和强制执行。质量闸那部分本批另有一篇专门讲,这篇只盯审计链路——因为它是这个仓库里少数能一路追到具体文件名和具体字段结构的部分。

README 说要记什么

Decision Audit Trail 那一小节的原文说得很具体。每一个重大的创意与技术选择——provider 选择、风格/playbook 选择、音乐曲目、音色选择、渲染器 family、任何回退或降级——都会连同考虑过的备选项、置信度分数和理由一起被记录。累积的决策日志跨所有阶段持久化,所以你能追溯输出为什么长这样。对应的文件是 schemas/artifacts/decision_log.schema.json

这段话里真正有信息量的是「考虑过的备选项」。只记结果的日志是给机器看的,记了备选项才是给人看的:你复盘的时候关心的往往不是「它选了 A」,而是「B 当时为什么没被选」。

要注意的是,这里的「置信度分数」不是随手打的印象分。事实卡里的 lib/scoring.py 实读结果显示,provider 选择走的是一套七维加权求和,权重逐项写死在第 38-44 行,七项相加正好等于 1.00。这篇不打算铺开那张权重表(本批另有一篇专讲评分引擎),只引跟审计直接相关的两行:task_fit 一项占 0.30,而 cost_efficiency 只占 0.10。知道这两个数,你看决策日志里那个分数时才知道它是什么口径——它是一个把「任务匹配度」摆在成本前面的综合分,不是「便宜就赢」。README 也说了,胜出的 provider 及其分数会连同所有考虑过的备选项一起记进决策链路。

一个为了审计而保留的冗余参数

上面还都是文档口径。真正能看出「这套设计是不是认真的」,得看源码里有没有那种只为可追溯而存在的东西。

lib/slideshow_risk.py 里有一个。这个模块负责给一份视频计划打幻灯片风险分,函数签名实读如下:

def score_slideshow_risk(
    scenes: list[dict[str, Any]],
    edit_decisions: dict[str, Any] | None = None,
    renderer_family: str | None = None,
    render_runtime: str | None = None,
) -> dict[str, Any]:

返回的是一个四键的 dict:

{
    "average": float,
    "verdict": str,
    "dimensions": {dimension_name: {"score": float, "reason": str}},
    "render_runtime": str | None,
}

关键在 render_runtime 这个参数。它的 docstring 原文是这么写的:评分逻辑当前对运行时是中立的——一个文字很重的 HyperFrames 合成和一个文字很重的 Remotion 合成一样「幻灯片化」;但这个参数仍然是契约的一部分,好让调用方把 runtime 和 family 一起记录下来。

翻译成人话:这个入参当前不影响任何计算结果,它进来只是为了原样出现在返回值里。按写代码的常规直觉,这种参数早该删了。它留着,是因为审计需要——三个月后回头看这条记录,你能知道当时这条计划是打算用哪套渲染运行时跑的。

顺带说一句返回结构本身也是审计友好的:dimensions 不只给每个维度的 score,还给一个 reason。分数用来卡闸,理由用来给人看。至于这六个维度各自是怎么打分的,源码里是六个 _score_* 私有函数,那部分我们没有读过,不做描述。

降级被编码进了数据结构

审计链路里最容易被糊弄过去的一类事件是降级。lib/delivery_promise.py 的模块 docstring 把这件事直接点名了,原文说它要防的最具破坏性的失败模式是:在用户不知情的情况下,从「动效主导」悄悄降级成「静图主导」。交付承诺在提案阶段设定并锁定,compose 阶段兑现不了时,系统必须停下来问,而不是悄悄替换

对应的实现落在 DeliveryPromise 这个数据类的一个字段上:

approved_fallback: str | None = None  # "animatic", "still_led", or None

三态。"animatic" 是动态分镜,"still_led" 是静图主导,第三个状态是 None。没有被批准的回退方案就是 None——「未批准」不是靠流程约定或者口头提醒来保证的,它是这个字段的默认值。同一个类里另外两个默认值也是实读出来的:tone_mode 五个取值(cinematic、educational、corporate、playful、raw)默认是 "corporate"quality_floor 三档(draft、presentable、broadcast)默认是 "presentable",取中间那档。

这个类还有个 validate_cuts(cuts) 方法,docstring 说返回含 'valid''violations''motion_ratio' 三个键的 dict。三个键名可以告诉你审计记录里会出现什么,但它具体怎么算 motion_ratio、怎么判违规,我们没有读完那部分代码,不展开。

checkpoint 层:改过的版本也不许消失

审计链路还有一层在 checkpoint 上。README 的 Quality Gates 第一条里有两句跟审计直接相关:checkpoint 写入器会拒绝一个没有记录批准的「已完成」闸控阶段;以及每一个被取代的 checkpoint 都会被归档,所以审计链路(含闸的状态迁移)在修订之后仍然存活。

第二句是重点。很多系统的「状态可恢复」做法是原地覆盖,改一版旧的就没了,链路上只剩最后一个状态。归档旧 checkpoint 意味着「这个阶段被打回重做过两次」这件事本身也留在记录里。对应的契约文件是 schemas/checkpoints/checkpoint.schema.json

顺带提一句同一节里的另一条原文金句,它讲的是用户自带素材时系统要先探测每个文件再做创意决策:No hallucinating content from filenames.(不许从文件名幻觉出内容。)对应 lib/source_media_review.pyschemas/artifacts/source_media_review.schema.json

20 个 artifact 契约的名录

审计链路最后要落到产物上。我们实读 schemas/ 目录,数出 24 个 .json 文件,按目录拆是 20 个 artifact schema + 1 个 checkpoint + 1 个 pipeline manifest + 1 个 style playbook + 1 个 tool schema

那 20 个 artifact schema 的文件名,本身就是一次制作会留下哪些结构化产物的清单。按大致的产出顺序摆开:

  • 前期brief(简报)、research_brief(调研简报)、video_analysis_brief(视频分析简报)、source_media_review(源素材审查)、proposal_packet(提案包)
  • 规划script(脚本)、scene_plan(场景计划)、asset_manifest(素材清单)、edit_decisions(剪辑决策)、action_timeline(动作时间线)
  • 角色character_designcharacter_qa_reportpose_libraryrig_plan(角色设计、角色 QA、姿势库、骨架计划)
  • 后期与结算render_report(渲染报告)、review / final_review(评审 / 终审)、decision_log(决策日志)、cost_log(成本日志)、publish_log(发布日志)

必须说清楚的一条边界:这些 schema 文件的内部字段我们一个都没有读过。上面只是按文件名说明「存在这样一个 artifact 契约」,不代表我们知道它有哪些必填项、怎么校验。

即便如此,这份名录本身就是可用的信息。三个 log 类 artifact 各管一摊——decision_log 管「为什么这么选」,cost_log 管「花了多少」(config.yamlbudget 那几个键本批另有专篇),publish_log 管「发到哪去了」。评审拆成 reviewfinal_review 两份,说明中间评审不会被终审覆盖掉。

还有一处交叉印证值得记一笔:角色那四个 artifact(character_design / character_qa_report / pose_library / rig_plan)对应的是 character-animation 这条流水线。这条流水线没有出现在 README 的流水线表格里,但它在 pipeline_defs/skills/pipelines/schemas/artifacts/ 三个地方都有对应实体。

一处数字上的差异

README 的架构图里,schemas/ 那一行标的是 “15 JSON Schemas”,我们实读目录数出的是 24 个 .json。两处不一致,以仓库当前状态为准。本批另有一篇专门做 README 数字与实读计数的核查表,这里只陈述这一条,不推断原因,也不拿它评价项目。

这条链路能给你什么,不能给你什么

把上面这些串起来看,OpenMontage 的审计设计有三个能落到实处的抓手:决策带备选项和分数decision_log.schema.json)、被取代的状态会归档(checkpoint 写入器拒绝无批准记录的闸控阶段)、降级被编码成显式的三态字段approved_fallback"animatic" / "still_led" / None)。加上 slideshow_risk 里那个只为记录而保留的 render_runtime,这几处是能对着源码和 schema 文件名核查的。

不能给你的也要说明白。这些全是仓库源码与文档的口径,我们没有安装或运行过这套系统,没有生成过任何一条决策日志,也无从判断实际跑起来时每条记录写得有多完整。更要紧的一点是,这套流程的执行者是你的 AI 编码助手——契约文本写了「必须记录」,不等于模型每次都会照做;能不能真正落地,取决于你用的 agent 和它当时的上下文。把它当成一套设计好的记录规范来看,比当成一道保证更接近实际。


本文依据 OpenMontage 官方仓库(github.com/calesthio/OpenMontage)的 README、 AGENT_GUIDE.mdconfig.yamlpipeline_defs/lib/ 下的治理模块整理,核对日 2026-08-09。 本文内容为仓库源码与文档口径,我们没有安装或运行过该系统,也没有调用过其中任何一个 provider API, 文中出现的成本数字均为项目方在 README 中自行标注的金额,非我们的实测结果。 该项目以 AGPL-3.0 发布,部分流水线在 manifest 中自标 stability: beta,请以仓库最新内容为准。

想系统学会用 AI?报名体系课或加入会员,照着学、照着用。