AI-Native游戏开发(5):剧情台词生产链
0. 系列文章导航
3句话,AI给我生成了一个galgame
AI-Native游戏开发(1):为什么选择图数据库
AI-Native游戏开发(2):角色美术生产链
AI-Native游戏开发(3):角色声音生产链
AI-Native游戏开发(4):场景与BGM生产链
AI-Native游戏开发(5):剧情台词生产链
AI-Native游戏开发(6):叙事图自增长
1. 剧情生产不是写小说,是编排
概念稿对剧情生产的想象是:「Event 是剧情基本单元,LLM 在世界状态上继续产生新 Event」。落地时这个模型被证明不完整——它解决了「AI 基于什么写」(世界状态),没解决「写出来的东西怎么管理」。
一部 Galgame 的剧情体量:一章几十个场景块、几百句台词,每句台词要挂立绘、挂音频;改稿是常态——改一句、插一段、删一幕都随时发生;成品要投影成运行时格式。如果生产单元就是「事件」,这些东西全部无处安放。
落地后的剧情生产链是一条五级产物链:
- Chapter(章):一个发布单位。审批点是「结构审」——分节方案与节奏通过与否。
- Section(节):把若干 Scene 编排成一节的演出顺序。它是纯编排容器,没有 status——容器不产产物,就不该有状态。这条判据与第 3 篇「VoiceClone 不是节点」一脉相承:图上的节点 = 需要独立调度或审批的对象。
- SecOutline(提纲):一节的剧情骨架,写明场景块顺序、分支结构、每块的情绪目标。文字产物,无审批,完成即 1。
- SecScript(定稿):一节的完整逐句剧本,人读格式,走定稿审批。
- LineAudio(台词行):定稿拆分后的逐句结构化真相,每行一节点,逐句走音频审批。
而 Event / Character / Location / Info / Choice 仍然稳坐叙事基础层(第 1 篇),它们不参与这条生产链的状态流转,却是每一级生产的依据——提纲自检事件的丰满度、定稿引用场景块、配音挑选立绘。概念稿的模型没有错,只是要再加一层:叙事图提供「写什么」,生产链管理「怎么把写的东西变成可发布的产物」。
下面按生产顺序走一遍:结构 → 提纲 → 定稿 → 拆分配音 → 发布。
2. 结构先行:章级设计与场景块预分配
第一站是章级结构设计 skill。它做三件事:
- 分节:把这一章要用的 N 个 Scene,按情感弧规划成 K 个节——哪里起、哪里落、高潮压在第几节。节奏是章级属性,不能放给逐节自由发挥,否则每节各自戏剧最大化,拼起来就是一路高潮的疲劳轰炸。
- 预分配场景块 id:给全章每个「场景块」分配章内唯一的标识(如序章 sec01 的两块——咖啡店块 s01_咖啡店、路口块 s01_路口)。剧本、配音、发布全链都靠它对齐「此刻在哪个场景」。
- 产出设计简报:本章的戏剧目标、每节的情绪定位、分支骨架——它是后续提纲与定稿两级的创作意图锚点。
完成即 Chapter → 10,人工做结构审:分节与节奏对不对、场景编排合不合理。这一步的审批性价比极高——改一处结构的成本是重排几行编排,漏过一处结构问题的代价是下游整章提纲定稿全部返工。审批位要卡在「错误传播半径最大」的上游,这是全链审批位置设计的统一逻辑(对照第 2 篇:文字层不审、图片层审,因为图片的错误代价大;这里结构审在先、定稿审在后,同理)。
结构重做的处理也干脆:旧的 Section 及其下游全部产物链直接删除重建——结构变了,挂在旧结构上的一切都不再有意义,保留它们只会制造「看起来还有效」的幻觉。
3. 提纲的自检与「拒绝产出」
第二站是节级提纲。提纲 skill 读取设计简报与本节编排的 Scene,先做一件事:自检本节的事件素材是否足以支撑一个戏剧完整的节。
素材不够时会怎样?这里出现了全流水线最特别的一个行为:拒绝产出。skill 不硬写,只产出一份缺口报告——「本节缺少 X 角色与主角的冲突事件」「Y 地点没有任何前置事件支撑」——不写任何 status,生产停在这里。
为什么拒绝比硬写更诚实?因为 LLM 永远写得出来——给它再少的素材,它也能编出一节「看起来完整」的戏,代价是人物行为没有前因、事件没有逻辑,读者说不清哪里怪但就是不对。素材不足时 LLM 的产出不是剧情,是剧情形状的填充物。与其让人在定稿审批时嗅出「味道不对」再层层回溯,不如在素材入口就立一道闸:缺素材,报缺口,补完了再来。
而「补素材」的动作由谁做?答案接上了叙事基础层——用户往叙事图里补 Event(可以手动,也可以用第 6 篇的自增长工具),补完重新触发提纲 skill。生产链拒绝的地方,恰好是叙事图需要生长的地方——这个衔接点是第 6 篇自增长回路的一半,先记住它。
素材足够时,提纲正常产出:每一节的骨架,标明场景块(必须用结构期预分配的 id)、每块的剧情功能与情绪目标、分支走向。status 到 1,无审批——又是文字层不审、靠下游级联兜底的老原则。
4. 定稿创作:台词与演出分离
第三站是节级定稿。定稿 skill 读设计简报与提纲,创作逐句剧本,产出本篇最重要的产物——台词.md。它的格式刻意保持着「人类作者一看就会用」的朴素:场景用二级标题(场景块 id + 场景名 + 时段),说话行是「角色名:台词」,旁白行以「旁白:」起头,选择与结局用专门标记。
但有一条格式纪律值得单独讲:说话行不许写表情标注。不许出现「陆择(轻笑):早啊」这样的写法——表情、动作、立绘切换,全部留给下游。
这是「台词与演出分离」:台词层只管「说了什么」,演出层(哪句配什么表情立绘、什么情绪配音)由第 3 篇的配音期逐句判别。理由有三:
- 写台词时的 LLM 不该越权做导演。 创作台词的注意力在「这个人此刻会说什么」,让它顺手标注表情,它给的往往是陈词滥调的舞台指示(苦笑、挑眉、叹气),而不是基于演出语境的判断。
- 演出决策需要全语境。 第 3 篇讲过,选立绘判情绪发生在「读完整节、知道前后句」的配音期,且决策依据包括当时立绘池里有什么——写作期根本不具备这些信息。
- 人的修改成本。 台词.md 是人要改的定稿格式(下面双轨分离详述),「陆择:早啊」改成「陆择:醒了?」是一处文字编辑;如果行内还嵌着演出标注,改台词与改演出搅在一起,永远理不清。
定稿完成 → status=10 → 人工定稿审:治理后台把整节台词.md 渲染成全文,人通读——对不对味、这个角色会不会说这种话、节奏顺不顺。通过 → 11,解锁拆分配音;驳回 → 0。这是剧情链上创作质量的主审关口,比任何技术校验都重要。
顺带一提:定稿 skill 也有「拒绝」通道——创作中发现提纲本身戏剧性破碎(两条分支没有本质差异、某场景空转没有情绪推进)时,产出「结构性问题报告」回退给提纲级,而不是硬着头皮往下写。每一级都能把问题顶回上一级,而不是自己消化——流水线里「硬消化上游问题」的环节,最终都会变成质量黑洞。
5. 双轨分离:人读定稿与结构化真相
定稿通过后,进入本篇最核心的设计。剧本现在有两种存在形态,各自承担完全不同的职责:
轨道一:台词.md——人的界面。 人类作者读它、改它、审它。它的格式标准只有一条:人改起来最顺手。加一句台词就是在编辑器里敲一行,改一句就是改几个字,删一段就是选中删除。
轨道二:图上的台词行——机器的真相。 每句台词一个 LineAudio 节点,携带操作类型(说话 / 旁白 / 转场 / 标记 / 结局)、说话人、文本指纹、立绘引用边、音频产物路径、逐句 status。顺序不由文件行号表达,由 produces 边上的 order 属性表达——初始拆分时隔一千取一个序号(第 1 句 1000、第 2 句 2000……),之后在两句之间插入新句,取中点(1500);中点耗尽才全节重排。
为什么必须两轨?这里躺着本篇最大的一个踩坑。项目早期只有单轨:台词.jsonl——一种逐行 JSON 的结构化剧本文件,人和机器理论上都能编辑。实践几个月后它死了,死因诊断书如下:
- 人根本不会去改一个 JSONL 文件。改一句台词要在 JSON 行里找到转义后的原文,小心翼翼地改引号里的内容,还得保持结构合法。人类作者对它的真实态度是:宁可不动,也不打开。
- 于是文件的「人可编辑」沦为理论特性,实际只有 LLM 单方面维护它。一个号称人与机器共享的格式,实际只有机器在用,这就是僵尸格式——人的修改意图进不来,机器的产物人不想看,双方向的沟越来越深。
- 更糟的是它没有身份概念:行号即身份,插入一行,后面所有行的身份错位;引用它的配音、立绘关系全部漂移。
双轨分离后,两个世界各自拿到了最适合自己的形态:人改 Markdown(顺手),机器读图(精确);而两条轨道之间的同步是全自动的单向阀——拆分器把台词.md 对齐进图,人永远不需要碰图。图是结构化真相,但真相的入口是人类友好的。
注:非音频行(纯旁白、标记、结局行)拆分进图即 11——没有音频要审,就没有审批必要。「节完成」不是一个按钮,是派生判断:提纲=1 且定稿=11 且全部行=11。
6. 幂等对齐:改稿只付增量成本
双轨分离的威力在对齐环节爆发。设定稿审批通过、配音也做了一部分之后,人回头改了台词.md——这在创作里不是异常,是日常。此时拆分器重新运行,做一次幂等对齐:把新 md 与图上已有的行逐句比对(按操作类型 + 说话人 + 文本指纹签名匹配),四种命运:
每种命运背后都是一笔成本账:
- 未变行:什么都不做。尤其关键的是第三个分支——上游(提纲)变更曾把全部行级联作废(-1),但未变句的音频文件还在:校验文本指纹 + 音频存在,直接恢复待审(10),不必重配。级联是粗粒度的保守作废(宁可错杀),对齐是细粒度的精确恢复(放过无辜)。
- 改句:沿用原节点置 0——第 3 篇的 voice key 不变,重配音频覆盖旧文件。行身份稳定在此时兑现价值:这句话的配音历史、审批记录都还挂在同一个节点上。
- 新增句:中点插入,前后句的 order 都不动。
- 删除句:节点与引用边一起删,干净离场。
一句话总结这套机制的意义:人改稿的心智负担归零,系统成本严格增量。改三句话,就只有三句话重配音;插一句,就多配一句。传统管线里「改剧本=相关资产全部重来」的恐惧,被「行身份 + 文本指纹 + 幂等对齐」三件套拆掉了。
7. 剧情反向驱动素材
到这里,前四篇的链都在剧情链的下游等着被驱动。配音 skill 的逐句判别(第 3 篇的四决策)正是驱动现场,本篇补全它的素材侧:
- 选立绘:每句说话行,LLM 沿「场景块 → 场景 → 该场景登记的立绘候选池」挑最贴切的一张,在行与立绘之间建 uses 引用边。候选池按「场景块 × 说话人」组织——因为这个场景里、这个角色、穿过这身衣服的立绘才有资格候选。
- 缺口兜底:池中没有任何贴切的变体时,当场创建一个 status=0 的立绘缺口节点(带变体氛围描述),并保证「场景 → 立绘设计」的登记边存在——第 2 篇的按需生产在这里收到需求信号。
- 着装缺口:新场景出现的角色没有对应着装立绘设计时,同样补登记边,缺口顺藤摸到美术链。
于是生产链的 DAG 长出了回边:剧情(下游)产生素材需求,回灌给美术链(上游)。第 2 篇说「立绘按需生产」,需求的「需」字,此刻才落到实处——它是台词语境里的一句话,不是一个预设清单。全程没有人传话:缺口以图节点形式落地,调度系统自然发现,生产 skill 自然认领。两条链只共享图,不共享会议。
8. 发布:投影,而不是导出
全章就绪(章批准、各节提纲 1 / 定稿 11 / 全行 11、所需立绘 11)后,发布 skill 做最后一跃:把全章图行投影成运行时的单一章 JSON。
「投影」这个词是精确的:运行时格式是图的一个视图,不是另一份要维护的文档。投影器按节序、按 order 把全部台词行线性化拍平(Section 这个编排容器在运行时已无意义,就此消失);说话行的立绘引用沿 uses 边解析成一个全局整键(角色-着装-变体-立绘 id 四段式——最后一段的立绘 id 保证同角色换装重名也不冲突);场景块沿关系边注入对应的背景音乐与场景信息。投影完成后过一道 schema 校验(全链最主要的自动校验之一),失败即中断发布——机器有唯一正确答案的检查,机器全责。
随后资产按状态收录:批准的立绘做抠绿与规格化处理后进运行时目录,批准的音频、归档的 BGM、批准的背景图一并就位;清单文件(manifest)把剧本里的逻辑名映射到实际资产路径——换一张图、重录一句音,只改映射,剧本 JSON 一个字不动。
最后一层隔离在运行时:Godot 工程里的集中式剧本解释器只认纯 JSON(十一种指令),不连数据库、不知道图的存在。游戏玩家打开的是静态产物;创作者的世界在图里。两侧通过投影单向解耦——图怎么演进、节点怎么级联作废,与已发布版本无关;要更新游戏,重新投影发布即可。全流水线至此闭环:世界观文字进来,可玩的游戏出去。
9. 踩坑与演进
坑一:用边表达场景归属,死于维护成本。 场景块最初的设计是让每句台词行向场景建一条「stages 到」的边——语义直观:行属于哪个场景,图上可查。运行一段时间后废止,改行不掩卷:每次拆分对齐、插行删行,都要同步维护这批边的指向;md 与图的对齐过程里,边成了第二份要 reconcile 的状态,错一处,场景归属就张冠李戴。替代方案是结构期预分配场景块 id、写进行级属性——id 是不可变的静态值,一次写好永远不用维护。教训升华为一条建模守则:「关系」适合表达两个独立演进的对象之间的引用(行→立绘,uses 边至今健在),不适合表达「大批量对象的分组归属」——后者用预分配的静态标识更稳。
坑二:级联粒度的权衡与 text_sha1 的诞生。 「改提纲作废全部行」听起来暴力——几十句已批的音频说作废就作废?最初的直觉是把级联做细(只作废真正受影响的行),很快发现细粒度级联需要理解「哪句台词依赖提纲的哪一段」,这个判断本身不可靠。最终方案是两级分工:级联保持粗粒度保守作废(宁可错杀),对齐期用文本指纹精确平反(放回未变句)。粗与细不是二选一,是各守一层——级联保证「绝不用旧」,指纹保证「不重复付费」。这个模式(保守作废 + 精确恢复)后来成了处理一切「级联 vs 增量」矛盾的模板。
坑三:定稿直写待审,没有提交按钮。 早期设计里有「生产完成 → 人工点提交 → 进入待审」的两步流程,实践下来纯属仪式:没有任何定稿在生产完成后不想进入审批。于是剧情链全部改为生产完成直写 10——审批的意义在「人工看过」,不在「人工申请被看」。流水线里每个要多按一次的按钮,都要回答「这一下阻止了什么事故」;答不出来,就删掉。
/*=============================================================*/
作者:CrazyJinn
本文版权归作者所有,欢迎转载.但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
如果看完这篇文章让您有所收获,请点击右下角"推荐".
如果这篇文章让您觉得不知所云,或者通篇谬误,请点击右下角"反对".并且欢迎您留言给我提出宝贵的意见.
如果您想获知我最新的动态,可以在绿色通道中点击"关注我".
/*=============================================================*/

浙公网安备 33010602011771号