AI写到第30章就"失忆"?15条状态轨详解
前言
上一篇讲了8级门禁,有同学问了一个关键问题:G1门禁检查"15条状态轨是否完整加载",但这15条轨到底是什么?它们怎么解决AI的"失忆"问题?
好问题,这篇就来回答。
先说个大家都有过的体验:你用AI写小说,写到第30章时突然发现------第3章说主角穿灰色卫衣,第28章变成了白色连衣裙;第7章老教授埋了句意味深长的话,到第30章还没回收;第12章口头禅是"该是我的,一分不让",第25章变成了"我一定要赢"。
你以为是AI蠢,其实不是------是AI真的"忘了"。
这篇讲的就是怎么给AI装一个"外部记忆体",让它在第270章仍然记得第3章的每一个细节。
AI为什么会"失忆"
先讲清楚问题根源。
大语言模型的上下文窗口是有限的。128K上下文听起来很大,但塞不下30章×1500字=4.5万字的正文+设定文档。当你开新对话写第30章时,模型对前29章的"记忆"完全依赖摘要------而摘要必然丢失细节。
本质上,AI写长篇的一致性问题,等于**"状态丢失"**问题。就像程序运行到第30个周期时,所有全局变量被重置了------程序当然会崩溃。
解决方案:给AI装一个外部记忆体。不依赖上下文窗口,而是用15条独立的状态文件持久化所有关键信息,在每章写作时按需加载。
为什么"摘要"解决不了问题
很多人想到的第一个方案是"每章写完后生成摘要,下次写作时加载摘要"。我试过,不够用。
| 维度 | 摘要方案 | 状态轨方案 |
|---|---|---|
| 信息保留 | 摘要必然丢失细节,只保留大意 | 逐项持久化,细节不丢失 |
| 可查询性 | 只能整段加载,无法按需查询 | 支持按角色/伏笔/时间等维度精确查询 |
| 可校验性 | 无法自动检测矛盾 | 支持轨间交叉校验 |
| token消耗 | 摘要越写越长,token爆炸 | 只加载当前章节相关的状态切片 |
| 扩展性 | 摘要格式不固定,难以扩展 | JSON结构化,易于扩展和修改 |
摘要是**"记大概",状态轨是"记精确"**。主角穿灰色卫衣这种细节,摘要里不会保留------但对长篇一致性来说,这个细节不能丢。状态轨的价值在于:把所有"看似不重要但一旦矛盾就会被发现"的细节,都持久化下来。
15条状态轨完整清单
15条轨按功能分为4大类:角色管理(5条)、叙事管理(4条)、节奏管理(3条)、世界管理(3条)。
类别一:角色管理(5条)
- 01 角色状态轨:位置/情绪/关系/已掌握信息
- 02 语言指纹轨:口头禅/语气词/句式偏好/禁用词
- 03 Soul Field轨:人设铁律及当前遵守状态
- 04 情感弧线轨:好感度数值变化曲线
- 05 信息差轨:谁知道什么/谁不知道什么
类别二:叙事管理(4条)
- 06 伏笔登记轨:伏笔编号/内容/回收计划/状态
- 07 已确立事实轨:时间/地点/物品/外貌等硬事实
- 08 章节摘要轨:每章300字摘要(辅助用)
- 09 钩子类型轨:逐章章末钩子类型记录
类别三:节奏管理(3条)
- 10 节奏温度轨:逐章温度档位记录
- 11 爽点计数轨:小爽/大爆/极爆累计统计
- 12 张弛状态轨:逐章张/弛标注与连续计数
类别四:世界管理(3条)
- 13 道具清单轨:重要道具持有者/位置/状态
- 14 空间位置轨:各角色当前所在地点
- 15 时间线轨:故事内时间推进记录
5条核心状态轨的数据结构
15条轨中,有5条是核心------它们直接决定了AI能否写出一致的内容。逐一拆解。
01 · 角色状态轨(角色管理 · 核心)
记录每个角色在每一章结束时的完整状态:在哪、什么情绪、和谁什么关系、知道什么、不知道什么。这是最基础的一条轨------如果这条轨丢了,所有其他轨的校验都会失效。
json
{
"character_id": "lin_zhiwan",
"chapter": 30,
"location": "深圳·南山区·深智科技总部·3楼会议室",
"emotion": "冷静但暗藏愤怒",
"relationships": {
"shen_jing": { "type": "对手", "affection": -0.5, "change": "↓0.2" },
"zhou_professor": { "type": "导师", "affection": 0.8, "change": "---" }
},
"known_info": [
"沈婧窃取方案B的证据",
"周教授的真实身份是功劳簿系统前代使用者"
],
"unknown_info": [
"沈婧背后的人",
"功劳簿系统的终极代价"
],
"active_goal": "在下周一的评审会上拿回方案B的署名权",
"blocking": "沈婧可能在评审前销毁证据"
}
02 · 语言指纹轨(角色管理 · 核心)
记录每个角色的说话方式------口头禅、语气词、句式偏好、禁用词。这是防止"角色声音趋同"的关键。没有这条轨,AI写到第30章时,所有角色的说话方式都会变成同一种"AI腔"。
json
{
"character_id": "lin_zhiwan",
"catchphrases": ["该是我的,一分不让", "证据呢", "我等这一天很久了"],
"tone_words": { "嗯": 0.8, "呵": 0.5, "------": 0.7 },
"sentence_style": {
"avg_length": "短句为主(8-15字)",
"pattern": "陈述句+偶尔反问收尾",
"emotion_expression": "克制型,用行为暗示而非直白情绪词"
},
"forbidden_words": ["人家", "嘛", "讨厌啦", "哼"],
"speech_samples": [
"第3章: '该是我的,一分不让。证据都在这里。'",
"第12章: '嗯。我等这一天,很久了。'"
]
}
为什么需要speech_samples?因为口头禅列表告诉AI"该用什么词",但speech_samples告诉AI"这些词在什么语境下、以什么句式使用"。两者配合,才能让角色的声音在270章里保持一致。
06 · 伏笔登记轨(叙事管理 · 核心)
这是长篇小说最容易出问题的地方。伏笔登记轨记录每一个伏笔的编号、内容、埋设章节、计划回收章节和当前状态。全书37个伏笔,每一个都有唯一编号。
json
{
"foreshadows": [
{
"id": "FB001",
"planted_chapter": 3,
"content": "周教授办公桌上那封未署名的信",
"plan_recover_chapter": 45,
"actual_recover_chapter": null,
"status": "planted",
"importance": "P0",
"related_characters": ["zhou_professor", "lin_zhiwan"]
},
{
"id": "FB037",
"planted_chapter": 268,
"content": "沈婧手机里那张十年前的合照",
"plan_recover_chapter": 270,
"actual_recover_chapter": null,
"status": "planted",
"importance": "P0",
"related_characters": ["shen_jing", "lin_zhiwan"]
}
],
"stats": {
"total": 37,
"planted": 35,
"recovered": 2,
"overdue": 0,
"p0_count": 12
}
}
05 · 信息差轨(角色管理 · 核心)
这是最容易被忽略但最重要的一条轨。它记录"谁知道什么、谁不知道什么"。很多剧情冲突的本质就是信息差------主角知道但反派不知道,或者反过来。如果信息差管理不好,就会出现"角色不应该知道这个信息却做出了反应"的逻辑bug。
json
{
"chapter": 30,
"info_matrix": {
"lin_zhiwan": {
"knows": ["沈婧窃取了方案B", "功劳簿系统可以溯源"],
"doesnt_know": ["沈婧背后有人指使", "周教授的真实身份"]
},
"shen_jing": {
"knows": ["林知晚重生了(猜测)", "方案B的原作者是林知晚"],
"doesnt_know": ["林知晚有功劳簿系统", "周教授在帮林知晚"]
},
"zhou_professor": {
"knows": ["林知晚有功劳簿系统", "沈婧背后的人是谁"],
"doesnt_know": ["林知晚已经发现了信件"]
}
}
}
信息差bug是最隐蔽的bug。角色不应该知道的信息,如果AI让角色做出了反应,读者会立刻觉得"不对劲"------但读者可能说不出哪里不对。这种隐性矛盾是长篇小说的隐形杀手。信息差轨的作用就是让这种矛盾可检测。
07 · 已确立事实轨(叙事管理 · 核心)
记录正文中已经写过的所有"硬事实"------时间、地点、物品、人物外貌、天气等。这些事实一旦确立,后续章节就不能矛盾。这就是防止"灰色卫衣变白色连衣裙"的轨。
json
{
"chapter": 30,
"facts": {
"character_appearance": {
"lin_zhiwan": "灰色连帽卫衣,马尾,不化妆",
"shen_jing": "白色衬衫裙,淡妆,戴细框眼镜"
},
"locations": {
"company": "深智科技·南山区·3楼",
"meeting_room": "3楼·会议室B·靠窗位置"
},
"time": {
"current_date": "第2周·周三",
"last_event": "周三下午3点·评审会"
},
"objects": {
"merit_book": "黑色封面笔记本,林知晚随身携带",
"letter": "未署名信件,周教授办公桌第二层抽屉"
}
}
}
状态轨的自动更新流程
15条轨不是手动维护的------每一章写完并通过G8人工确认后,系统自动从正文中提取状态变更并更新15条轨。
整个流程是这样的:
- 章节写作完成 --- AI生成正文,通过G3-G6门禁检测
- 状态提取 --- AI读取本章正文,提取状态变更:
extract_state(chapter_text) → state_diff - 轨间交叉校验 --- 检查状态变更是否与已有状态矛盾(如角色同时出现在两个地点)
- 状态合并 --- 将
state_diff合并到15条轨的JSON文件中:merge_state(tracks, state_diff) - G8人工确认 --- 作者审核正文+状态变更,通过则正式写入
- 写入磁盘 --- 15条轨JSON文件持久化到
dynamic/tracks/目录
python
# 状态更新伪代码
def update_tracks(chapter_num, chapter_text):
# 1. 提取本章状态变更
state_diff = ai_extract_state(chapter_text)
# 2. 加载当前所有状态轨
tracks = load_all_tracks(chapter_num - 1)
# 3. 交叉校验
conflicts = cross_validate(tracks, state_diff)
if conflicts:
return UPDATE_FAIL(conflicts)
# 4. 合并状态
new_tracks = merge_state(tracks, state_diff)
# 5. 人工确认
if author_approve(chapter_text, state_diff):
# 6. 写入磁盘
save_all_tracks(new_tracks, chapter_num)
return UPDATE_SUCCESS
else:
return UPDATE_REJECTED
写第N章时加载什么
15条轨的全量数据在270章时会非常大------不可能每次写作都全量加载。需要按需加载。
| 轨 | 加载策略 | 加载量 |
|---|---|---|
| 角色状态轨 | 加载本章出场角色的最新状态 | ~3-5个角色 |
| 语言指纹轨 | 加载本章出场角色的指纹 | ~3-5个角色 |
| 伏笔登记轨 | 加载status=planted且plan_recover≤N+5的伏笔 | ~5-10个 |
| 已确立事实轨 | 加载最近5章的事实+全局硬事实 | 最近5章 |
| 信息差轨 | 加载本章出场角色的信息矩阵 | ~3-5个角色 |
| 节奏温度轨 | 加载最近10章的温度序列 | 10章 |
| 章节摘要轨 | 加载最近3章摘要 | 3章 |
| 其他 | 按需加载 | 视情况 |
按需加载的核心原则:模型的上下文窗口不需要装下270章全文,只需要在每章写作时加载当前相关的状态切片------就像程序运行时从数据库查询数据,而不是把整个数据库加载到内存。这把"上下文窗口不够"的问题彻底解决了。
轨间协同:15条轨不是孤立的
15条轨之间有协同关系------一条轨的变更会触发其他轨的校验或更新。
| 触发轨 | 变更 | 联动轨 | 联动动作 |
|---|---|---|---|
| 角色状态轨 | 角色A知道了信息X | 信息差轨 | 从doesnt_know移到knows |
| 角色状态轨 | 角色A位置变为Y | 空间位置轨 | 更新A的当前位置 |
| 角色状态轨 | A对B好感度变化 | 情感弧线轨 | 追加数据点 |
| 伏笔登记轨 | 伏笔FB037被回收 | 已确立事实轨 | 伏笔内容变为确立事实 |
| 已确立事实轨 | 新事实"角色A持道具X" | 道具清单轨 | 更新道具持有者 |
| 章节摘要轨 | 第N章摘要生成 | 节奏温度轨 | 从摘要提取温度标注 |
轨间协同让15条轨不是15个孤立文件,而是一个联动的状态网络。一条轨的变更会自动传播到相关轨,确保所有维度的状态保持一致。这就像数据库的级联更新------改了一个表,关联表自动更新。
实战案例:灰色卫衣如何在第280章仍然一致
用一个具体例子展示状态轨怎么工作。第3章建立了"林知晚穿灰色连帽卫衣"这个事实,到第280章时怎么保证不矛盾?
- 第3章 --- 正文写入"林知晚穿着那件灰色连帽卫衣" 状态提取 → 已确立事实轨更新:
lin_zhiwan.appearance = "灰色连帽卫衣,马尾,不化妆" - 第15章 --- 正文写入"林知晚换了件白色连衣裙" 状态提取 → 检测到外貌变更 → 已确立事实轨更新:
lin_zhiwan.appearance = "白色连衣裙,马尾"注意:不是矛盾,是变更。事实轨记录的是当前状态,不是初始状态。 - 第28章 --- AI试图写入"林知晚穿着灰色卫衣" 状态加载 → 事实轨显示当前外貌是"白色连衣裙" → G3检测到与已确立事实矛盾 → 拦截
- 第280章 --- 写到林知晚时 状态加载 → 事实轨显示第279章结束时外貌(可能是最新变更) → AI基于最新事实写作,不会矛盾
事实轨记录的不是"第3章的设定",而是**"到上一章为止的最新状态"**。当角色换衣服时,事实轨会更新------这不是矛盾,是变更。真正的矛盾是"角色在第28章穿着白色连衣裙,但AI写她穿灰色卫衣"------这才是G3要拦截的。
情感弧线轨:270章好感度变化
情感弧线轨记录主角与各角色的好感度数值变化。这条轨的特殊之处在于它是一条数值曲线------可以可视化。
从数据来看:好感度从初始的+0.3(闺蜜),到第30章降至-0.2(发现窃取),到第100章降至-0.6(正面冲突),到第200章回升至-0.1(开始理解),到第270章回到+0.2(终局和解)。这条曲线是自动生成的------每章写完后,AI根据本章的互动内容更新好感度数值。
为什么是15条,不是5条或25条
这是开发过程中反复调整的数字。最初设计了25条,太多------维护成本高,加载慢,有些轨的使用频率极低。最终精简到15条,刚好覆盖了所有核心一致性维度。
| 版本 | 轨数 | 问题 | 结果 |
|---|---|---|---|
| v1 | 8条 | 信息差、空间位置、时间线未覆盖,导致信息差bug和时空矛盾 | 不够用 |
| v2 | 25条 | 太多,部分轨使用率<5%,加载慢,维护成本高 | 过度设计 |
| v3(最终) | 15条 | 覆盖所有核心一致性维度,每条轨使用率>20% | 平衡点 |
状态轨的数量不是越多越好------每多一条轨,维护成本和加载成本就多一份。15条是"刚好够用"的平衡点:少一条会有盲区,多一条是浪费。这个数字是经过3个月实践验证的。
总结
回到最初的问题:如何给AI装一个"外部记忆体",让它在第270章仍然记得第3章的每一个细节?
第一层:持久化存储 --- 把AI的"记忆"从上下文窗口搬到文件系统,解决"上下文不够"的物理限制。
第二层:结构化查询 --- 不是把所有历史塞进prompt,而是按需查询当前相关的状态切片,解决"token爆炸"问题。
第三层:联动校验 --- 15条轨不是孤立的,而是联动的状态网络。一条轨的变更自动传播到相关轨,确保所有维度的状态一致。
核心要点提炼:
- 摘要方案解决不了问题 --- 摘要"记大概",状态轨"记精确",细节不丢失
- 15条轨分4大类 --- 角色管理5条、叙事管理4条、节奏管理3条、世界管理3条
- 按需加载是关键 --- 不全量加载,只加载当前章节相关的状态切片,像数据库查询一样
- 轨间协同形成状态网络 --- 一条轨变更自动传播到关联轨,保证多维度一致
- 事实轨记录的是"当前状态" --- 角色换衣服是变更不是矛盾,AI基于最新事实写作
用一句话总结:给AI装"外部记忆体"比扩大上下文窗口更有效。模型的上下文窗口不需要装下270章全文,只需要在每章写作时加载当前相关的状态切片------就像程序运行时从数据库查询数据,而不是把整个数据库加载到内存。
下一篇,我会拆解核心创意卡------5项不可修改的设定如何像锚一样,把270章的故事牢牢固定在原始创意方向上。
本文是「AI写作工程化」系列第3篇。如果觉得有帮助,点个赞吧。你觉得这种"外部记忆体"的思路怎么样?评论区聊聊。