差不多两个月前,我开始有点受不了自己这种状态:想做短视频,结果晚上九点开始写脚本,写到十一点还没定稿,第二天剪辑又花一下午。明明是个技术人,却被重复劳动磨得没脾气。于是我用 LLM 搭了一套可编程的短视频管线,把“想一个主题”到“出一条成片”的整个过程,全部变成一条可以反复执行、随时调整、断点续跑的代码流水线。这篇文章就是把我踩过的坑、改过的方案、最后能用住的配置,原原本本写出来分享。它的核心价值不是“帮你做一个视频”,而是让你理解一个可编程的内容生产系统应该怎么设计:每一个环节由谁负责、数据以什么格式传递、出错怎么恢复、费用怎么控制。不管你是做科普号、产品号还是个人 IP,这套思路都能直接搬走。
1. 为什么要做“可编程”的短视频管线——整体设计与思路拆解
1.1 从“人肉流水线”到“代码流水线”:我的动机
先说动机。我是一个会写代码、懂一点视频剪辑的普通从业者,不是专业导演。过去我产出一条 30 秒的抖音口播视频,流程大概是:找选题、整理资料、写口播稿、录制或找配音、剪片子、加字幕、配 BGM。这中间最耗时的其实不是“剪”,而是“想”——脚本改来改去、素材找来找去、字幕对不上时间轴。
一开始我也纠结过:直接用现成的 AI 视频工具不就行了?但我很快发现,市面上大多数工具只能解决“某一个点”,比如帮你写个脚本,帮你做个数字人,帮你管一段字幕。没有一个工具能把“从选题到成片”这件事作为一个整体来编排,更别提让你自己控制中间的每一步、换成自己的素材库、接入自己的业务数据。所以我才决定自己搭一条管线。
所谓“管线”,本质上就是把上面那条人肉流程,拆成一连串有明确输入和输出的处理单元。每个单元做一件事,单元之间用统一的数据格式对接。人肉流程变代码流程之后,最大的好处是你可以随时替换任意一个环节:今天配音用 A 平台,明天可以换 B 平台;今天素材库用自己的截图,明天可以换成本地老电影资料库。这种解耦能力,是人肉操作给不了的。
1.2 “可编程”到底意味着什么:三层拆解
“可编程”这个词听起来有点玄,其实落到工程上就三层东西:配置层、调度层、执行层。
配置层很简单,就是一份参数文件,定义你这期视频要什么风格、多长、发在哪个平台、语气是正经还是活泼。我习惯用 YAML 或 JSON 来写,一部视频对应一份配置。调度层是管线的核心,负责读配置、调用各个执行器、把上一个环节的输出存下来传给下一个环节。它不关心内容怎么生成,只关心流程怎么走。执行层则是具体干活的东西:LLM 负责写稿和决策,素材检索模块负责找画面,渲染模块负责把文字和画面合成视频。
这么拆有什么好处?我举个例子。我原来的流程里有一个“配字幕”的环节,后来发现字幕样式在不同平台要求不一样,横版和竖版也不一样。我在可编程管线里把字幕渲染做成一个独立的执行器,只接收“字幕列表+样式参数”,输出就是带字幕的画布。以后无论抖音影视解说还是小红书竖屏教程,都是同一套逻辑,只是参数不一样。
这套结构和传统定时脚本最大的区别在于,它不只是“到点了自动跑一遍”的机械任务,而是有反馈、有判断、可以中途自我修正的工作流。你可以把 LLM 当成一个“会动脑子”的执行器,把传统的正则、FFmpeg、文件处理当成“不会动脑子但绝对可靠”的执行器,各司其职。
1.3 为什么主角是 LLM 而不是传统脚本
可能有人会问:既然都“可编程”了,那直接写死一个脚本模板不就行了,非要 LLM 干嘛?
这是个好问题。传统脚本的强项是“确定性操作”,比如把第 3 秒到第 8 秒的视频裁出来、把 BGM 音量压到 -20dB、把所有含“你好”的字幕换成“您好”。但生产短视频有一个绕不开的痛点:每个视频的内容都不一样,脚本要从哪来?选题要怎么写?素材怎么排布才能有网感?这些是没有固定算法的“模糊判断”,传统脚本完全做不了。
LLM 在这里的价值是“内容生成和决策”。它可以基于一个主题生成口播稿,可以基于一段文案自动拆出五个分镜,可以判断这段素材放开头更有冲击力还是放结尾更有余韵。我实际做的,就是让 LLM 输出结构化的“决策结果”,再用传统代码去执行这个决策。
有人会问:LLM 是不是深度学习?当然是。LLM 就是基于深度神经网络的大语言模型。但在我的这套管线里,我没有去碰训练和微调那部分,只是把它当做一个超强的内容引擎来调用。这就好比你去买菜,不需要自己会种菜,但你要知道哪种菜适合做什么菜,以及怎么跟菜贩子沟通。LLM 在我这里的角色就是那个“啥都懂一点的摊主”。
2. 核心模块细节解析与实操要点
2.1 第一层:LLM 担任内容创意与结构化生成器
整条管线的第一层,也是决定内容质量的一层,是让 LLM 做“创意生成”。但直接甩一句“帮我写个短视频脚本”是绝对不行的,输出不稳定,格式也乱七八糟。我采用的是“角色隔离+结构化输出”的方式。
角色隔离是说,在提示词里明确告诉 LLM:你现在不是通用助手,你是短视频策划,负责写分镜;另一个环节是解说词作者,负责把分镜转成口播。这样设计的原因是,同一个模型在一个上下文里同时扮演脚本作者、剪辑师、运营,特别容易把风格混在一起。拆开之后,每一段输出的质量都会明显更稳。
结构化输出则是硬性要求。我不允许 LLM 输出一段自然语言让我去“人工理解”,而是要求它输出一份约定好的 JSON 分镜表。每个分镜包含:镜头编号、画面描述、所需素材关键词、屏幕文字、解说词、预估时长、转场方式。我再写一个校验函数,检查 JSON 字段是否齐全、时长加起来是否符合总时长要求。如果不符合,就让它重新生成或人工修正。
这里有个关键经验:别指望一次生成就完美。我通常是“先生成初稿,再单独跑一次审稿提示词”,让 LLM 以剪辑师的身份检查脚本有没有逻辑断裂、有没有超时,然后给出修改意见。第二次调用价格很低,但换来的稳定性非常可观。
2.2 第二层:知识库与 RAG 检索——让素材不再靠脑补
光有文案不够,短视频特别吃“画面素材”。我发现很多 AI 工具生成的视频内容之所以假,是因为素材全靠模型想象,没有真实资料的支撑。我这一层引入的是“知识库+RAG 检索”方案。
我把自己的素材来源整理成两类:一类是本地资料库,比如产品手册、往期文章、行业报告、自己拍过的库存视频描述文档;另一类是公开的网页摘要,比如某个热点的来龙去脉。这些文本先切成片段,做好向量索引。当新的选题进来,我用 LLM 先提炼出“内容意图”和“检索条件”,比如这个视频要讲“中药处方审核”相关的几个注意事项,就直接去库里检索相关资料,把结果拼接到提示词上下文里。
这里呼应一下最近很火的 RAG 和 GraphRAG 思路。简单说,RAG 就是让模型在回答之前先去资料库查一遍,再基于查到的内容来生成。GraphRAG 则是把资料实体之间的关系也建立成图,回答“多个角色之间关系如何”这类问题时更准。但短视频场景下,普通 RAG 往往就够用了,因为口播内容本身不是深度的关系推理,更多是事实引用。我用得最多的是向量检索+关键词召回的双重策略:先向量检索出 20 条最相关的素材片段,再用传统关键词过滤掉跟当前主题完全没关系的,最终保留 5-8 条。
这一层还有个容易被忽略的价值:知识库能让你的内容形成“护城河”。别人用同样的模型,但素材库不同,生成内容的差异度和可信度就完全不同。比如给企业做产品介绍短视频,把你家 ERP 系统里产品参数、定价策略、应用场景整理进知识库,比让模型凭空编要实用得太多。
2.3 第三层:可控的渲染与合成——LLM 不碰像素
前两层负责“想”,这一层负责“做”。我的原则是:LLM 永远不直接碰像素、不直接碰音频文件,它只负责输出“怎么做”的指令,真正的合成交给专业工具去执行。
这个设计很关键。LLM 直接生成视频目前在可控性上仍然不理想,时长、字体、画面细节都容易翻车。而我用 LLM 输出的 JSON 分镜表,再映射到 FFmpeg 指令和模板上,就是完全可控的。
具体做法是,我准备了几套“视觉模板”:口播式模板、图文轮播式模板、影视解说式模板。每套模板本质上是 FFmpeg 滤镜图的参数配置,只留下可变部分,比如背景图、文字内容、字幕位置、时长。管线拿到 LLM 分镜表后,会按照模板的规则把每个分镜转成一条 FFmpeg 命令,最后把所有片段拼接成一个完整视频。
这里我要特别强调一下“模板引擎”的选择。我第一次做的时候,直接让 LLM 输出完整的 FFmpeg 命令行,结果十个里有七个渲染失败,不是引号没转义,就是滤镜顺序写错。后来改成让 LLM 只输出“素材路径、文字内容、时长、转场编号”,然后由我自己的代码去拼命令,失败率瞬间降到了基本为零。LLM 擅长做选择,不擅长做精确的语法拼接,这一点别跟它较劲。
素材这一块我也要说一下。很多人的素材文件命名非常随意,比如“IMG_0293.png”,这样的文件放进管线里等于没有。我给素材做了规范化命名:类型_场景_关键词_序号.jpg,比如“photo_ocean_sunset_01.jpg”。这样 LLM 分镜里只要给出关键词“ocean sunset”,我就能用简单的文件名匹配找到对应文件,完全不需要训练一个图像识别模型。
3. 实操过程与核心环节实现
3.1 从“一个主题”到“一条成片”:端到端一次跑通
理论说多了容易飘,还是来一个具体案例。我最近做了一条关于“如何快速搭建本地知识库”的 30 秒竖屏科普视频。输入只有一个主题词,参数配置是“时长 30 秒、画面风格科技感、口播语气干练”。
管线执行过程大致是四步。
第一步,主题扩展。LLM 拿到“如何快速搭建本地知识库”后,先生成一条 80 字以内的口播核心观点,并给出 8 个画面关键词,比如“文档导入”“向量化”“本地部署”“问答测试”。
第二步,分镜生成。它把 30 秒切分成 5 个分镜,每个分镜 6 秒左右,包含屏幕文字、解说词片段和素材关键词。这里有个我专门设定的规则:每屏只放一句话,字数不超过 14 个字,保证手机上看得清。LLM 输出后,我用校验函数检查总时长是否为 30±1 秒,如果有分镜超了 10 秒,就二次调用让它压缩。
第三步,素材检索。我本地素材库里恰好有早前录屏的几张截图和一张知识库架构示意图。检索模块根据“截图、知识库、界面”这些关键词在三秒钟内召回这几个文件,并把相对路径写进 JSON。
第四步,渲染发布。渲染模块读取 JSON,按模板拼出 FFmpeg 命令,把素材图逐帧合成画面、叠加屏幕文字、接入口播音频、最后再加一条 15 秒的 B GM 循环。整个渲染过程两分钟不到,最终导出一条 1080×1920 的竖版 MP4。我检查一遍成片后发现有一段画面比例不对,于是改了配置里“画面填充方式”的参数,重新跑一遍,没动任何代码。
能这么顺,核心在于中间产物全部是文件。每一步执行完,我都会把结果落盘:脚本写了 report_20230625.json,分镜拆成分镜_20230625.json,最终渲染日志存成 render.log。这意味着任何一步出问题,我只需要从失败的那一步重跑,不需要从头再来。
3.2 关键的 Prompt 模板与 JSON 契约
整个管线最值得抄作业的部分,就是让我反复打磨的那套“JSON 契约”和 Prompt 模板。直接分享一段我现在在用的系统提示词,注意它不是最终答案,但你照着搭第一版完全没问题。
你是短视频分镜策划。根据用户提供的主题和参数,输出一个 JSON 数组。 每一个分镜对象必须包含: - id: 数字,从 1 开始 - duration: 该分镜时长,单位为秒 - screen_text: 屏幕文字,不超过 14 个中文字符 - narration: 解说词,用自然口语表达,不要书面语 - visual_hint: 画面素材关键词,3-5 个英文或中文关键词,空格分隔 - transition: 转场效果,取值 subset of ["cut", "fade", "slide"] 额外要求: 1. 所有分镜的 duration 之和,必须等于目标总时长; 2. 解说词连起来朗读一遍,要符合“总时长 × 每秒 4.5 个字”的估算; 3. 不要输出任何 JSON 以外的文字,不要用 Markdown 代码块包裹 JSON。执行代码我一般用 Python,把 JSON 解析和校验写成两个函数,比如:
import json, re def parse_llm_json(raw: str): # 兼容模型偶尔用 ```json 包裹的情况 cleaned = re.sub(r"^```json|```$", "", raw.strip(), flags=re.M).strip() data = json.loads(cleaned) assert isinstance(data, list), "分镜应该是一个列表" return data def validate_shot_list(shots, total_time=30): errors = [] if abs(sum(s["duration"] for s in shots) - total_time) > 1: errors.append("总时长超出容差") for s in shots: if len(s["screen_text"]) > 14: errors.append(f"分镜 {s['id']} 屏文字超长: {s['screen_text']}") return errors这套“解析+校验+重试”的循环非常管用。如果校验函数报错,我就把错误信息拼一条新的提示词再喂给 LLM,让它根据错误修正。过程中我会加一个重试上限,比如 3 次是安全的,超过 3 次我就直接人工介入,避免无限调用浪费 token。
3.3 可编程管线的调度代码与断点续跑
前两步解决“单次调用”的问题,第三步解决“整个流程怎么串起来”的问题。我的调度脚本核心是一个状态机:每个任务有自己的唯一 ID,执行成功后写入完成标记文件。脚本启动时先扫描标记文件,只运行尚未完成的任务。
简化版逻辑大概是这样:
import os, json, subprocess from pathlib import Path STATE_DIR = Path("./state") STATE_DIR.mkdir(exist_ok=True) def run_step(step_name, func, *args, **kwargs): marker = STATE_DIR / f"{step_name}.done" if marker.exists(): print(f"{step_name} 已存在标记,跳过") return result = func(*args, **kwargs) # 执行成功才写标记 marker.write_text(json.dumps({"status": "ok"})) return result def step_script(topic): # 调用 LLM 生成口播稿 return llm_generate_script(topic) def step_storyboard(script): # 调用 LLM 生成分镜 return llm_generate_storyboard(script) def step_render(storyboard): # 调用 ffmpeg 渲染成片 subprocess.run(build_ffmpeg_cmd(storyboard), shell=True, check=True) def build_short_video(topic): script = run_step("01_script", step_script, topic) storyboard = run_step("02_storyboard", step_storyboard, script) run_step("03_render", step_render, storyboard) if __name__ == "__main__": build_short_video("如何快速搭建本地知识库")这看着简单,但就是这套机制帮我省了大量时间和 token 费用。以前跑一条管线,如果渲染步骤挂了,前面的 LLM 调用就白费了,还要重新花钱生成一遍。现在有了断点续跑,每个已完成步骤的结果都是落盘文件,重跑成本几乎为零。这也是“可编程”三个字落到我口袋里的最直接感受。
在调度层我还会调用一些“工具型”函数,比如检查 FFmpeg 是否安装、检查本地素材目录是否存在、检查磁盘空间是否足够。这些检查的成本非常低,但能避免跑到一半因为预料外的路径问题全盘崩溃。
4. 常见问题与排查技巧实录
4.1 模型不稳定:连续两次结果完全不一样
这是新手最容易懵的地方:同一个 Prompt,两次调用的结果完全不相关。第一次那组分镜特别惊艳,第二次却像换了一个人在写。原因很多,可能是模型自身的采样随机性,也可能是上下文长度变化导致注意力偏移。
我的处理方式分三层。第一层,在调用参数里把 temperature 调低,一般我在做脚本生成时用 0.3 左右,做创意发散时才会调到 0.8。第二层,给模型提供“锚定信息”,比如把上一轮某个人工改过的好分镜作为示例,告诉它“参考这个风格”。第三层,增加“自我一致性校验”的二次调用,让模型在多个候选里自己选一个最符合需求的。每次多花一点 token,但换来的是成片质量的稳定,非常划算。
这里还要提醒一句:如果同一套配置换个模型供应商就变样,不要急着改代码。先检查一下不同平台对 JSON 输出的支持程度,有的平台对“强制 JSON 格式”支持得很好,有的则需要你通过提示词强约束。我用过的最稳妥办法是,让模型先输出一个 JSON 字符串,然后在代码端用 json.loads 解析,解析失败再重试,不能让任何一步完全脱离校验。
4.2 请求失败与工具参数错误
“LLM request failed: provider rejected the request schema or tool payload.”这个报错,我用框架的时候遇到过好几次。表面意思是模型服务商把你传入的工具 Schema 给拒了,实际上是你的工具参数定义里可能包含了服务商不支持的类型、嵌套层级太深、或者 JSON Schema 格式不够严格。
我当时怎么排查的呢?先把所有工具参数简化:不用嵌套对象,全部改成顶层参数+扁平列表;去掉 Optional 类型标注,用 defaultValue 代替;禁止数组套数组,只在必要的时候保留一层数组。改完以后再调用同一个函数,问题基本消失。这个坑在“LLM 作为 Agent 调用外部工具”的时候特别常见,我一开始把工具的入参设计得像 REST API 请求体那么复杂,结果直接被拒。
另一个经常出问题的点是 Response Format。如果你明确要求了 JSON 格式输出,但服务商拒绝 schema,可以试试把要求写进提示词而不是参数里。虽然丑点,但兼容性极高。我是先试参数方式,不行了再退回提示词方式,两条腿走路。
4.3 素材库越来越大?给检索与合成加速的建议
素材库从几十个文件涨到几千个以后,新的问题出现了:每次渲染都要扫一遍素材目录,越来越慢;向量检索也会因为库里内容太杂,召回来一堆不相干东西。
我的优化思路是分层。第一层是索引层,给素材库建一个 JSON 索引文件,包含文件名、关键词、类型、尺寸、时长、使用次数。这样渲染时直接查索引,不需要遍历磁盘。第二层是检索层,向量检索和关键词检索并行跑:关键词召回速度快,适合精确匹配;向量召回覆盖长尾语义,适合“看起来像”的场景。两个结果取交集优先,如果交集太小,就把关键词召回的权重调高。
再一个加速技巧是:不要每次生成视频都重新调用 LLM。如果选题是固定的系列内容,比如“知识库系列”已经讲了三期,那么分镜结构、口播风格、画面模板都应该是复用的。我专门建了一个“风格快照”文件,里面保存了之前满意的脚本片段和 Prompt 模板,新的视频先检索最接近的历史案例,用历史案例作为 few-shot 示例,而不是从零开始。这让单条视频的 LLM 调用次数从十几次降到了五次左右,成本降了一半还多。
4.4 关于“LLM 是不是深度学习”的疑问
既然聊到模型层面,顺便把这个问题说清楚。LLM 当然是深度学习模型,它是一个超大规模的神经网络,靠海量文本训练出来的能力,本质是近似人类语言模式的概率分布。但在产品管线里,你不需要关心它内部是几层 Transformer 或者用了多少参数,你只需要把它看作一个“高能力内容引擎”。很多人一看到“大模型”三个字就觉得要会炼丹、要做训练,其实日常做应用层开发,最大的功夫在提示词工程、数据组织和流程编排上。这几个方面恰恰跟模型训练是两码事,但也恰恰是做出好落地的关键。
5. 落地心得与扩展方向
5.1 先跑通最小闭环,再逐步加细节
我必须坦白说,第一版管线只干了非常蠢的一件事:用 LLM 生成一个文案,再用固定的图片拼成一张 30 秒的图卡视频。画面上没有动效,连接词都没有,字幕还是卧底的。但就是这个最小闭环,让我把“调用 LLM 生成文案→解析 JSON→FFmpeg 拼视频”这条主链路彻底打通了。随后我每加一个功能,比如动态字幕、背景音乐、素材检索,都是在这个闭环上打补丁。如果一上来就试图做完整的智能剪辑系统,只会被各种细节拖死。
整个过程中最反直觉的体会是,真正拖慢进度的不是模型的笨,而是数据的脏。素材文件命名不规范、文本资料有大量重复和噪声、历史脚本没有一个统一的格式,这些问题会让你在管线调试时根本分不清是 LLM 错了还是数据错了。所以建议你先把资料整理成干净、带格式的输入,再让 LLM 发挥,它的效果会直线上升。
还有一点必须说,就是别把所有环节都交给 LLM。哪怕你发现有些纯逻辑的操作用 LLM 也能做,比如用提示词去统计 JSON 字段数,但传统代码做这件事只需要一行,速度更快、结果最准、还不花钱。我在渲染层、时间轴计算层、校验层用的都是硬编码规则,LLM 只在内容创作和决策的层面发挥作用。这样的分工让整个系统既聪明又牢靠。
5.2 下一步:从单条视频到内容矩阵的扩展
管线跑顺以后,我开始复制这条流水线到不同平台和内容类型上。给 B 站做横版知识区视频,只需要换一套配置和视觉模板;给企业做产品介绍视频,重点是接入了企业自己的知识库;给个人 IP 做口播号,则换了更口语化的提示词模板。本质上,所有视频都在走同一条管线,变的只是配置和素材库。
如果你也想搭一套自己的管线,我的建议是先从固定一个内容类型开始,比如“30 秒竖屏口播科普”,跑通后再做横向扩展。别一上来就追求覆盖所有视频类型,那会让你的调度层被各种分支逻辑压垮。好架构的秘诀是规律地重复,而不是一次性爆出所有功能。
最后再分享一个小技巧:给素材库的每个文件增加扩展字段“remark”,里面可以写一小段关于这段素材适合什么场景的批注。你随手写几个字,在后续检索时就会变成一条极其精准的“语义索引”。我后来把很多库存截图按照 remark 字段重新整理了一遍,检索命中率明显提升。这种工作不花什么钱,但对长期迭代很有价值。我的体会是,可编程管线的尽头不是把一切都自动化,而是把“内容灵感”和“工程纪律”接在一起。谁先打通这条链路,谁就能在短视频这条赛道上省下大把时间和精力,去做更值钱的事情。