Files
oak-editor/docs/zh/plans/ai-agent-design.md
T
Mike-Solar 3cc6f75ccc docs: archive completed plans, add the external plugin system design
- docs/zh/plans: finished plans move to completed/ (the RIIR series, the
  event-bridge and dependency plans, the v04 manual test plan).
- New design docs: the external (functional) plugin system
  (process-isolated, JSON-RPC/shm) and its protocol.
- ai-agent-design refreshed; README pointers follow the moves.
2026-08-25 03:03:28 +08:00

15 KiB
Raw Blame History

AI Agent 插件设计(基于 OPP/1 外部插件系统)

本文是 Oak 引入 AI 能力的长期设计,已按外部插件系统重写(旧版假设 RIIR 拆分后面对一堆 C ABI 小库、引擎内置 oak-mcp-server,已作废)。 AI 能力现在是一个外部功能插件:独立进程、经 OPP/1 协议操作 Oak。

依赖文档(冲突时以它们为准):

  • external-plugin-system.md——插件系统总体设计 (进程模型、能力位、确认模式、里程碑 P1–P6)
  • external-plugin-protocol.md——OPP/1 协议全文 (方法/事件/事务/shm/UI 的冻结定义,本文引用的 §n 均指该文档)

一句话:多模态 LLM 跑在一个独立插件进程里,经 OPP/1 的策展宿主 API 操作 Oak(事务化编辑、确认后执行),经 render.get_frame/get_thumbnails 的 shm 取帧通路把画面回喂模型,形成"编辑 → 看图 → 再编辑"的视觉闭环。


1. 定位与前提

1.1 前提(未满足不动工)

  • 插件系统 P1P3 完成:传输与生命周期、宿主 API 核心(事务 + project/media/timeline/node 方法族)、取帧与导出的 shm 数据面可用。
  • AI 面板需要 P4(声明式 UI);无头模式(脚本/CI)只依赖 P1–P3。
  • Python SDK oakxp(P6 的一部分)是本插件的载体,二者同期开发、互为验证。

1.2 设计铁律(继承旧版,按插件系统重述)

  1. AI Agent 只经 OPP/1 访问 Oak——插件进程内一行 Oak 代码都没有, 不链接任何 Oak 产物(铁律:协议是唯一边界)。
  2. 一切编辑动作必须包在 edit.begin/commit 事务里(协议 §6), 历史面板一次 Ctrl-Z 整段撤销;UI 默认"确认后执行"。
  3. 不为 AI 发明新的引擎内部机制;Agent 工具面是 OPP/1 方法的组合, OPP/1 方法又是现有 graphops/renderops/oak_task 的组合。
  4. API key 绝不写入 Oak 侧的任何文件(.ove 工程、Oak 自身配置); 允许存插件自己的配置文件(§5.1),环境变量仅作 CI/无头场景的覆盖项。

2. 总体架构

2.1 插件进程内部分层

插件名 oak-plugin-ai(Python 3,实现语言与发行形态的论证见 §2.3; 参考实现即插件系统的 examples/plugin-roughcut 的完整版):

┌─ Oak 主进程 ────────────────────────────────┐
│  oak-plugin-hostP1P4 提供)               │
│   ├ OPP/1 控制面(JSON-RPC over stdio      │
│   └ shm down/up 区域                         │
└───────┬─────────────────────────────────────┘
        │ stdio + shm
┌───────┴─── oak-plugin-ai(独立进程)────────┐
│ ⑤ LLMProviderClaude/GPT │ llama.cpp 本地    │
│ ④ Agent 编排:对话 loop、工具调用、视觉闭环    │
│ ③ 工具适配层:OPP 方法 → LLM tool schema     │
│ ② 会话状态:事务令牌、帧缓存、操作日志         │
│ ① oakxp SDK:分帧/收发/shm attach/帧→PNG     │
└─────────────────────────────────────────────┘
  • 插件可以纯无头跑(CI、批处理脚本:spawn 后不注册面板,只走工具面); 注册面板时才是用户可见的"AI 剪辑助手"。
  • MCP 的位置:如要让外部 LLM 客户端(Claude Desktop、agent 框架)直连, 由插件自己在进程内起一个 MCP server,把 §3 的工具面按 MCP 再暴露一次。 Oak 内核始终对 AI、对 MCP 无感知——这是与旧版"引擎内置 oak-mcp-server" 的根本区别。

2.2 视觉闭环(本设计的核心)

多模态 LLM ──► Agent 编排 ──► OPP 事务化编辑 ──► render.get_frame ──► PNG ──► 回喂 LLM
   ▲                                                                          │
   └────────────────── 看图判断(效果/切点/内容定位) ◄─────────────────────────┘
  • 验证式edit.commit 后立即 render.get_frame 取切口/效果帧,LLM 判断 "效果对不对",不对则 edit.undo 或追加修正事务。
  • 内容感知式render.get_thumbnails(range, count≤64) 等间隔采样拼 contact sheetLLM 扫图定位("人何时进画面""哪里该切"),据此下刀—— 自动粗剪/打点的雏形。
  • 连续回放playback.play + playback.playhead_moved 事件(≤30 Hz+ 按间隔 get_frame 采样。注意受 §12 限流约束(默认 8 帧/s),采样间隔 不得小于限流周期。
  • 完整报文流水示例见协议文档 §14(握手→缩略图→事务下刀→验证帧→事件), 可直接作为本插件的集成测试夹具。

2.3 实现语言与跨宿主复用(决策已定)

定为 Python,解释器嵌入式发行:插件包内含私有 CPythonPyInstaller 或 python-build-standalone),.oakplugin 单包交付,用户无需自行安装 Python。 插件以 GPLv3 开源发布;作为独立进程经 stdio/JSON-RPC 与 Oak 通信, 许可证选择不影响 Oak 本体。

选 Python 而非 Rust 的理由:

  1. 性能无关:插件只做协议编解码、LLM 编排、PNG 编码(Pillow 为 C 实现); 延迟大头是 LLM 往返(秒级)与 Oak 侧渲染(与插件语言无关),插件进程 没有任何重计算。
  2. 跨宿主复用:同一套 AI 能力规划覆盖 Oak / DaVinci Resolve / Premiere 但三家宿主的扩展 API 语言各异——Resolve 是 Python/LuaPremiere 没有 Python 入口UXP/JavaScript 面板 + C++ SDK)。因此正确结构不是 "一种语言通吃",而是一份与宿主无关的 AI core + 各宿主薄适配层
┌─ AI core(宿主无关,一份代码)───────────────┐
│  Agent 编排 / LLMProvider / tool schema      │
│  提示词策略 / 会话状态                        │
└──────┬───────────┬──────────────┬───────────┘
   Oak 适配层    Resolve 适配层   Premiere 适配层
   (OPP/1,       (Resolve         (UXP/JS 面板 →
    oakxp SDK)    Python API,      localhost 调
                  直接 import)     core 本地服务)
  • Oak 适配层 = oakxp SDKOPP/1),即本文的 oak-plugin-ai
  • Resolve 适配层直接 import corePython 母语,零成本复用);
  • Premiere 用 UXP 面板做壳,经 localhost 与本机 core 进程通信。
  1. 生态:主流 LLM SDKanthropic / openai / llama.cpp 绑定)均为 Python 一等公民,Agent 框架与评测工具链也最全。

3. 工具面(LLM tool schema → OPP/1 方法映射)

Agent 暴露给 LLM 的是约 20 个策展工具,每个是 OPP/1 方法的薄组合 (协议 §8 是方法全文,下表"OPP 方法"列即最终调用):

Agent 工具 OPP 方法 说明
open_project / save_project project.open/save 工程生命周期(事务 + 确认类)
get_project_overview project.get_info + timeline.get_structure 一次返回序列/轨道/块树,供 LLM 建立上下文
probe_media / import_footage / list_footage media.probe/import_footage/list_footage 媒体探测与导入
add_track / place_clip / split_clip / trim_clip / move_clip / ripple_delete / add_transition / add_marker timeline.* 时间线编辑,全部在事务内
add_effect / set_param / set_keyframe / list_effects node.add_effect/set_param/set_keyframe/list_types + get_params 效果与关键帧;get_params 的 min/max/choices 回填进 tool schema,约束 LLM 出参
get_frame(time) / scan_timeline(range,n) / get_audio_levels render.get_frame/get_thumbnails/get_audio_levels 视觉闭环取帧口
play / pause / seek playback.* 回放控制
export_render(preset) export.start + export.progress/done 事件 导出(确认类)
undo_last_action edit.undo 仅用户明确要求时调用(协议 §6 规则 5)

事务编排是适配层的职责,不暴露给 LLMLLM 的一次"动作"(可能含多个 timeline.* 调用)由适配层包成一个事务——先 edit.begin(label=LLM 动作摘要), 串行执行(协议保证同事务内按到达顺序),任一失败则 edit.abort 并把错误 回喂 LLM,全成功才 commit。LLM 看不到 txn 令牌,从根上避免"忘记 commit" "嵌套事务"这类误用。

取帧→PNG 通路(关键路径):render.get_frame 返回 FrameRefshm 形态: bgra8 + 槽位号),SDK frame.to_png()Pillow)编码 → base64 → 作为图片 消息发给 LLM;随后立即 shm.release——批量扫描时必须流水线化释放, 否则 8 槽耗尽触发 SHM_EXHAUSTED(协议 §10.3)。小图(≤64 KiBOak 可能 直接 inline PNGSDK 对两种形态透明。

4. AI 面板(声明式 UI,协议 §11.1)

面板在 session.hello.panels 声明 "ui":"declarative",控件树:

column
├── chat_log    #log      对话与操作日志(用户/助手/系统三角色)
├── list        #pending  待确认动作清单(确认模式,见 §5)
├── row
│   ├── text_input #prompt  剪辑意图输入
│   └── button     #send    执行
└── progress    #job      扫描/导出进度
  • 交互经 ui.event 上行(submit/click/select),插件用 ui.set_props 增量追加 chat_log 条目、更新进度。
  • "撤销整段会话":面板放一个按钮,逐个 edit.undo 回滚本会话提交的 事务(插件在自己的会话状态里记事务顺序)。
  • 面板被关闭会收到 panel_closed,重开收到 panel_shown 时重发 ui.set_tree 恢复(协议 §11.1)。
  • 像素面 UI(§11.2)本插件不用——聊天面板声明式足够。

5. 模型层与安全

5.1 LLMProvider

抽象接口(输入:消息 + 图片;输出:文本 + tool_calls),后端:

  • 云端 BYOKClaude / GPT 多模态,用户自带 key(效果优先)。
  • 本地llama.cpp 跑 Qwen-VL / LLaVA 类多模态模型(隐私、离线优先)。
  • 自定义 endpointOpenAI 兼容接口):把 provider 指向任何兼容 /v1/chat/completions 的服务(自建代理、企业网关等)——为后续接入 托管服务预留通用通路,不绑定特定厂商。

API key 存插件自己的配置文件(如 ~/.oak/plugins/oak-plugin-ai/config.toml), 面板提供密钥输入框(text_input),用户无需手配环境变量;环境变量只作 CI/无头场景的覆盖项(优先级:环境变量 > 配置文件)。配置文件权限 0600、 不进版本库。存插件自己的配置是插件的内部事务,Oak 不感知——铁律 4 约束的 只是 Oak 侧的文件。无 key 时优雅降级:面板仍可用,但只做"工具说明 + 手动执行",不做对话编排。

5.2 能力位与确认(协议 §7 的具体化)

manifest 声明最小必要集

capabilities = ["project.read", "media.read", "media.import",
                "timeline.read", "timeline.edit", "node.read", "node.edit",
                "render.frame", "playback", "export", "ui.panel"]

双层确认,职责分清:

  1. Oak 协议层(§7.3):timeline.edit 等确认类方法默认弹窗 "插件 oak-plugin-ai 请求:split_clip …"。用户可选"本会话内允许"。
  2. 插件会话层:Agent 把 LLM 规划出的整段动作先列入 #pending 清单, 用户点"执行"才发事务——这是体验层确认,与协议层弹窗不冲突: 建议插件引导用户在 Oak 侧对本插件设"本会话允许",确认交互集中在面板内。

5.3 其他安全约束

  • 限流遵守:扫描采样按握手 limits 下发的配额规划(默认 8 帧/s、 短边 ≤1080),收到 RATE_LIMITEDretry_after_ms 退避,不得重试轰炸。
  • 沙箱会话(可选增强):对破坏性大改,Agent 可先 project.save 副本到 临时路径操作,用户接受后再回真实工程。有了事务 + 整段撤销后,此项降为 可选,默认不启用。
  • 插件崩溃不丢编辑:已 commit 的事务都在 UndoStack 里,未决事务 Oak 自动 abort(协议 §6 规则 4)——AI 死在哪都不会留下半截剪辑。

6. 可测试(与项目风格一致)

  1. Mock LLM server:录制/回放 tool_call 序列与固定回复,Agent loop 在 CI 无 key 无网络跑通。
  2. Mock Oak(协议级)oakxp SDK 自带回放 harness——把协议文档 §14 的 报文流水当夹具,插件不连真 Oak 也能单测工具适配层与事务编排。
  3. 黄金帧校验:连真 Oak 的端到端测试复用 render-worker harness (真实渲染 ≥2 帧 + 像素非全黑 + 一致性断言),验证"Agent 的编辑确实 改变了画面"。
  4. 会话回放tool_call + 帧哈希落盘日志,可回放复现、可作测试夹具。

7. 里程碑(对齐插件系统 P1–P6)

里程碑 内容 依赖 验收
A1 骨架 oakxp SDK + 握手/心跳/重连;插件注册空面板 P1、P4 杀掉插件 Oak 不崩、面板徽标与重启正常
A2 工具适配层 §3 全表映射 + 事务编排(自动 begin/commit/abort+ 取帧→PNG 通路 P2、P3 Mock Oak 夹具全绿;真 Oak 上"导入→铺轨→切开→删除→加效果"可整段撤销
A3 无头闭环 Agent 编排 + LLMProvider + Mock LLM A2 CI 无网络跑通"LLM→工具→取帧→回喂";黄金帧校验过
A4 AI 面板 §4 面板 + 待确认清单 + 撤销会话 A3 真机对话粗剪一段素材,确认/撤销交互完整
A5 内容感知 contact sheet 扫描打点、自动粗剪策略、本地模型 provider A4 对 10 分钟素材自动出粗剪版,人工抽检切点可用

8. 风险与边界(明确不做)

  • 把 LLM/推理放进任何 Oak 进程或引擎模块(引擎对 AI 无感知); MCP server 如需存在,只在插件进程内。
  • 绕过 OPP/1 访问 Oak(协议是唯一边界);LLM 不直接接触 txn 令牌(适配层封装事务)。
  • 把 API key 写入 Oak 工程文件或 Oak 自身配置(插件自己的配置文件 除外,见 §5.1)。
  • 让取帧回路阻塞 Oak GUI 线程——render.* 本来就走引擎 ticket/进程池 路径(协议 §8.6),插件侧并发流水线化而不是串行等帧。
  • 突破协议限流;需要更高帧率的"连续回放分析"场景,先按 §13 版本 演进规则给协议加配额项,不在插件侧硬挤。
  • 第三方大模型客户端的接入细节(OAuth、计费、配额)超出本文范围 按需另立文档。