内容流水线

写第 40 章,该喂哪些前文?

长篇章节生成的关键难点不是单章质量,而是如何在上下文窗口限额内,调度出真正有用的设定与前文,同时保证事实一致性。

每次生成小说的一章,调度器要做三个决策:注入哪些世界设定、哪些前文摘要、哪些结构约束。这不是一个简单的"贪心召回"问题,而是要在有限的上下文窗口内,权衡相关性、预算和一致性的三角形约束。

调度问题的三个维度

相关性:召回真正需要的设定与前文

生成第 10 章时,模型需要知道的背景信息远超过上下文容量。世界观有多条规则线,前文有 9 章的事件积累,人物有 10 多个角色的状态变化,每一项都可能与当前章节相关。

相关性检索的核心是"这些东西与当前章节生成任务有多大的影响"。这不只是 Qdrant 的向量相似度匹配。一条"主角接到任务时必须穿过北城门"的世界规则,与其他几条规则的组合方式,决定了它对第 10 章是否真正有约束力。

系统里的做法是把世界观资源分层:

  • 硬约束层:世界核心规则、人物基础设定、已确定的事实
  • 软约束层:前文原文、场景描写、对话
  • 可选层:已排除的假设、备选方向

向量检索时,应该先检索硬约束层,再按优先级检索软约束层,最后考虑可选层。这个顺序的反转会导致"生成偏离世界规则但文采很好"的常见问题。

预算:在窗口限额内排序

假设模型上下文窗口是 8K tokens,去掉系统 prompt、生成目标、章节大纲,实际可用空间约 6K。这 6K 要装下:

  • 世界观摘要(500-800 tokens)
  • 相关人物设定(300-500 tokens)
  • 前 N 章摘要(1000-2000 tokens)
  • 本章拆细(200-300 tokens)
  • 写法约束(200-300 tokens)

就算每项都精简,也很容易超出。这时候需要动态预算:系统估算本章的生成复杂度(新人物出现?大事件转折?),动态调整各部分的分配。

简单的做法是按字数均分,结果通常是浪费。好的做法是:

  1. 把硬约束固定分配(不能省)
  2. 把相关性最高的前文摘要(不是原文)作为主体
  3. 其余空间留给可选背景

前文不用原文,用摘要。这是关键优化。一章正文 2000 字,用 200 字的摘要(关键事件 + 角色状态变化 + 留下的悬念)可以承载 80% 的必要信息,剩下 20% 的细节(某个对话的原词、场景的视觉细节)在绝大多数情况下不影响后续章节的生成一致性。

一致性:跨章节事实的映射

第 10 章里模型可能生成"某交易的金额是 5000 元",第 11 章的调度器需要知道这个信息。但如果第 10 章生成了两个版本(一个 5000 元,一个 6000 元),调度器用了不同的版本,第 11 章可能会自相矛盾。

这是故事"越写越散"的根本原因。传统做法是写完全文后回头检查一致性,那时候改得很贵。好的做法是在每章生成后,立即抽取"硬事实"(人物位置、已完成交易、确定的时间戳、确认过的背景细节),写入一个"事实账本",下一章生成时优先查这个账本。

这不是自然语言的摘要,而是结构化的事实提取:交易金额、时间点、位置坐标、角色关系状态。第 11 章的模型看到的前文摘要里,这些数字必须与事实账本对齐。

LangGraph 的角色:流程与状态

LangGraph 的工作是管理整个调度流程和状态转移。它不生成小说,而是组织生成的前置条件。

一个最小的调度 DAG 是这样的:

检索相关世界规则 → 检索前文摘要 → 检索事实账本
            ↓
        动态预算分配
            ↓
        确定最终上下文
            ↓
        调用生成模型
            ↓
        检测一致性问题
            ↓
    是否需要修复 → 是 → 重新调度 + 重新生成
            ↓ 否
        提取并记录新事实
            ↓
        状态转移到下一章

LangGraph 在这个流程中的价值是:

  1. 可观察性:每一步的输入输出都记录,可以回放整个调度决策过程
  2. 可恢复性:如果中间某一步失败(比如生成模型超时),可以从失败点恢复,不用重新调度前面所有步骤
  3. 条件分支:一致性检测失败时,可以触发自动修复流程,而不是简单地重试整个生成
  4. 状态机:跨多章的生成是有顺序的,章 N 的状态会影响章 N+1 的调度。LangGraph 管理这个状态链

代码层面,这意味着每个节点是一个独立的可调用单元,节点间通过状态对象通信。比如"动态预算分配"这个节点,它的输入是"已检索的资源列表 + 本章复杂度评分",输出是"每个资源的分配 token 数",这个输出成为下一个节点的输入。

Qdrant 的角色:相关性与召回

Qdrant 存储两类向量:

  1. 世界观资源的向量化(规则、势力、地点、角色设定)
  2. 历史章节的向量化(章节摘要、关键事件、角色状态快照)

调度时,系统用当前章节的"生成任务"(比如"主角在封闭病区内发现病历记录不一致")作为查询向量,去 Qdrant 检索。

检索策略分两层:

第一层:硬约束检索

用专有字段(not 向量相似度)精确匹配。比如"这章涉及的人物有:角色 A、角色 B",那么系统直接从数据库里取这两个角色的设定,不走向量检索。硬约束必须 100% 准确。

第二层:软上下文检索

用向量相似度检索前文摘要、相关规则、可用场景要素。设置相似度阈值(比如 0.7),只返回真正相关的资源。

一个常见的优化是使用混合检索:用关键词和向量相似度结合。比如检索"与角色 A 相关的前文事件",既用 BM25 匹配"角色 A"这个关键词,又用向量相似度找相似的事件类型。这能减少"语义相关但实际无关"的召回。

优先级策略:硬约束优先

一个实际的优先级排序是这样的:

第一梯队(固定,必须纳入)

  • 当前章节涉及的所有人物的最新设定
  • 上一章的事实账本
  • 本章任务单里的硬约束("主角必须提到过的某个承诺")
  • 世界核心规则中与本章有直接冲突关系的部分

第二梯队(按相关性,逐个加入直到预算用尽)

  • 历史章节中提到过的相关地点描写
  • 相关势力或人物的行动线
  • 前 3 章的事件时间线
  • 可能在本章触发的伏笔提示

第三梯队(可选,仅在预算充足时加入)

  • 其他角色的背景故事
  • 世界观的附加说明
  • 参考范本

这个优先级的核心原则是:生成一致性 > 生成创意。第二梯队和第三梯队是为了提升文章质量,但如果加入它们会导致硬约束无法完整表达,就必须删掉。

一致性检测与修复流程

生成完成后,系统会用一个检测模块检查:

  1. 本章提到的人物位置与上章是否矛盾
  2. 本章提到的时间戳是否与事实账本对齐
  3. 本章是否违反了硬约束规则
  4. 本章是否引入了未设定过的背景信息

如果检测到矛盾,调度器不是简单地重新生成,而是定向修复:

  • 位置矛盾:部分改写那个段落,保持其他内容
  • 时间矛盾:调整时间戳,保持事件顺序
  • 规则违反:提示模型重新考虑那个场景
  • 未设定背景:或纳入世界设定,或要求模型移除

这需要生成模块支持"部分修复"而不是"全盘重试"。全盘重试成本高且容易导致连锁问题(修好了位置矛盾,却引入了新的对话矛盾)。

现有系统的实现参考

项目里已经实现了的相关部分:

"本书世界、角色、拆书、知识库联动"模块说明系统已经在做这些事:世界观能生成世界骨架和世界手册,角色准备会结合势力倾向和世界规则,知识库文档能回灌到规划和正文生成。这是调度器的底层数据来源。

"章节定稿时自动抽取正文中的关键硬事实并写入事实账本,下一章生成时即可读到真实前文"这一项正是上面说的事实账本机制,系统已经开始做了。

"修复懒规划(JIT)模式下结构化大纲步骤被误报"未产出"的问题"说明系统在处理的一个具体问题是:生成任务和实际输出的不对齐。调度器需要理解"这一步预期输出什么"和"实际输出了什么"之间的差异。

一致性和失败处理这两个难点,已经不是理论讨论,而是项目里正在打磨的工程问题。调度器的价值体现在能多快地从这些失败中恢复。

星野的头像

星野 XINGYE

一个人维护 AI 平台的工程师。这里记录 63 篇复盘:18 份故障档案、OTA、架构演进与工作流。