
把短剧创作搬进一张画布:Shortdrama Studio 开发手记
把故事、角色、镜头和素材放进同一张画布,再让 Agent、生成任务与协作围绕创作过程运转。记录 Shortdrama Studio 从想法到工作台的十来天。
我想做短剧的时候,最先遇到的不是“视频模型够不够强”,而是材料散得太快。
一段故事梗概写在文本里,角色设定另开一页,分镜又是一组提示词。参考图在文件夹,配音和视频有各自的生成入口。等某个镜头不满意,想回去改角色服装或调一句台词,已经很难看出这次修改会影响哪些素材。单次生成很容易演示,接着改、接着用、让别人接手,才开始像制作。
Shortdrama Studio 就是从这个问题长出来的。我给它设想的不是一个输入故事就吐出成片的黑箱,而是一张能放下创作过程的工作台:文字、角色、镜头、图片、音频、视频各占一个位置,能相互连接,也能看清哪些步骤已经完成、哪些还在排队。这个设想听起来简单,写进真实应用以后,却把我带进了数据、状态和协作的一连串细节里。
5 月上旬的十来天,我大部分时间都花在这张画布周围。一开始以为只要把创作步骤排好、把模型接进来,工作台就有了。真正动手之后,注意力慢慢从“怎么生成”移到“生成之后怎么继续做”。
一条链条,不是一只按钮
最初摆在我面前的是一条制作链:从项目描述和故事文本出发,提炼角色,拆出场景与镜头,再为镜头准备参考图、声音和视频。每一步都可能需要人工改写。角色设定不是最终答案,它还会变成后面图片或视频的上下文;一张图也不只是展示结果,还可能是下一个镜头的输入。
如果把这些东西塞进一张普通表单,填写时很整齐,修改时却容易失去来龙去脉。我因此把画布当成主工作区。项目有根节点;角色、场景或镜头、文字、图像、音频、视频可以成为不同节点;连线表达上下游关系。用户仍然能自己改文字、调整位置和提示词,不必只等 Agent 连续做决定。

这也改变了我对 Agent 的期待。我希望它能先读当前项目和画布,再补写故事、角色或镜头节点,必要时建立生成节点、连接节点、整理布局。它应该像一个在工作台旁边帮忙的人,而不是另一个与项目资料脱节的聊天窗口。于是 Agent 的入口放在画布右侧,默认可以收起;真正需要拆解创意或修改节点时再打开。
我也保留了几种很普通的手工动作:从素材库把资源拖进画布,选中节点后复制、粘贴或删除,摆错位置就撤销,改好后保存。做创作工具时,这些动作容易被“自动生成”的展示盖住,但它们决定了人能不能接住机器给出的半成品。一个角色节点写得不合适,最直接的处理应该是打开改,而不是整段流程从头再来。
首次体验入口放了一个 15 秒短故事草稿。它先出现在输入框里,用户可以修改,再让 Agent 把故事拆成可编辑的画布节点。这个过程比一上来展示空白画布更容易理解:先看见一段具体的戏,再决定哪里需要人物、镜头与画面。草稿也有本地预览版本,因此这一步主要是引导创作流程,不承担展示生成质量的任务。
让素材真的沿着线走
画布做出来之后,我很快发现一条线本身不够用。把图片节点连到视频节点,画面上当然像一个完整流程;但生成视频时,系统到底取了哪张图?当前模型接不接受它?这张图还在排队,还是已经能用?如果这些答案不在界面和任务里,连线就只是好看的箭头。
5 月 5 日,我把这件事收束为“素材槽位”。上游节点的图片、音频或视频会被识别成下游的输入槽位,并标出就绪、等待、缺失或不支持等状态。提示词框里能看到这些输入;服务端创建任务时,也要重新计算可用素材和生成模式。比如图片连到图片节点时应考虑参考图编辑,图片接到视频节点时应检查图生视频模式。模型不支持的素材,需要明确提示,而不是安静地扔给接口,等它报一个含糊的错。
这个改动看似只是提示词框多了几张缩略图,背后却横跨模型目录、前端画布、任务参数和处理器。它让我第一次比较清楚地感到:短剧工作台的难点在于让每次连接都变成可检查的输入。创作者需要知道正在用什么,也需要有机会在发送之前发现不对。
文字也有类似的来路。生成任务会解析提示词中对画布节点的引用,把那段文字带进本次上下文。写一个镜头时,可以引用前面整理好的设定,不必每次把角色外貌和故事背景从头粘贴一遍。不过引用越方便,越要让节点的标题和内容保持清楚,否则下游拿到的可能是过期版本。
我还为项目准备了素材库和 Prompt 文档。生成结果要作为项目资源留下来,才能被下一轮任务引用;Prompt 则不能只藏在一次请求里。画布和素材库是两种视角:前者看制作关系,后者看已经拿到手的东西。两边都需要,但我不想让用户每改一次镜头都在几个页面之间重新找文件。
这让我逐渐把“可继续编辑”看得比“一次出图”更重。短剧镜头很容易反复推敲:图出来了,可能只是构图对了,人物表情还不对;声音出来了,可能台词语气不合适。工作台需要保住已有的角色和镜头关系,让用户只重做有问题的一段。连线、槽位和素材记录解决的正是这种局部修改,而不是替创作者宣布整条链已经完成。
从“能发起”到“能回来”
接上生成服务后,真正消耗时间的不是第一次提交请求,而是请求之后的状态。
图片、配音、视频来自不同供应商,调用方式并不一样。有的同步返回内容,有的先给任务 ID,过一阵才能查询结果。处理器还需要把第三方结果整理成项目素材,再更新画布节点。一个按钮点下去,实际上跨过了前端、API、队列、外部服务、资源存储和数据库。任何一处断开,画布上都可能留下一个“排队中”或“生成中”。
5 月 5 日,生成任务接入 Cloudflare Queue,随后几天的提交几乎都围绕任务稳定性:排队任务怎么恢复,长时间图片任务的 lease 怎么算,流式响应如何解析,刷新页面后如何避免重复提交,失败重试时如何不把旧任务状态写回节点。这些提交标题不像“新功能”那样显眼,却更接近做产品的日常。一次成功的模型调用说明接口能通;一个任务在刷新、超时和重试之后仍能给出可信状态,才比较接近可用。
我遇到过特别绕的情况:新任务已经启动,画布的旧快照却还指向失败的 task ID;协作同步或保存过程又把旧状态覆盖回来。用户看到的现象只是按钮点了似乎没动,内部却是两套状态在互相争。后来的修复把任务表作为运行状态的依据,在读写画布时做对齐;复制项目也会清理原项目的运行态,避免新项目背着旧任务出发。
另一类问题来自模型接口的差异。文本或脚本节点面对兼容 OpenAI 的网关,可能拿到了内容,却因为返回结构不完全符合 AI SDK 的校验而失败;图片流有时没有预期的 SSE 头,也有单张图片输出和大体积内联数据的处理问题。处理这些差异,比在供应商列表里增加一个模型名字费心得多。
任务日志是我后来补的一面镜子。5 月 7 日的提交把运行事件持久化,让排队、接管、供应商请求、响应和错误能回看。此前一个失败节点可能只剩一句错误提示;有了事件链,至少可以判断问题落在哪一步。日志也刻意只存摘要,不把整段 base64 媒体塞进去。这不是一张漂亮的创作页面,却直接决定下一次故障能不能查明白。
我不太愿意让“失败”只是一块红色标签。对一段视频任务来说,排队失败、供应商拒绝请求、生成完成后素材发布失败,处理方式完全不同。前两种要检查任务和模型参数,最后一种可能需要处理产物保存。把这些阶段拆开以后,重试才有了前提:先弄清楚哪一段没有走完,再决定是继续等待、重新取结果,还是发起新任务。

当第二个人来到画布
单人操作时,画布状态问题已经不少。加上协作者,又多了一层:我移动节点的同时,别人可能在改提示词;Agent 也可能刚好新增节点。如果每个人只把本地整张画布覆盖到服务器,最后保存的人就可能抹掉别人刚做的事。
5 月 4 日的协作改动引入了权限、项目成员、画布实时同步和评论。主画布与评论分别维护协作内容;在线变化通过 WebSocket 传递,持久化仍要回到数据库。这不是为了让项目页面多几个头像,而是因为短剧制作里的反馈经常落在某个镜头或素材上。“这个角色脸不一致”“这里的环境音太满”,最好能留在相关位置,不要散落在一段无法定位的聊天记录里。
共享的 Agent 会话又带来并发问题。同一个项目的两个人如果同时发送消息,两个运行过程可能读到相同历史,分别写回,后写的覆盖先写的。项目为线程增加运行约束和协作更新信号,消息还要标出是谁发送的。这里我不得不接受一个取舍:同一线程不会无限并行地接收所有创作请求。宁可让后来的请求等一下,也要先保证会话历史和画布修改有一致的顺序。
但锁本身也会出错。Cloudflare Worker 的一次执行要调用模型、数据库和协作房间,外部请求次数会积累。5 月 5 日的问题记录写下了一次真实的坏循环:执行撞到 subrequest 限制,线程可能残留忙碌状态;用户重试,又遇到 409;前端还可能带着中断的工具消息继续发送。
后来我减少单次 Agent 工具步数,让已完成步骤尽量增量保存,并在重试时从最后一条用户消息重新走流程。复杂请求被切成更短的对话轮次,代价是用户可能需要多说一句,收益是系统不必靠一次漫长运行赌完全部步骤。
把入口移到创作本身
前面这些修补都指向同一个问题:用户打开应用后,能不能马上知道下一步做什么。
5 月 9 日,我把项目首页调整成以 Agent 为入口。它可以从创意开始引导,但最终还是要回到项目和画布。对第一次使用的人来说,直接面对一大片空白节点空间会有点无从下手;对已经有内容的人来说,聊天又不能吞掉现有结构。所以首页负责开头,画布负责承接和修改,素材库负责保存结果。三者之间的关系,比单独把任何一个页面做得热闹更重要。
后台也逐渐长出了任务、供应商和用户管理入口。这些不是创作者最先看到的部分,却决定服务能否长期维护。不同模型可用哪些模式、某个供应商是否启用、任务失败在什么阶段,都需要有明确位置查看。到 5 月 10 日,OpenAPI 文档和 SSE 流的 schema 也在反复调整。对我来说,这些调整提醒了一件事:Agent 看上去像一个自然语言界面,底下仍是一套需要清楚契约的 API。

5 月 12 日的两个提交又回到 Agent 面板本身,调整会话界面并恢复紧凑布局。这是一个很小但很实际的收尾:画布是核心,右侧助手不能因为功能变多就把创作空间挤没了。我希望它在需要时出现,完成任务后退回一边。
到这里,完成了什么
现在打开 Shortdrama Studio,可以从项目开始,在画布上组织文本、角色、场景和媒体节点;编辑节点、连线、保存,再去素材库找已有资源。Agent 可以读取画布、增改节点、连接节点和派发生成任务。生成链路有供应商目录、任务状态、队列和日志,协作与权限也有各自的位置。它已经有了工作台的骨架和相当多的实际交互。
但我还没有拿出一部能代表这套流程的完整实测作品。剧本、角色一致性、分镜、参考图、配音与视频片段,需要在同一个项目里从头走到底,才能判断哪里真省了时间。开发实验页和本地预览也只能用来观察界面;截图里的待运行卡片,不能算生成结果。片段质量、跨镜头人物一致性、成本与速度、多人长期协作,仍要靠真实任务回答。
尤其是“成片”这一步,工作台把文本和媒体生成步骤接到了同一条流程里,可靠的自动剪辑、完整时间线编辑和一键发布还不是它现在能交出的成果。不同模型的输出能否拼成观众愿意看完的短剧,仍要回到每个镜头的画面、声音和节奏上判断。
回头看这十来天,我对这个项目最满意的地方并不是接了多少模型,而是问题开始变得可见。创意能落到节点,素材能看到来源,任务失败能找到阶段,协作修改有权限和同步路径。它离“自动短剧工厂”还有距离,却已经比一个会生成几张图的演示页更像真正的工作台。
关于画布、素材槽位、任务队列和 Agent 协作的具体实现,我另写了一篇《Shortdrama Studio 技术设计:画布、Agent 与异步任务怎样协同》,展开记录这些边界怎样落到代码里。
接下来如果继续做,我想先选一个足够短、愿意公开的原创故事,完整走一遍:写故事,定角色,拆镜头,生成参考图与声音,再看视频片段能否按同一套设定接起来。把每一步的耗时、失败、人工修改和最终成片都留下来。只有这样,我才能回答最初那个问题:这张画布,究竟有没有让短剧创作变得更顺手。
