←Back to Journal
02 / Entry· 11 min read

给六岁的耳朵做一版《西游记》:用大模型和 TTS 搭一条儿童播客流水线

从睡前故事讲到自建 23 集儿童播客:原著改编规则、角色版脚本、小米 MiMo 音色设计、本地 VoxCPM2 兜底,以及一条能重复跑的音频生成流水线。

🔊 系统朗读

我家孩子六岁,最近每天晚上都要听《西游记》。洗完澡,钻被窝,灯一关,他就问:今天讲哪一集?

一开始是在短视频平台上听。平台的“听视频”确实能锁屏播放,但孩子的手还是会往屏幕上摸:下一集是不是更好玩?推荐页里有没有新的奥特曼?听着听着,故事就变成了划屏幕。

后来我发现,问题不只是屏幕。平台上的西游故事大多是剪辑版、二创版,前后接不上;配音往往是一个人从头讲到尾,悟空、八戒、唐僧都是一个调;内容里还夹着不适合睡前的打斗和吓人的描写。最要命的是,我不知道下一集会讲什么。

于是我想,干脆自己做一版。要求不复杂:按原著讲完整,人物有各自的声音,长度适合睡前,内容我自己签字。

我平时写代码,正好可以把这件事拆成一条能重复跑的流水线。工具是 Qoder 加小米的 MiMo TTS,本地再用 VoxCPM2 兜底。做了几周,脚本写到第 23 集,音频出了 22 集,总共 4 个多小时。下面把这套东西拆开讲讲。

一、先写“不能做什么”

让大模型改编《西游记》,最容易出现的问题不是它讲不好,而是它太想讲好。它会自动加戏:给悟空加一句现代俏皮话,给妖怪加一段原著没有的身世,把唐僧写成只会拖后腿的糊涂师父,把打斗写得更刺激。单看每一段都挺热闹,连起来就不是原著了。

所以第一件事不是写 prompt,而是把边界写死。项目里的 AGENTS.md 和规则文件先定下七条:

  • 只做减法和翻译,不做加法。 不新增原创妖怪、法宝、支线,不采用 86 版电视剧和动画电影的原创情节。
  • 不改变因果链。 谁引起、谁出手、谁帮忙、结果如何,必须与原著一致;可以压缩过程,不能调换因果。
  • 不改变人物底色。 悟空可以顽皮、急躁、爱面子,但不能写成完美英雄;唐僧可以谨慎、心软、会误会,但不能写成无能或虚伪。
  • 暴力必须柔化。 不写血腥、尸体、剖腹、砍头过程、吃人细节;用“打退、制服、现出原形、被收走”替代“打死”。
  • 恐怖有边界。 危险可以紧张,但不能让孩子带着害怕入睡;每集结尾必须落地、有安全感。
  • 不拿偷盗、撒谎、欺负人当笑点。 原著的胡闹可以保留,但要保留后果,不写成“只要厉害就可以不讲规矩”。
  • 不传教、不说教。 佛道称谓和取经设定按故事讲,不解释教义;道理放在情节和人物选择里,不放在旁白的大段总结里。

“只做减法”听起来抽象,落到句子上很具体。原著写“那猴王将身一纵,跳上树梢”,改成“孙悟空轻轻一跳,就跳到了树梢上”,这是翻译;如果改成“孙悟空一个帅气的空翻落到树梢上,朝妖怪比了个手势”,就是加戏。

原著里的“打死”,在儿童版里改成“打回原形”“被主人收走”“再也不能害人”。黑松林那一集,猎户上山抓猴子,原著里悟空把他们打死了;脚本里改成一阵大风把猎户卷下山,人没死,冲突还在。黄袍怪和百花羞的两个孩子与主线无关,也容易让孩子困惑,整段删掉。

这些删改不是随手做的。每一集脚本头部都留一张“改编记录”:

text
# 原著:第二十八回 花果山群妖聚义 黑松林三藏逢魔;第二十九回 脱难江流来国土 承恩八戒转山林
# 压缩:花果山景物描写、八戒化斋的反复心理、波月洞两次打斗的回合、宝象国朝堂的繁文缛节
# 柔化:猎户改为被大风卷下山,不写打死;妖怪抓人不写吃人细节;
#       百花羞被掳后的生活只写想家,删去两个孩子及相关情节
# 删去:原诗、黄袍怪与百花羞的前世因缘、百花羞书信全文、宝象国文武官员的议论

这张表是给未来的自己看的,也是给模型看的。下次改这一集,先看它,不会把已经想清楚的问题再想一遍。

二、一集 15 分钟,拆成六步

一条稳定的流水线,比一次惊艳的生成更重要。每一集都按同样的顺序走:

步骤产出关键检查
原著卡回目、事件、因果、必须保留的细节每一场都能在原著找到
场景大纲3-5 场,每场“目标—阻碍—行动—结果”没有阻碍的过场删掉
角色脚本[角色] 台词一行一个角色,单块不超过 120 字
三查原著忠实、儿童理解、TTS 可读三张表逐项过
音频分块合成、合并先试听一个块,再批量
封面与发布1:1 封面、音频、文案风格统一,结尾落地

第一步是原著卡。不是把原文贴给模型让它总结,而是先确认这一集到底覆盖哪几回、哪几个事件、因果怎么走。第 22 集覆盖第二十八、二十九回,主线只有一句话:唐僧在黑松林被抓,百花羞托他带信,八戒和沙僧去救,却打不过黄袍怪。

第二步是场景大纲。每场只写四件事:谁想要什么,遇到什么阻碍,做了什么,结果怎样。没有阻碍的过场,删掉或并到下一场。打斗只留三个回合,孩子能数得清;三十个回合的打斗,孩子只记住“打来打去”。

第三步才是写角色脚本。第四步过三张自查表:原著忠实、儿童理解、TTS 可读。第五步生成音频。第六步做封面、写文案、上传。

目标时长是 10-15 分钟。最近几集因为原著事件密,落在 15-17 分钟。我宁愿长一点,也不把因果砍断。最早的第 1 集只有 5 分钟,后来逐步稳定到现在这个长度。

三、脚本是给耳朵写的,不是给眼睛看的

角色版脚本长这样:

text
[旁白] 孙悟空一听,高兴极了。

[孙悟空] 嘿嘿,这些桃子看起来好好吃呀!我先尝一个,就一个!

[旁白] 他摘了一个最大的桃子,咬了一口。

看起来像剧本,其实它同时是 TTS 的输入格式。解析脚本只认行首的 [角色],后面的字全部交给模型读。所以正文里不能出现括号、星号、井号、表情符号、Markdown,也不能写“他笑着说”“(小声)”“【音效】”这类舞台提示——这些都会被原样念出来。

停顿只能靠标点。同一角色连续几行会被合并成一个音频块,换行不产生停顿;想要停,就写逗号、句号、省略号。一个块 40-90 字最舒服,最长不超过 120 字;一句台词不超过 50 字。块太大,模型的语气会塌;块太小,句子会碎。

还有几条看起来琐碎、但直接影响听感的规则:

  • 数字写成汉字:十万天兵、四十九天、三千年,不写 100000、49 天。
  • 不用英文单词和字母缩写,“OK”写成“好”。
  • 多音字风险词换掉:“行者”容易读错,就统一写“孙悟空”。
  • 拟声词一集不超过五个,不叠用;省略号一集不超过八处。
  • 角色名前后完全一致,不能一会儿悟空、一会儿行者、一会儿大圣。

这些规则的共同点是:把“表演”从文字里拿掉,交给声音。文字只负责说清楚谁、在什么场合、说了什么。

写完还要过三张表。第一张防加戏,第二张防听不懂,第三张防读错。第二张表里最有用的一条是:遮住文字,只听一遍,能不能听出谁在说话、现在在哪、发生了什么;七岁孩子听一遍,能不能复述“谁想要什么、遇到什么、最后怎样”。三张都过,才送去生成音频。

四、让每个角色有自己的嗓子

单播最大的问题不是不好听,而是信息不够。孩子看不到画面,声音是唯一的线索。如果悟空、八戒、唐僧都是同一个嗓子,脚本就只能不停写“孙悟空说”“猪八戒说”,故事立刻变成朗读课文。

我给每个固定角色写一段音色描述,交给小米 MiMo 的 TTS。接口很直接:user 放音色描述,assistant 放要读的台词,返回 wav。

python
completion = client.chat.completions.create(
    model="mimo-v2.5-tts-voicedesign",
    messages=[
        {"role": "user", "content": voice_prompt},  # 音色描述
        {"role": "assistant", "content": line},     # 要读的台词
    ],
    audio={"format": "wav"},
)

音色描述不是在调参数,是在选角。好的描述要回答五个问题:多大年纪、什么性别、音色是亮还是厚、说话是快还是慢、这个人的性格怎样落在声音里。

角色音色设计(节选)想要的效果
孙悟空二十二岁上下的青年男声,音色明亮清脆,语速中等偏快,说话利落俏皮像动画片里的悟空在跟小朋友聊天,不是在喊
猪八戒三十岁上下的成年男声,中音偏亮,声音圆厚,尾音发憨,声音里带着乐呵爱显摆、爱占便宜,被拆穿了也不恼
唐僧二十八岁上下的青年男声,干净柔和,慢而清楚,句尾轻轻落下温柔但不软弱,不念经
观音三十五岁上下的成年女声,中低音温润,平,不慌不忙慈悲,但不是哄小孩的软
阎王五十岁上下的成年男声,低音浑厚,说话很慢,一句一句问清楚有分量,但不阴森

负面词和正面词一样重要。几乎每段描述后面都跟着一串:不喊、不咆哮、不朗诵、不拖长音、不唱腔、不用气声、不装可爱。模型很容易把“威严”演成“吼”,把“慈悲”演成“哄小孩”,把“妖怪”演成“怪物腔”。这些负面词是在把表演往回拉。

现在 prompt/prompts.py 里有 60 多套音色描述。不是每个角色都需要单独一套:小仙女、猴子们、围观群众可以共用;但主要角色必须有辨识度。孩子听到一个声音,应该能立刻知道是谁来了。

路由规则是:在 prompts.py 里有音色描述的角色,走小米 MiMo;临时出现、没有预设音色的角色,走本地 VoxCPM2。VoxCPM2 支持参考音频克隆,适合把某个声音固定下来;但它有 512 token 的批大小限制,长文本要先切成 300 字以内的小段,再分别生成、拼接。MiMo 的 voice design 则把“设计音色”和“合成”放在一次调用里,少一层对齐的麻烦。

两类模型各有各的坑。MiMo 的坑在描述:描述越文学,越容易生成噪声;“温暖低沉”这种词,不如“三十五岁女声、中低音、语速慢、句尾收住”稳。VoxCPM2 的坑在长度:一段太长会直接崩,必须切。工程上的结论很简单:不要让一个模型干所有事,按角色和场景分流。

五、生成脚本干的都是脏活

一集 17 分钟,不是一次请求生成的。第 22 集有 74 个块,9 千多字。脚本会逐个块调用 TTS,落成 block_07_孙悟空.wav 这样的文件,再用 ffmpeg 按顺序拼起来,块与块之间插 600 毫秒静音。

生成脚本看起来平平无奇,但它决定了这件事能不能规模化:

  • 解析:只认 [角色] 台词,忽略 # 开头的改编记录。
  • 映射:CHAR_MAP 把脚本里的角色名映射到 prompts.py 里的音色键;名字对不上就直接报错,不让它悄悄读错人。
  • 断点续跑:已存在的块跳过。74 次请求里任何一次失败,都不应该让整集重来。
  • 重试:失败等 5 秒、10 秒再试,三次还不行才停。
  • 合并:统一采样率,插静音,输出一个完整 wav。

这些设计不高级,但很实用。生成一集的时间主要花在等 API 上,人不用盯着;真正花时间的是前面的改稿和后面的试听。机器跑十几到几十分钟,人可能改一晚上。

还有一个顺序问题:先试听一个块,再批量生成。音色、语速、停顿不对,一个块就能听出来;等 74 个块全跑完再发现,返工成本就高了。

六、Qoder 在这里到底是什么角色

不是“一句话生成一集”。至少现在不是。它更像一个能读项目规则、能写脚本、能跑检查的合作者。

每集开工,它先读 AGENTS.md、三份规则文件和创作手册,知道这一集不能加戏、不能改因果、不能把妖怪写成怪物腔;然后按原著卡拉场景大纲,写角色版脚本,补改编记录;再写这一集的生成脚本,把新角色加进 CHAR_MAP 和音色表;生成后检查角色名、数字、标点、块长度;最后按统一风格做封面。

但有几件事必须人来:这一刀该不该砍,这个笑点会不会冒犯,这段打斗会不会吓到孩子,这个结尾能不能让孩子安心睡着。这些没有标准答案,只能由每天陪他睡觉的人来判断。

三查里,原著忠实和 TTS 格式可以大量借助模型;儿童理解这一关,最后必须由人听。模型可以告诉你“这句话没有超长”,不能告诉你“这句话六岁孩子听不懂”。

这件事给我最大的工程启发是:把规则写进文件,不要留在脑子里。规则一旦变成 AGENTS.md、.cursor/rules 和创作手册,模型每次都能读到,我也能随时回看自己为什么这么改。否则做了二十集以后,连我自己都记不清第一集为什么删了那个情节。

七、踩过的坑

模型天然爱加戏。 它会把“悟空回花果山”写成一场复仇爽文,把“唐僧误会悟空”写成师徒决裂。规则只能压住大部分,剩下的要在改稿时逐段和原著对。

音色描述越文学越容易翻车。 一开始写“温暖柔和的女性,声音低沉舒缓”,生成出来是噪声。后来改成年龄、性别、音色、语速、句尾处理,再加一串负面词,才稳定。

长文本会崩。 本地 VoxCPM2 超过批大小会直接报错;云端 TTS 虽然能吃长文本,但语气会越来越平。切块不是妥协,是让每一块都有独立的情绪。

TTS 会把所有字都读出来。 一个括号、一个星号、一个英文缩写,都会变成耳朵里的杂音。脚本必须干净到像给播音员的口播稿。

角色名不统一,孩子会以为是三个人。 悟空、行者、大圣混着写,成年人知道是一个人,六岁孩子不知道。现在统一由 CHAR_MAP 管,名字对不上就报错。

块与块之间的响度不天然一致。 不同批次生成的音频,音量、底噪、气口都可能不同。合并后要整体听一遍,必要时做响度归一。这个问题还没完全解决,但在清单上。

封面风格会漂移。 前几集是卡通头像,后面变成电影感构图,放在一起不像一套。后来固定了 1:1 方图、同一套光线和构图语言,才看起来像同一个节目。

恐怖的标准要以孩子为准。 大人觉得“只是有点紧张”的描写,孩子可能带着入睡。现在的做法是:先给声音和影子,再给一个滑稽细节,最后才露真身;每集结尾一定回到安全的地方。

“AI 味”主要来自解释和总结。 模型喜欢在结尾讲一段道理,或者在每个新词后面停下来解释。现在的处理是:解释完马上用一次,道理最多一句,能放进人物选择里就不放旁白。

八、现在的样子

目前的状态:23 集脚本,22 集音频,总时长约 4.3 小时;最近几集 15-17 分钟;60 多套音色;封面统一成 1:1 方图。音频传到公众号的播客入口,孩子听的时候不用盯着屏幕。

我不敢说它比平台上的版本更受欢迎,但至少有三件事我能确认:故事前后接得上,孩子可以一集一集往下听;声音能区分人,不用每句话都写“某某说”;下一集讲什么、删什么、讲到什么程度,由我决定。

也有不满意的地方:有些块之间的响度还不够平;个别多音字还会读错;早期几集长度和风格不统一,需要重做。这些都在清单上。

九、接下来

短期先把第 23 集收尾,把前几集的长度和音色统一一遍;中期做响度归一和批量试听,减少人工返工;长期想把一百回都做完。这是个很长的工程,但流水线已经跑起来了,剩下的主要是时间和耐心。

我不打算把它做成一个多大的平台。它就是给我家孩子做的一个版本:按原著讲,人物有各自的声音,长度适合睡前,内容我自己负责。

这件事最有意思的地方,不是大模型能生成音频。而是它把“做内容”的门槛降到了一个人可以承担的程度:不用会配音,不用会剪辑,不用组团队,但仍然可以决定讲什么、怎么讲、讲到什么程度停下。

孩子听到的每一个字,都是我签过字的。睡前故事的标准也不是播放量,而是第二天早上他还记不记得,以及昨晚有没有做噩梦。

分享
← 返回博客列表
🎁 有邀请福利哦,点击查看
🎁