长篇小说写到三十万字后,"记住前面写了什么"变成最大的瓶颈。角色在第五章确立的设定,到第二十章突然对不上;伏笔埋了二十章没回收;世界观里的时间线出现逻辑洞;前面说过的势力关系后面又改了。全量注入上一章或全书到上下文里根本不可能,纯向量检索又容易因为相似度不够而漏掉关键的硬约束。
这个问题需要分层的记忆系统。根据信息的稳定性和用途把记忆分成三层:设定层、事实层、文本层。每层的存储方式和检索策略完全不同。
为什么不能统一用向量库
一个很自然的想法是"把所有信息存到向量库里,需要时向量检索"。但设定信息不行。
世界规则、人物档案这类信息是硬约束,一旦因为向量相似度不够高而没被召回,就会产生直接的设定冲突。模型可能生成"主角这章掌握了某个禁忌知识",但系统没召回"世界规则里明确说这个知识是自杀性的",结果后续剧情完全跑偏。向量检索是概率性的,概率性检索不能承载硬约束。
事实信息(已发生的事件、角色状态变化、伏笔)可以用向量检索,因为"不完美的匹配"还能通过更多文本从模型推理出来。如果系统检索到"角色在某章失去了一条胳膊"这个事实后又检索到"这个事件在剧情中的含义是……",模型有足够的上下文修复漏掉的细节。
原文(正文片段)是纯量级的数据,全量注入的成本太高,用摘要替代是更经济的做法。
设定层:结构化存储、全量或定向注入
设定层装的是世界级的硬规则和静态档案,包括:
世界规则(约 600 字压缩)
- 现实是否稳定、超常能力是否公开、死亡是否可逆、信息获取是否受限
- 这个世界"允许什么、不允许什么"
系统性规则(通常 4-6 条)
- 力量体系的上限、交易与代价的原理、禁忌知识的危害方式
主要势力(通常 3-5 个)
- 每个势力的名称、目标、常用手段、与其他势力的关系
核心人物档案(通常 4-8 个)
- 每个人物的身份、核心目标、掌握的信息、心理底线
这些东西在整部小说中是不变的(或变化极缓),写作的任何环节都需要遵循它们。设定层必须在调用 AI 生成章节时全量注入或按需定向注入。全量注入适合小说世界相对简洁的情况;如果世界复杂设定众多,可以做定向注入——比如这一章涉及势力 A,就只注入 A 的档案和相关规则。
关键是:设定层的记忆片段永远不能因为上下文窗口压力而被省略。这是整个系统的天花板。
事实层:向量检索 + 时间过滤
事实层装的是已经发生的、会影响后续剧情的信息。
章节摘要(每章一句话)
- "主角从势力 B 得到了关键物品 X,但同时被势力 A 注意到了"
角色动态状态(追加式、非覆盖)
- 某角色掌握了什么新信息、失去了什么能力、和某人的关系发生了什么变化
伏笔记录
- 埋下的伏笔及其状态(待回收 / 已回收)、涉及的章号
时间线(关键事件及其时间距离)
- "第五章后的第三天,X 事件发生"
世界新设定(剧情中确立、原设定没有的)
- "这个世界原本不知道 X,但第十二章中 Y 揭露了 X"
这一层用向量检索的原因是数据量大(几十万字的小说可能有几百条事实)且不需要完美精确。模型在知道"五章前主角失去了左腿"和"十章前主角加入了某组织"的基础上,能够合理推理出后续事件。即使系统漏掉了某条非关键事实,模型也不太会产生硬冲突。
时间过滤很重要。检索结果应该默认优先最近的事件,因为离当前章节越近的事件通常影响力越大。"三章前角色的转折"比"五十章前的背景"更应该被注入。
文本层:只取最近段落
文本层就是原始的正文片段,用于衔接语气和细节。一个几十万字的小说,全部原文根本放不进上下文。
解决方案是简单的:只注入前一章的结尾(约 800 字),这足以让模型维持住文笔连贯性和情感线的延续。对于需要回顾很久之前的情节细节的场景,用事实层的摘要替代——"第五章中,X 因为 Y 而死亡"这一条摘要比翻出整个第五章的原文高效得多。
当然也存在"某章需要直接引用或高度呼应某个很久以前的场景细节"的情况。这时候文本层可以临时扩大范围,但这是特例,不是常态。
具体的实现策略
设定层在每次生成章节前直接注入——要么全部、要么按这章涉及的范围选择。不需要任何检索逻辑,就是结构化的数据块。
事实层维护一个 memory.json 文件,存储:
synopsis:全书概要,每章更新后重写,封顶 1000 字chapterDigests:逐章一句话摘要characters:角色的动态状态(与静态档案分开)foreshadow:伏笔列表,标记待回收或已回收timeline:关键事件及章号和相对时间worldFacts:剧情中新确立的设定事实
每章生成完成后,系统调用一次 AI,输入"旧记忆 + 本章正文",要求输出增量——这一章新增了什么伏笔、角色状态如何变化、有没有新设定。然后用纯函数 normalizeMemory() 合并增量到旧记忆里:新伏笔追加、已回收伏笔置状态、角色按 name upsert(同 ID 的覆盖)、synopsis 重写、timeline 追加。
生成下一章时,buildChapterMessages() 的流程变成:注入设定块 → 注入记忆块(由 buildMemoryContext() 生成) → 注入上一章结尾 → 生成新章。记忆块里包含:最近 6 章摘要、全部角色现状、最后 8 条未回收伏笔、最后 5 条时间线、最后 10 条世界新设定。这些都是硬上限,防止记忆块因为章数增多而无限膨胀。
一致性与失败处理
这套流水线的核心难点不是单点生成质量,而是一致性和失败恢复。
一致性来自增量而不是合并。每章记忆更新要求 AI 只输出增量,而不是整个记忆的重写。这样设计有两个好处:一是防止 AI 每次都改掉前面的内容(一种无意义的膨胀),二是增量小得多,解析 JSON 时出错的概率降低。合并逻辑交给纯函数 normalizeMemory(),这个函数可以单测,保证逻辑稳定。
同一章重建幂等。由于 chapterDigests 按章号存储,相同章号的摘要会覆盖而不是追加,所以即使记忆重建时对同一章调用多次,也不会出现重复记录。角色状态的 upsert 机制也是同理。
记忆更新失败不影响正文。每章正文先落盘、记忆更新在后。如果记忆更新失败(比如 AI 返回格式错误、JSON 解析异常),降级处理:用这章的 title 或 summary 作为摘要追加到 chapterDigests,lastChapterNo 照常推进,其余记忆保持不变。这样下一章的生成可以继续进行,用户不会察觉到记忆层的故障。
重建任务的断点续跑。存量书如果想补全记忆,后台可以跑 runMemoryRebuild() 任务,按章序遍历,跳过 lastChapterNo 以内的章(已纳入过的)。这个任务可停、可继续,防止重复扣费。
记忆分层的边界
这个设计对应的问题空间是:长篇写作中保持内容一致性和连贯性。它解决的是系统层面的记忆管理,不覆盖人工的内容审校和设定调整。
如果作者在某个时刻决定"我要改前面某角色的设定",那是人为修改设定层、然后手动落盘的过程。系统的记忆不会自动同步这种改动,因为改动涉及主观判断。类似的,如果某章生成出来的内容和记忆产生冲突(比如模型莫名其妙加了个新势力),那也需要人工介入编辑,而不是靠记忆系统自动修正。
记忆系统的职责是:提供足够的上下文约束,让模型生成时减少无意义的冲突;一旦冲突出现,系统快速降级,不中断工作流。
■