Skip to content

从原著到成片:智能体驱动的 AI 读书视频生产系统

约 5539 字大约 18 分钟

AgentCodexRemotionTTS

2026-08-24

如果把一本书交给 AI,让它自动生成一条可以发布的视频,真正困难的部分是什么?

不是调用一次大模型,也不是把几张图和一段配音拼在一起。真正困难的是:如何让一个具有不确定性的智能体,稳定地完成原著理解、脚本创作、来源核对、分镜规划、图像生成、语音合成、音画同步和交付验收,同时保证它不会脱离原著、不会跳过复审,也不会在失败后把整条流水线推倒重来。

我把这套实践整理成了一个开源项目:AI 读书视频工程。它采用“智能体决策层+确定性生产引擎”的双层架构,让 Codex 负责理解和规划,让 Node.js、豆包 TTS 与 Remotion 负责稳定执行,最终从一本本地原著生成有声 MP4、两种发布封面和可直接复制的发布文案。

项目和实际效果可以从下面三个入口查看:

这篇文章不只展示结果。我更想把里面的系统设计、核心代码路径、踩过的坑和取舍讲清楚,让读者能够按照同样的思路复刻一套自己的垂直视频生产智能体。

这不是一个“提示词生成视频”的玩具

最早想到这个项目时,我也可以选择一条更短的路:把书名交给模型,让它根据记忆写一篇解读,再调用 TTS,最后按固定间隔切几张图片。

这条路很快,但它有三个致命问题。

第一,模型记忆和网络摘要不能证明内容来自原著。人物、情节、转折甚至结局一旦写错,后面的图像和视频做得越精致,错误就被包装得越完整。

第二,脚本、图像、配音和视频彼此没有状态关系。脚本改了一个字,旧配音可能继续被复用;发音规则改了,最终成片也未必知道应该重做。

第三,失败恢复非常困难。一条十分钟视频可能运行几十分钟甚至更久,如果网络在最后阶段断开,从头再来意味着重复消耗模型调用、图片生成和 TTS 额度。

所以我没有把它设计成一条松散的 Shell 脚本,而是把它做成一个有来源、有状态、有门禁、可恢复的生产系统。

核心架构:让概率性决策进入确定性工程

整个系统可以分为两层。

智能体层擅长处理语义问题:这一段是不是原著的关键场景,观众是否能理解人物冲突,现代类比有没有伪装成作者观点,哪个画面最值得停留。

确定性引擎擅长处理工程问题:原文哈希是否变化,脚本是否经过批准,音频究竟有多少采样,某个镜头应该从第几帧开始,最终 MP4 是否真的包含 H.264 视频流和 AAC 音频流。

我认为这是这套系统最重要的设计。不是让智能体控制一切,而是只让它在需要判断的地方发挥能力;到了可以计算、校验和复现的环节,就交回传统程序。

为什么它可以被称为一个垂直智能体

book:auto 并不是按照固定模板顺序填空。它会启动一次可恢复的 Codex 非交互会话,给出目标、可用工具、仓库规范和停止条件,然后让 Codex 根据当前书籍状态推进任务。

一次完整运行大致包含下面的反馈循环:

它具备一个垂直智能体需要的几个基本要素:

  • 目标:把指定原著制作成符合频道标准的完整交付物;
  • 环境感知:读取当前书籍、已有文件、哈希、检查结果和工具错误;
  • 规划能力:决定脚本结构、内容层次、关键画面和下一步动作;
  • 工具调用:运行质量门、图片生成、TTS、Remotion 和交付检查;
  • 反馈修正:根据失败结果修改当前书,而不是机械继续;
  • 状态与恢复:保存 Codex 会话、JSONL 事件和有效中间产物;
  • 终止边界:原文不可靠、认证或额度不可用、同一问题多次修复失败时停止。

这里的“智能”不来自某一个神奇 Prompt,而来自模型、工具、状态和反馈循环的组合。

第一条硬边界:原著必须成为可验证的事实源

对于书籍解读,最危险的不是文字不够华丽,而是内容看起来合理,实际上来自模型记忆、书评或二手剧情梗概。

因此,新项目只接受用户合法取得并放入根目录 source/ 的 UTF-8 .txt.md。建书时,程序会记录:

{
  "sourceMode": "local-source",
  "sourcePath": "source/书名.txt",
  "sourceEncoding": "UTF-8",
  "sourceSha256": "..."
}

每次恢复运行都会重新计算 SHA-256。文件缺失、内容变化、编码不正确或者不是目标书籍,流程都会在写脚本、生成图片和调用 TTS 之前停止。

脚本里的来源也不是只写一句“根据原著”。每个关键段落都要映射到具体原文行号;引入新场景的段落还要记录人物、行动和结果。纯分析段可以没有场景锚点,但不能连续堆叠,也不能让分析脱离故事。

这样设计不是为了增加格式,而是为了给智能体建立一个可以回查的工作记忆:当它复审某句话时,能够重新定位原文,而不是再次凭概率生成一个听起来正确的答案。

脚本规划:从摘要生成升级为叙事工程

如果观众没有读过原著,只抛出几个抽象观点,很难建立情绪和理解。系统要求所有题材至少完成一条完整内容链:

现实问题
  → 具体场景
  → 原著核心案例或剧情
  → 解释原理
  → 回到现实
  → 补充局限

小说要讲清人物、目标、阻碍、反转、后果与结局;非虚构作品要讲清案例、论证条件和适用边界。原著内容、现代类比和频道判断在内部数据中分别标记,到了口播里再用自然语言连接,而不是把视频切成三个生硬栏目。

留存结构也会被显式建模。脚本需要记录开场钩子、首次兑现、每段的 payoff 和下一段 nextHook。质量门检查第一句话是否直接进入冲突或反常识,前二十秒是否真的给出价值,后续是否形成持续的“小兑现+新问题”。

这一步的难点在于:机器可以检查字段有没有填写,却无法证明内容真的好听。因此项目同时保留了两类复审。

复审类型适合检查什么谁负责
语义复审原著是否讲清、句子是否自然、类比是否越界、结局是否完整Codex 智能体
工程质量门字段、比例、段落映射、哈希、字符数、时间范围Node.js 脚本

工程校验不能代替编辑判断,智能体自称“审核通过”也不能代替工程证据。两个环节必须同时成立。

审批哈希:让下游知道自己使用的是哪一版脚本

长流水线中很常见的错误是:脚本已经修改,配音和画面却仍然对应旧版本。

项目在脚本复审后计算 SHA-256,并写入 approval.json。分镜、TTS 和渲染开始前都要确认当前脚本哈希与批准哈希一致。只要脚本变化一个字符,旧批准立即失效。

多音字是另一个容易被忽略的问题。正文必须保持标准写法,不能为了让 TTS 读对而把字幕文字改成错别字。因此项目把发音替换放在独立的 pronunciationOverrides 中,只改变发送给 TTS 的文本。发音规则也有自己的哈希,规则变化后旧 WAV 自动失效。

这类哈希看起来不如生成式 AI 吸引眼球,却是系统能否稳定返工的关键。

分镜规划:先找语义关键点,再决定图片数量

很多自动视频工具按固定时间切镜头,例如每五秒换一张图。这种实现简单,却会让重要剧情和过渡句获得同样的视觉权重。

这个项目反过来做:智能体先从脚本中选择关键剧情、核心概念、现代类比和局限,再把每个关键点映射到镜头。一个段落可以有一到四个镜头,每个镜头通过 weight 表示相对重要性。

{
  "segmentId": "seg-07",
  "shots": [
    {
      "label": "关键剧情场景",
      "image": "assets/storyboards/sheet-03.png",
      "panel": 0,
      "weight": 3
    },
    {
      "label": "回到现实的类比",
      "image": "assets/storyboards/sheet-03.png",
      "panel": 1,
      "weight": 1
    }
  ]
}

为了降低图片生成和素材管理成本,新书使用纵向 9:16 的 2×2 分镜母图。一张 PNG 中包含四个纵向子画面,Remotion 根据 panel 裁切需要的区域。图片模型只负责生成无字插画;准确的中文书名、章节重点字和封面文字全部由代码排版,避免模型生成乱码。

资产生成后还要检查母图比例、语义覆盖和可见文字。只有实际图片通过复核,流程才允许进入 TTS 和渲染阶段。

TTS:云端只负责说话,本地负责建立主时钟

语音部分使用火山引擎豆包语音合成 2.0。系统不会把整篇稿件作为一个无法定位的大请求,而是按固定开场和脚本段落分别调用 TTS。

接口返回 SSE 事件,其中音频数据是 Base64 PCM。程序将数据解码为二进制片段:

for (const line of responseText.split(/\r?\n/u)) {
  if (!line.startsWith('data:')) continue
  const event = JSON.parse(line.slice(5).trim())
  if (event.data) chunks.push(Buffer.from(event.data, 'base64'))
}

writeFileSync(outputPath, Buffer.concat(chunks))

每段 PCM 会经过静音裁剪,再插入段间停顿,最后拼成一条单声道 WAV。真正决定视频长度的不是字数估算,而是 PCM 的真实采样数:

音频秒数 = PCM 字节数 ÷(采样率 × 每个采样的字节数)
总帧数   = ceil(音频秒数 × FPS)

系统同时生成 narration-timeline.json,保存每个段落的开始秒数、结束秒数和真实时长。至此,WAV 成为整条视频唯一的主时钟。

这样做解决了一个很实际的问题:同样数量的汉字,标点、数字、人名和语速都会影响最终口播长度。如果先按字数排画面,配音完成后必然漂移;让画面跟随真实音频,时间轴才能稳定。

Remotion:把 React 变成视频渲染引擎

Remotion 可以理解为“用 React 编写的视频时间轴”。项目把 TTS 生成的完整 WAV 放在第零帧:

<Audio src={staticFile(props.audioFile)} />

画面则按照音频时间轴换算出的帧数排列:

<Sequence
  from={shot.startFrame}
  durationInFrames={shot.durationInFrames}
>
  <ShotScene shot={shot} />
</Sequence>

同一段音频中的多个镜头按 weight 分配时长,插画上叠加轻微缩放、平移、淡入和代码排版的章节重点字。最后由 Remotion CLI 渲染为 H.264 视频流,并把 WAV 转码为 AAC 音频流,一起封装进 final.mp4

这一层没有模型推理。输入的图片、文字、帧数和音频确定以后,输出就是可复现的。智能体负责决定“放什么”,Remotion 负责精确执行“从哪一帧开始、持续多少帧、怎样编码”。

book:auto:把长任务做成可恢复会话

准备好环境以后,最短入口只有一条命令:

npm run book:auto -- --title "活着" --author "余华" --audience "25~40岁泛读书用户" --source "活着.txt"

运行前需要:

  1. Node.js 20 或更高版本;
  2. 已安装并登录的 Codex CLI;
  3. 可用的 Codex imagegen Skill;
  4. 豆包 TTS API Key;
  5. 放在 source/ 中的合法完整原文。

建议先运行无费用环境检查:

npm run book:auto:check

book:auto 默认使用安静进度模式,只显示当前阶段、插画数量、渲染帧数、已用时间和网络状态。完整事件保存在 .runtime/book-auto/<book-id>.jsonl,错误输出和交付复检也分别保存。

如果中途断网、额度不足或渲染失败,修复原因后执行:

npm run book:auto -- --resume --book "book-003-活着"

系统会恢复同一个 Codex 会话,先重新校验原文和现有产物,再从最早失败的门禁继续。脚本、发音规则和固定开场的哈希仍然匹配时,WAV 可以直接复用;已有插画仍然通过比例、完整性与视觉复核时,也会被保留而不是重新生成。

这也是我认为自动化工具和生产系统的分界线:前者只会重新执行,后者知道什么仍然有效。

为什么没有选择漫剧式视频

既然已经使用 AI 生成画面,一个自然的问题是:为什么不把每个镜头都生成成会动的漫剧或图生视频?

从系统骨架看,两种方案其实大差不差:

脚本语义
  → 镜头规划
  → 视觉资产
  → TTS 音频
  → 时间轴
  → 编码与交付

真正不同的是“视觉资产”这一层。

对比维度分镜插画漫剧/图生视频
单镜头资产静态图片数秒视频片段
角色一致性主要保证外观和服装还要保证运动过程不变形
连续性用剪辑和叙事连接要处理动作、镜位和前后帧连续
失败方式构图、细节或文字错误还会出现动作崩坏、脸部漂移、物体消失
抽卡成本较低,图片可复用和裁切通常需要按镜头反复生成
制作时间生成后可直接进入排期每段视频生成和返工都更慢
动态表现依赖轻动效和节奏原生运动感更强

漫剧当然更“动”,但当一条长视频包含几十个语义镜头时,角色一致、动作自然、镜头衔接和失败重抽会迅速放大时间与成本。一个五秒片段生成失败,损失的不只是五秒,而是等待、重试、筛选和重新适配时间轴的整套工作。

分镜插画是一次有意识的工程取舍。它不是否定漫剧,而是先验证更核心的问题:观众是否愿意跟随一条来源可靠、叙事清晰、视觉语义匹配的书籍解读。静态画面通过景别裁切、缓慢推进、章节重点字和音频节奏,同样能形成完整的视频表达。

在我当前的个人使用方式里,不需要为每个镜头采购视频生成 API。需要单独配置的云端服务主要是豆包 TTS,实际试验中免费额度已经能够完成一条完整口播;插画则使用已有的 Codex 图片生成能力。这里的“低成本”是相对于频繁的视频抽卡,并不意味着图片、模型订阅和本地渲染完全没有成本,具体免费额度也应以服务商当期规则为准。

更重要的是,这两种方案并不冲突。以后如果视频生成的速度、成本和一致性改善,只需要把静态图片资产替换为动态片段,原文绑定、脚本复审、审批哈希、TTS、音频时间轴和交付门禁都可以继续复用。

真正难的不是调用模型,而是约束模型

回头看整个项目,技术难点主要集中在五个地方。

1. 来源一致性

模型很容易生成“像真的一样”的内容。必须让原著路径、哈希、行号映射和恢复校验成为系统约束,而不是 Prompt 里的友好提醒。

2. 不确定决策与确定执行的边界

脚本质量和视觉语义需要智能体判断;时长、帧数、文件格式和审批状态必须由程序计算。边界划错以后,要么系统变得僵硬,要么结果不可复现。

3. 长任务恢复

图片生成、TTS 和渲染都可能失败。恢复机制必须保存会话和产物,同时依靠哈希判断哪些内容能够复用,不能简单地“从上次那条命令继续”。

4. 音画同步

中文 TTS 的真实时长无法只靠字数准确预测。将 WAV 采样数设为主时钟,再反向分配镜头,是避免长视频逐渐漂移的关键。

5. 质量门不能被智能体自己绕过

如果智能体既生产内容,又能随意修改验收规则,那么所谓自检没有意义。生产命令只能修复当前书的内容和素材,不能降低来源、审批、配音或交付标准。

这些问题并不只存在于视频项目。任何让智能体持续调用工具、产生正式交付物的系统,最终都会遇到来源、状态、权限、恢复和验收。

如何复刻一套自己的版本

如果准备从零实现,我建议按下面顺序推进,而不是一开始就追求全自动。

  1. 先做单本书纵向切片:完成原文绑定、脚本、TTS、两张图和一分钟视频;
  2. 建立数据契约:把脚本、来源、视觉计划和时间轴拆成结构化 JSON;
  3. 让音频成为主时钟:先得到真实 WAV,再计算视频帧数;
  4. 用 Remotion 做确定性模板:把图片、文字、音频和帧数变成可参数化组件;
  5. 补来源与审批哈希:保证返工时不会混用旧资产;
  6. 增加质量门:先检查可机械判断的问题,再接入智能体语义复审;
  7. 最后加入自动智能体:让它读取检查结果、修复内容并调用已有命令;
  8. 加入恢复和日志:只有做到可诊断、可继续,长任务才真正可用。

单本书目录可以保持这样的结构:

books/book-xxx-书名/
├─ book.json
├─ approval.json
├─ content/
│  ├─ script.json
│  ├─ source-map.json
│  ├─ visual-plan.json
│  └─ narration-config.json
├─ generated/
│  ├─ narration-timeline.json
│  └─ prepared.json
├─ public/assets/
│  ├─ audio/narration.wav
│  └─ storyboards/
└─ output/
   ├─ final.mp4
   ├─ cover-3x4.png
   ├─ cover-4x3.png
   └─ publish-copy.txt

当这条最小链路稳定以后,再扩展更多视觉风格、音色、视频生成方式或发布平台,成本会低很多。因为真正值得复用的不是某一次生成结果,而是来源、状态、时间轴和质量门构成的生产基础设施。

写在最后

这个项目最初只是一个想法:能不能让 AI 帮我把一本书做成一条视频?真正实现以后,我发现答案不是“找到一个更强的模型”,而是建立一套让模型知道何时判断、让程序知道何时接管的系统。

Codex 负责理解原著、编写脚本、规划分镜和处理反馈;豆包 TTS 把文字变成声音;Remotion 把声音、画面和代码时间轴变成视频;来源哈希、审批门和交付检查则保证每个阶段仍然属于同一本书、同一版脚本和同一套标准。

这是一种很典型的智能体工程:模型提供柔性的认知能力,传统软件工程提供刚性的可靠性。两者组合起来,才让“从原著到成片”不再是一次演示,而成为可以恢复、复用和继续演进的生产系统。

如果你也想复刻,可以从 GitHub 项目 开始;如果想先看完整运行过程,可以看 Bilibili 制作记录;最终呈现则放在这条 抖音成品 中。