
前段时间我发了一篇文章《一天生产 1000 条视频,AI 还是太好用了》不少朋友留言挺感兴趣,想了解一下应用了哪些技术点,今天我们就来简单聊聊。
从结果看,这个项目就是一个短视频模板。输入一句话,出来一条视频,似乎没什么特别。
但如果把项目拆开,你会发现它做的根本不是“视频模板”,而是用程序构建的一条完整的短视频自动生产线。
我现在这个项目,做的是“别再只会说”这一类英语表达短视频。比如在会议里反驳别人时,很多人会直接说You are wrong.,但更自然的表达可能是I don't think that's quite right.。系统会把这种内容自动组织成一条短视频:前面给场景,中间给对比,后面给替代表达和收尾文案,再自动配音、自动算时长、自动渲染。
1. 先别急着生成视频,先把内容变成“结构化数据”

一条数据对应一个视频
项目里,最关键的一步不是渲染,而是建模。
因为如果输入只是“一段自由文案”,后面所有步骤都会不稳定。但如果输入是一条结构化内容数据,程序就知道该怎么处理它。
这个项目里,一条内容大概长这样:
{ "context_zh": "开会想反驳同事时,别再只会说", "wrong": "You are wrong.", "better": "I don't think that's quite right.", "why_zh": "先降对抗再讲观点,对方更愿意听下去。", "alternatives": [ "I'm not sure that's correct.", "I see it differently." ], "tone_tags": ["polite", "soften-disagreement"], "difficulty": "A1-A2"}
这段代码其实不复杂,但它特别重要。
你可以把它理解成一张“视频菜谱”:
-
context_zh 是场景
-
wrong 是常见但不够地道的表达
-
better 是更好的表达
-
why_zh 是解释
-
alternatives 是补充表达
-
tone_tags 和
difficulty决定内容风格和难度
一旦内容先被做成这种标准件,后面的 AI、配音、时长、渲染,才有可能稳定接上。
所以这类系统的第一原则不是“让 AI 很会写”,而是“先把内容定义清楚”。
2. AI 不直接生成视频,而是先生成“合格草稿”
很多人会想,既然都用了 AI,为什么不直接一句话让它输出成片?
因为那样虽然看起来省事,但很难控。
这个项目里,AI 干的事情不是“直接做视频”,而是先产出候选内容草稿,而且这些草稿不是随便写的,是有字段约束的。
服务端给模型的要求,核心大概是这样:
[ "请生成“别再只会说”系列视频的候选数据。", "每个元素字段必须是:title_zh, context_zh, wrong, better, wrong_reasons_zh, better_reasons_zh, why_zh, alternatives, tone_tags, difficulty, cta_zh, tts, scene_timing_sec, enabled。", "wrong 和 better 不能相同;tone_tags 只能从固定枚举里选择;tts.speed 在 0.7 到 1.3 之间。", "请直接输出 JSON 数组。"]
这段提示词的重点,不是“写得多优美”,而是“把输出限制成程序能消费的格式”。
也就是说,AI 在这条链路里更像一个“候选内容生成器”,不是一个拥有最终决定权的创作者。它先把草稿交出来,系统再做校验、去重、筛选,然后再进入下一步。
这就是为什么这类项目能比“纯 AI 一把梭”更稳定。不是因为模型多强大,而是因为它被放进了一个规则明确的系统里。
3. 配音不是最后补的,而是先参与时间轴计算(手动划重点!!!)
很多人做视频时,默认思路是先排版,再补配音。
但程序化视频正好反过来。
在这个项目里,文案确定之后,会先走 TTS,也就是文本转语音。现在接的是火山引擎的 TTS。每个视频被拆成 3 段:开头、核心说明、结尾,每段各自生成音频文件。
生成音频之后,项目不会直接渲染,而是先测音频时长,再把它换算成视频帧数。
代码逻辑非常直接:
12const sec = await audioDuration(audioFile);scene.durationFrames = Math.ceil((sec + 0.25) * FPS);
这两行代码很短,但很能体现工程思路。
意思是:
- 先拿到真实音频长度
sec - 再补一点安全留白
0.25 - 最后乘上视频帧率
FPS - 得到这一段画面应该持续多少帧
为什么这一步关键?
因为视频最终顺不顺,靠的不是“设计感”,而是声画是否同步。声音没说完,画面先切走,会很怪;声音结束了,画面还停着,也会很怪。
所以这个项目不是先写死一个时间轴,而是让“真实音频”反过来决定“画面时长”。这一步很像工业生产里的“反向校准”。
4. Remotion 的价值,不是做动画,而是“用代码装配视频”
等到数据和时间轴都准备好,才轮到 Remotion 上场。
如果一句话解释 Remotion,我会说:它是“用 React 写视频”。
这个项目里,视频本身是一个 React 组件。它接收一条item 数据,然后按这条数据决定字幕、卡片、背景、动画和音频怎么出现。
入口代码其实很直白:
<Composition id="StopSayingVideo" component={StopSayingVideo} fps={30} width={1080} height={1920} schema={stopSayingVideoSchema}/>
这段代码哪怕不懂 React,大概也能看明白:
-
component 指向真正的视频组件
-
fps={30} 表示每秒 30 帧
-
width 和
height定义了竖屏尺寸
-
schema 用来约束传入数据的结构
它背后的意思是:视频不是在剪辑软件里手工拼出来的,而是像页面一样,通过组件和数据渲染出来的。
这会带来一个特别大的好处:同一套画面模板,可以批量吃不同的数据。你只要换内容,不用一遍遍手工重做视频。
5. 真正让它变成“内容工厂”的,是批量工作台
如果项目只有数据、TTS、Remotion,它已经能做视频了,但还不够“生产化”。
真正把它变成生产系统的,是后面的批量工作台。

视频生产工作台
它可以做几件事:
- 输入主题,先生成候选内容
- 加载已有素材,避免重复造轮子
- 勾选要生产的内容
- 一键提交任务
- 自动执行整条流程:生成计划、生成语音、测量时长、渲染视频
- 最后返回状态、日志和输出文件
提交任务的接口也很像一个真正的生产系统:
1234await createStepRunner(jobCtx, "build-plan", () => runner.runBuildPlan())();await createStepRunner(jobCtx, "gen-voiceover", () => runner.runGenVoiceover({ ids }))();await createStepRunner(jobCtx, "measure-timing", () => runner.runMeasureTiming({ ids }))();await createStepRunner(jobCtx, "render-video", () => runner.runRender({ ids }))();
这段代码我很喜欢,因为它特别能说明这个项目的本质。
它不是“生成一个视频函数”,而是一个有步骤、有状态、有日志的流水线。每一步都可以单独追踪,也可以整体编排。到这个层面,它就已经不是“脚本工具”,而更像一个轻量内容工厂了。
最后想说的
如果让我用一句话总结这个项目,我会说:
它不是在用 AI 直接生成视频,而是在用工程化的方法,把视频生产拆成一个可控系统。
先结构化,再生成草稿,再做配音,再用音频校准时间轴,最后交给 Remotion 渲染,再通过工作台实现批量化。这条链路看上去比“一句话出视频”麻烦,但恰恰因为多了这些步骤,结果才更稳定,也更容易扩展。
而且这种思路并不只适合英语口语号。
只要你的内容能先被拆成标准化字段,这条方法论就能迁移到很多场景里,比如知识切片、口播科普、产品演示、培训视频,甚至企业内部内容系统。
所以我觉得,这个项目真正值得分享的,不是某个炫酷功能,而是一种很朴素、但非常有效的方法:
先结构化,再自动化,最后批量化。
AI 内容生产真正开始变得可靠,往往就是从这里开始的。


