AI视频流水线实战:用蓝耘元生代和Remotion实现一条命令自动出片
最近我把“每天做一条技术新闻视频”这件事彻底外包了——不是外包给某个剪辑师而是外包给一条由我自己写的 AI 流水线。早上到工位双击运行一个脚本然后去倒杯咖啡回来的时候一条带配音、字幕、动态画面的技术新闻视频已经躺在输出目录里了。整套方案的核心就两个东西蓝耘元生代负责 AI 写稿和语音合成Remotion 负责把文案渲染成视频。一条命令出成片不是 demo是我已经跑了一个多月的日常流程。这篇文章把这条流水线从零到一的完整思路、代码骨架、参数选型和踩坑记录都摊开讲一遍。如果你是做内容、做自媒体、或者单纯想给自己的技术博客配个视频版本这篇应该能帮你省掉至少一个月的摸索时间。1. 整体设计从“手动剪片”到“代码流水线”先说说我为什么要这么折腾。做技术新闻视频最烦的其实不是剪辑本身而是每天重复同一套流程找选题、写文案、录音、找素材、剪片子、加字幕。这套流程我手动做过一条三分钟的视频从搜集信息到导出成片最快也要两个小时。而且内容越做越多时间成本根本不是线性的是在累加。所以我想得很清楚与其每天花两小时做这件事不如花两周时间把两小时压缩成一条命令。这个思路本质上就是“内容工厂化”——把创意工作里的重复劳动全部交给代码和 AI人只负责定规则和抽查质量。1.1 为什么选“蓝耘元生代 Remotion”这套组合先说结论这套组合的匹配度很高原因是它们分别解决了两类完全不同的需求。蓝耘元生代这个平台我主要用的是它的大模型生成能力和语音合成接口。写新闻口播稿需要大模型来做信息重组和口语化改写配音需要高质量的 TTS。这些能力如果自己搭要么模型效果跟不上要么语音合成听着像机器人。云端 API 的好处就是省事而且效果稳定不用本地 GPU 也能跑。Remotion 则是一个用 React 写视频的框架。它和传统剪辑软件最大的区别是视频里的每一帧、每一个字、每一张图都可以用代码精确控制。这意味着我可以把视频模板当成一个普通的前端组件用 Git 做版本管理用参数控制每一期内容然后通过命令行自动渲染。传统视频模板要改一个字幕位置得打开软件拖半天在 Remotion 里改一个 CSS 数值就行。关键点是这两者是互为上下游的关系。蓝耘元生代提供“内容生成”能力Remotion 提供“视频合成”能力。我把它们串起来中间用 JSON 作为数据传递格式就得到了一个完整的自动化流水线。1.2 流水线整体架构一览整套流程可以拆成四个环节信息采集从多个新闻源抓取当天技术圈的热门话题。文案生成把原始信息喂给大模型生成适合口播的新闻稿。语音合成调用蓝耘元生代的 TTS 接口把文案变成音频。视频渲染把文案、音频、画面模板交给 Remotion输出成片。一条命令的本质就是把这四个环节按顺序串起来。每个环节产生一个中间产物下一个环节消费上一个环节的输出。这样做的好处是任何一个环节挂了或者效果不满意我可以单独重跑那一段不用整条流水线从头再来。提示在设计这种自动化流水线时我强烈建议把中间产物都落盘不要用内存变量传来传去。这样出了问题时你可以直接检查某个环节的输出文件快速定位问题在哪。2. 信息采集与选题让 AI 先筛一遍信息新闻视频最怕的不是没素材而是素材质量差、信息重复、或者全是旧闻。所以采集端不能只挂一个 RSS 完事要做轻量级的去重和热度筛选。2.1 新闻源的选取原则我跑了一段时间后发现技术新闻的采集源需要满足三条标准更新频率高、内容垂直、信息密度大。分散在不同社区的源有一个好处就是话题覆盖面广AI 在写稿时可以有选择余地能挑出真正有信息量的新闻来讲。目前我主要用这几类源技术社区热门仓库的每日趋势。头部技术媒体的 RSS 订阅。优质开发者社区的每日热榜。这些源的共性是可以直接通过 HTTP 抓取或标准 RSS 解析获取不需要跟平台签复杂的授权协议。抓取频率也不用太高一天早晚各一次就够了技术新闻不像财经新闻那样以秒级更新。2.2 用脚本做一次粗筛在把新闻喂给大模型之前我会先用代码做一次粗筛。这一步非常重要能省下大量 token也让最终生成结果的质量更可控。粗筛的逻辑很简单过滤发布时间只保留 24 小时内的内容。过滤标题长度标题过短的直接丢大概率是无效噪音。关键词过滤剔除明显不相关的类型比如纯招聘类、纯广告类内容。这里有一个经验不要把原始全文都塞给 AI。一方面 token 成本高另一方面信息太杂反而会干扰大模型的总结能力。我把每条新闻处理成“标题 摘要 链接”的三元组摘要控制在 150 字左右这个体量足够 AI 理解上下文又不会造成信息过载。import feedparser from datetime import datetime, timezone import requests from bs4 import BeautifulSoup # 伪代码抓取 RSS 并做基础清洗 def fetch_news(feed_url): feed feedparser.parse(feed_url) entries [] for item in feed.entries[:30]: title item.get(title, ).strip() summary BeautifulSoup(item.get(summary, ), html.parser).get_text() pub_date item.get(published_parsed) if not title or not summary: continue if len(title) 10: continue if is_old(pub_date): continue entries.append({ title: title, summary: summary[:150], url: item.get(link, ), }) return entries2.3 选题策略给 AI 一个“选题框架”每天的热点新闻可能有一二十条但视频只有三分钟顶多讲三到五条。所以我还给大模型加了一道“选题指令”让它按重要程度排序而不是随机抽几条。我常用的选题框架是优先选有明确技术突破的内容新版本发布、核心架构调整。其次选对开发者有实际影响的框架更新、工具链变化。最后选有讨论度的非技术新闻但不涉及敏感话题。这道指令看着简单实际效果提升很大。没有指令时AI 经常选一些无关痛痒的热搜词加了框架之后选出来的内容明显更像是“技术新闻”而不是“娱乐八卦”。3. 文案生成与配音蓝耘元生代的核心用法采集完原始素材就到了整条流水线里最依赖 AI 能力的环节把新闻改写成口播稿然后合成自然的人声。这一步我全部通过蓝耘元生代的接口来跑自己的代码只负责组装请求和解析结果。3.1 用大模型生成口播稿的提示词设计口播稿和文章的写法完全是两回事。文章可以信息密度高句子紧凑口播稿必须留出呼吸感句子要短逻辑衔接要顺最好还能有一点拟人的语气词。我的提示词经过了好几轮迭代目前的版本大概长这样你是一位资深科技新闻主播的撰稿人。 请根据以下新闻素材写一段 3 分钟左右的口播新闻稿。 要求 1. 开头用一句有吸引力的话引入当天主题。 2. 每条新闻先讲结果再讲背景最后讲影响。 3. 句子要短口语化适合朗读。 4. 不要使用生僻英文缩写必要时给出中文解释。 5. 最后加一句收尾引导观众关注后续内容。 素材如下{news_json}这段指令里最重要的一段话就是“先讲结果再讲背景最后讲影响”。很多 AI 写出来的技术新闻稿喜欢按“背景前置”的方式写先铺垫一大堆历史最后才说正题这放在口播里很劝退。用这个框架后成稿节奏明显更紧凑。3.2 控制时长和断句节奏视频时长得跟音频长度匹配。Remotion 渲染时是按照音频时长来计算视频长度的所以文案长短直接决定成片快慢。我的经验是中文口播语速大概在每分钟 240 到 280 字之间。三分钟的视频文案控制在 800 字左右最稳妥。为了让音频断句更自然我还会在文案里预留标点符号尤其是句号和逗号不能省。TTS 引擎对逗号会做短停顿对句号会做长停顿。如果文案全是长句就算 TTS 效果再好听起来也会喘不过气。生成完文案之后还要做一个轻量校验检查字数是否在目标区间检查有没有过长的句子检查有没有重复段落。这个校验可以用简单的脚本跑不需要 AI 参与。3.3 调用语音合成接口的要点蓝耘元生代的语音合成接口调用方式比较标准传一段文本指定音色和格式返回音频文件。我挑选 TTS 音色时主要试了三种维度清晰度、自然度、稳定性。清晰度指是否吞字自然度指语气是否生硬稳定性指同一个音色在不同时间合成出来的效果是否一致。合成时有个细节坑如果整段文案一次性传给接口音频文件会很长万一中间某句话说错了整个文件都要重合成。所以我按段落切分每一条新闻单独合成一段音频最后再用工具拼接。这样某一段效果不好只需要重跑那一小段。import requests # 伪代码调用蓝耘元生代语音合成接口 def tts(text, output_path): resp requests.post( https://api.example.com/v1/audio/speech, headers{Authorization: fBearer {API_KEY}}, json{ model: tts-model-name, input: text, voice: zh-CN-News-HD, response_format: mp3, speed: 1.0, }, timeout60, ) if resp.status_code 200: with open(output_path, wb) as f: f.write(resp.content) else: raise RuntimeError(fTTS failed: {resp.status_code} {resp.text})参数里我单独说一下speed。技术新闻我推荐用 1.0 到 1.05 之间的语速太慢像念课文太快又容易让听众漏掉关键信息。1.0 是一个比较稳妥的默认值。3.4 本期画面素材的生成逻辑视频里不能只有一个静止背景加字幕那样太单调。我最初的版本是用随机渐变背景后来发现视觉变化不够。后来又加了一个步骤让蓝耘元生代的图像生成能力根据每条新闻生成一张封面底图然后用这张图做背景配合渐变遮罩保证文字可读性。这个方案的逻辑是每期新闻都不一样如果背景图也是自动生成的视频的“新鲜感”会强很多。生成提示词我通常这样写科技感插画主题为【主题词】深色背景简洁构图主体居中留出上下字幕安全区域。然后我会把生成的图片缩放到 16:9 分辨率再压暗处理。这里有个细节压暗操作必须在模板层做不能依赖原始图片。因为图片生成的效果不可控直接叠原图很可能出现文字看不清的情况在模板里盖一层半透明黑色遮罩才是稳妥方案。4. Remotion 模板用 React 把画面“写”出来如果说蓝耘元生代是流水线的“大脑和声音”那 Remotion 就是流水线的“手和画笔”。所有画面元素——字幕、图片、配音波形、切换动画——都在 Remotion 模板里定义。4.1 为什么推荐用代码写视频传统视频剪辑软件的思路是“时间轴 素材轨道”你得手动把素材拖进去、对齐、裁剪。Remotion 的思路完全不同视频的每一帧都是一个 React 组件渲染出来的结果。所有内容由数据驱动文案换一批、图片换一批出来的视频自然也跟着变。用代码写视频还有一个隐藏好处版本可控。我的视频模板是存在 Git 仓库里的哪次改动导致画面变了diff 一看就知道。传统剪辑项目文件基本没法 diff出了问题只能靠记忆回退。4.2 模板结构怎么设计我的视频模板结构分成三层片头层展示期号和当天日期配一段短动画。新闻层每条新闻一屏包含标题、摘要、背景图。片尾层引导关注和预告次日内容。新闻层的排列顺序和展示时长由上一步生成的 props 文件控制。我定义的 props 大概长这样{ date: 2025-01-01, title: 科技新闻日报, items: [ { id: 1, title: 某框架发布新版本, summary: 该版本引入了新的编译机制构建速度提升明显。, image: assets/news1.png, durationInFrames: 180 } ] }每个durationInFrames表示这条视频片段占多少帧。在 30fps 的项目里180 帧就是 6 秒。这个值我是根据对应音频的时长算出来的公式很简单总帧数 音频时长秒 * 30为了保证画面和声音完全同步我渲染前会把每个新闻音频的实际时长读出来回填到这个 props 里而不是拍脑袋填一个固定值。4.3 写一个最简单的新闻视频组件下面是一个极简的 Remotion 组件骨架它做的事情是根据 props 里的内容渲染标题和摘要文字并在帧数到达某个阈值时做一次简单的淡入。import {AbsoluteFill, interpolate, useCurrentFrame, useVideoConfig} from remotion; import {z} from zod; const newsSchema z.object({ date: z.string(), items: z.array(z.object({ id: z.number(), title: z.string(), summary: z.string(), image: z.string(), })), }); export const NewsVideo: React.FCz.infertypeof newsSchema ({date, items}) { const frame useCurrentFrame(); const {fps, durationInFrames} useVideoConfig(); const opacity interpolate(frame, [0, 15], [0, 1], { extrapolateRight: clamp, }); const currentItemIndex Math.min( Math.floor(frame / (durationInFrames / items.length)), items.length - 1 ); const current items[currentItemIndex]; return ( AbsoluteFill style{{backgroundColor: #0f1115}} AbsoluteFill style{{opacity}} h1 style{{color: #fff, fontSize: 48, margin: 60}} {current.title} /h1 p style{{color: #ccc, fontSize: 28, margin: 40}} {current.summary} /p /AbsoluteFill /AbsoluteFill ); };这个组件故意写得非常简单但已经能说明核心逻辑了frame是当前帧的编号useVideoConfig可以拿到视频的总帧数和帧率interpolate用来做数值映射。纯前端 React 的技能直接平移过来就能用学习成本主要在理解“帧”这个概念上。4.4 中文字体和隐藏播放头的处理用 Remotion 做中文视频有两个必须提前处理的问题。第一个问题是字体。Remotion 在浏览器环境里渲染但渲染用的无头浏览器不一定安装了中文字体如果不指定字体你会看到满屏方块。解决方法是把字体文件放到公共资源目录然后在组件里用 CSSfont-face加载。我用的是一种开源的思源黑体子集文件不大而且清晰度不错。font-face { font-family: MyNewsFont; src: url(/fonts/NotoSansSC-Regular.otf) format(opentype); font-weight: 400; }第二个问题是播放头闪烁。在开发模式里预览时Remotion 会显示时间轴播放条渲染视频时不会出现。但如果你在某一步把浏览器也打包进去了可能会多出播放控件。我后来把所有视频组件都用remotion/player封装然后用命令行直接渲染整个过程没有人工干预这个坑自然就绕开了。4.5 渲染性能和并发优化Remotion 渲染视频是逐帧渲染的初期很慢一条 3 分钟的视频可能要跑十几分钟。后来我发现可以开启并发渲染把每一帧拆给多个 worker 同时处理。说实话直接把并发数拉太高也不会有无限收益显卡和 CPU 的资源是有限的。我目前的配置是并发 4帧率 30分辨率 1920x1080一条三分钟的视频大约在五分钟左右能渲染完成。如果机器性能好并发调到 8速度还能再快一些。但我不建议无限拉高因为渲染到一半如果内存溢出前三分钟就白跑了还不如稍微稳一点。5. 一条命令编排全流程脚本设计与运行日志整个流水线的最后一个环节是把上面所有模块串成一个可重复执行的命令。这里不是简单地把几个命令用连起来而是要处理好异常退出、中间产物检查、重试逻辑等细节。5.1 入口脚本设计我用的是 Bash 脚本作为总入口。里面对每一步执行完都做了断言如果某一步失败脚本立即停止并输出日志这样我不会在第二天早上拿到一条只做到一半的视频。#!/bin/bash set -e DATE$(date %Y%m%d) OUT_DIRout/$DATE mkdir -p $OUT_DIR echo [1/5] 抓取新闻... python scripts/fetch_news.py $OUT_DIR/raw_news.json echo [2/5] 生成口播稿... python scripts/generate_script.py --input $OUT_DIR/raw_news.json \ --output $OUT_DIR/script.md echo [3/5] 合成语音... python scripts/tts.py --input $OUT_DIR/script.md \ --output $OUT_DIR/audio.mp3 \ --metadata $OUT_DIR/audio.json echo [4/5] 构建渲染参数... python scripts/build_props.py --audio $OUT_DIR/audio.json \ --script $OUT_DIR/script.md \ --images assets/covers \ --output $OUT_DIR/props.json echo [5/5] 渲染视频... npx remotion render src/index.tsx NewsVideo \ $OUT_DIR/daily-$DATE.mp4 \ --props$OUT_DIR/props.json \ --codech264 echo 完成$OUT_DIR/daily-$DATE.mp4这段脚本的逻辑很直白但里面有三个细节值得注意。第一set -e必须开。没有它某个环节失败时脚本照样往下跑最后的成片会是缺素材的废片。第二日期用20250101这种纯数字格式方便排序和归档。文件名里带上日期以后找出某一期的素材会很方便。第三图片目录assets/covers是提前由图像生成脚本产出并缓存好的。如果某期不需要重算封面图可以跳过那一步直接复用。这属于压缩成本的细节。5.2 定时任务的配置一条命令手动跑还不够我的目标是每天早上自动出片。我用的是系统的定时任务每天早晨八点触发脚本。这个时间点我已经实际跑了一个多月没有碰到严重的稳定问题。定时任务最关键的是环境变量。脚本里所有 API Key、密钥都是从环境变量读取的。配置定时任务时不要.bashrc里的环境变量因为定时任务并不会加载 shell 的交互配置。我是在脚本开头显式引入一个项目专用的.env文件确保无论何时运行都能拿到正确的配置。set -a source .env set a这里用set -a的原因是如果直接source .env里面的变量可能只在当前 shell 有效不会传给子进程。加上set -a后所有变量会自动导出到子进程环境Python 脚本和 Remotion 渲染进程都能读到。5.3 运行日志的可观测性自动化脚本跑得越多越需要日志。我的方案很简单所有终端输出都重定向到logs/daily-$DATE.log这样哪天视频出了问题我可以直接看日志定位是哪一步挂了。bash run.sh logs/daily-$DATE.log 21日志里我会打印每一步的耗时和输出文件名。别小看这些信息跑了十几天后如果你发现渲染时间突然从五分钟变成十分钟有了日志就可以对照找出到底是新闻条数变多还是机器变慢。5.4 成本预估这笔账值不值我知道很多人关心自动化流水线的成本。我的经验是这样蓝耘元生代的大模型调用按 token 计费一天新闻稿加选题指令大概消耗的 token 量并不多。语音合成按字符计费一段三分钟音频一个月下来也是一笔可以忽略的数目。图像生成是最费钱的如果一天生成三到五张封面一个月累积起来还是挺可观的。所以我做了一个折中封面图不是每天重新生成而是使用历史素材库里的图片。遇到没有合适图片的新闻再从素材库中选一张主题相近的。这样图像生成成本可以压缩到一个很低的水平。注意AI 生成图片质量不稳定如果直接拿原图做背景有些图可能完全没法看。我的模板里对图片做了高斯模糊和暗化处理相当于“兜底”。就算素材图不完美视频画面也不会太突兀。6. 常见问题与排查技巧实录自动化流水线跑一个月不踩坑是不可能的。这里把最典型的几个问题整理出来按症状、原因和解决方式列成速查表方便你以后直接对照。6.1 字幕文字溢出或截断症状长标题在画面上显示不全或者字幕换行后超出安全区域。原因视频画幅是 16:9但新闻标题长短不一。我最初用固定字号两条超长标题一撑开就崩了。解决在渲染前对标题做长度检测。如果标题超过 24 个字符就自动缩小字号或强制截断并在模板里用text-overflow: ellipsis做兜底。更重要的是我在写口播稿时就要求 AI 控制每条标题长度而不是生成后靠 CSS 硬扛。const fontSize title.length 24 ? 32 : 48;6.2 音频时长和视频画面不同步症状第一条新闻讲完了画面还是上一条的背景图。原因严格说这不叫 bug是我最早没有动态计算帧数。每条新闻的音频时长不一样但我给所有片段设了相同的帧数导致错位。解决在tts.py里合成音频后读取每个段落音频的真实时长写进props.json的durationInFrames字段。这条逻辑补充后画面和声音的同步问题彻底消失。6.3 API 偶尔超时导致流水线中断症状跑着跑着某一步提示网络超时或连接重置。原因云端接口偶尔会有抖动跟具体平台无关这是调用云端 API 的常态。解决我对所有远程请求都做了重试逻辑。第一次失败后等三秒重试最多重试三次。如果三次都失败脚本才真正退出。加了重试后我连续三十天没有因为接口超时中断过。def request_with_retry(func, retries3, delay3): for i in range(retries): try: return func() except Exception as e: if i retries - 1: raise time.sleep(delay)6.4 视频画面出现乱码或字体不一致症状字幕里偶尔出现缺字或少笔画的情况。原因中文字体文件是子集字体只包含了常用字。新闻里出现生僻的人名或技术术语时子集字体里没有这个字形渲染就会出问题。解决把字体换成完整版的现代中文黑体并统一设定为视频组件里的全局字体。代价是字体文件体积大一些加载时间稍长但换来的是一年四季都不会乱码的稳定效果。6.5 AI 输出格式不稳定导致解析失败症状某一天脚本在解析口播稿时崩溃报 JSON 解析错误。原因我让大模型输出 JSON 结构但偶尔它会在内容里混入解释文字或者把引号写错导致json.loads失败。解决不要依赖一次输出就解析。我在提示词里明确要求“只输出 JSON不要输出其他文字”同时给了解析失败后的兜底逻辑截取第一个{到最后一个}之间的内容再尝试解析。这个兜底逻辑看着简陋实测却解决了九成的问题。6.6 成片出现重复新闻或信息过期症状连续几天视频里有同一条新闻。原因新闻源本身会有聚合转载。同一条重要新闻可能出现在多个来源中AI 把不同来源的报道当成了两条新闻。解决在做粗筛时增加标题去重逻辑对标题做文本相似度比较低于一定阈值的直接合并。同时我限制了每条新闻的时效窗口超过三天的内容一律过滤掉。from difflib import SequenceMatcher def is_duplicate(title1, title2, threshold0.85): return SequenceMatcher(None, title1, title2).ratio() threshold7. 内容可以继续扩展的方向这条“AI 自动化内容工厂”搭好之后延展空间其实是很大的。我目前只用它做技术新闻视频但底层能力是可以复用和迁移的。第一个扩展方向是“多平台分发”。视频生成后可以对接各平台的发布 API自动把成片同步到视频号、B 站、抖音等平台。不同平台的封面尺寸和标题规范不同但 Remotion 可以一次性渲染多个分辨率版本一次生成、多处投放。我目前还没有完全跑通这层只做了本地目录规范和手动上传但自动上传的接口对接是明确可行的。第二个方向是“多语言版本”。底层的新闻素材和口播稿是用中文写的但文案生成和语音合成都可以替换成其他语言。换一下提示词模板和音色参数就能生成英文版、日文版或者用同一条文案生成不同音色的版本。这类修改在代码层面就是换参数不用动流水线结构。第三个方向是“自定义视觉主题”。现在的模板是深色科技风。如果做的是泛科技内容可以换一套柔和明亮的主题如果做财经新闻可以换成更商务感的字体和配色。Remotion 的组件化特性决定了主题切换本质上就是替换一套样式变量。第四个方向是“增加视频内互动元素”。比如在视频里嵌一个投票二维码或者在片尾展示上期观众评论。这些都可以通过接口拉取数据再塞进 props 里渲染出来。相当于把“互动反馈”也纳入自动化环节。我个人目前在做的扩展是两条一是把成片里的长摘要改成短视频排行榜形式二是把每日三条新闻改成周末“本周技术盘点”对一周的新闻做二次总结。本质上都是调整提示词和模板结构代码层面没有太多新东西。最后分享一个我在实际使用中的体会。整套流水线里最需要“人”的部分反而不是视频渲染或语音合成而是“内容质量的抽查”。AI 生成的口播稿大体上没问题但偶尔会出现事实性错误特别是一些技术术语上的细微差别。所以我每天会花五分钟快速拉一遍成片重点看新闻标题和关键信息有没有被 AI 说反。这个习惯我建议别省自动化是帮你节省时间不是帮你放弃判断力。做个“只做终审的倒班编辑”比做一个半夜还在剪片子的剪辑师要幸福得多。