feat: expand novel IP and production workflows

This commit is contained in:
www
2026-09-18 08:14:05 +02:00
parent b2ae4600b4
commit d9c81a3ac0
235 changed files with 117971 additions and 2721 deletions
+511
View File
@@ -0,0 +1,511 @@
如果这样,那章节越多,后续要传递给api的参数就越多?
是的,**如果你每次都把前面所有章节正文传给 API,章节越多,参数一定越来越大,成本会爆,速度也会慢。**
但真正的长篇小说系统**不能这么做**。
正确做法是:
> **不是把全部正文传给模型,
> 而是把“压缩后的关键记忆 + 当前章节相关内容”传给模型。**
也就是说,后面写第 100 章,不需要把前 99 章全文都传进去,只需要传:
```text
小说圣经摘要
当前卷纲
最近 3-5 章摘要
本章相关人物状态
本章相关伏笔
本章章节卡
禁止改动规则
文风规则
```
这样 API 输入会长期保持稳定,不会随着章节无限增长。
---
# 一、错误做法:全文堆上下文
比如写第 80 章时,你把第 1–79 章全部塞进去:
```text
第1章全文
第2章全文
第3章全文
...
第79章全文
请写第80章
```
这个做法有几个问题:
1. token 成本越来越高;
2. 请求越来越慢;
3. 模型容易被大量旧内容干扰;
4. 真正重要的信息反而被淹没;
5. 超过上下文长度后直接无法调用;
6. 多模型协作时更难稳定。
所以长篇流水线绝对不能靠“全文传递”。
---
# 二、正确做法:三层记忆压缩
你要做的是**分层记忆**。
## 第一层:永久核心记忆
每次都传,但内容要很短。
包括:
```text
小说一句话核心
世界观规则
主角核心人设
主要角色不可改动项
文风规则
禁用桥段
短剧改编规则
```
控制在 **10002000 字**
这部分相当于小说宪法。
---
## 第二层:近期记忆
每次只传最近 35 章摘要。
比如写第 80 章,只传:
```text
第75章摘要
第76章摘要
第77章摘要
第78章摘要
第79章摘要
```
不传全文。
每章摘要控制在 150300 字。
总共大概 **10001500 字**
---
## 第三层:检索记忆
这部分不是每次都传全部,而是按本章需要查。
比如第 80 章出场人物是:
```text
岑青
陈淑蘅
姚知知
```
那就只查这几个人的状态:
```text
岑青当前知道了什么
陈淑蘅隐瞒了什么
姚知知上次出现在哪里
她们之间的关系变化
```
如果本章涉及某个伏笔,就只查相关伏笔。
比如:
```text
F012:被撕掉的签到簿缺页
F018:姚知知画本里的第五只手
```
不相关的伏笔不传。
---
# 三、写第 100 章时,真正传给 API 的应该是这样
不是:
```text
前99章全文 + 请写第100章
```
而是:
```json
{
"bible_summary": "小说核心设定摘要,约1500字",
"style_rules": [
"克制",
"电影感",
"不狗血",
"不打脸复仇",
"对白短而有张力"
],
"current_volume_outline": "当前第3卷卷纲摘要,约800字",
"recent_chapter_summaries": [
"第95章摘要",
"第96章摘要",
"第97章摘要",
"第98章摘要",
"第99章摘要"
],
"active_character_states": [
{
"name": "岑青",
"current_state": "已经确认林照不是一个人,但还缺最后证据"
},
{
"name": "陈淑蘅",
"current_state": "知道周榕真名,但仍不愿公开其他女工身份"
}
],
"active_foreshadows": [
{
"code": "F012",
"title": "签到簿缺页",
"status": "developing",
"expected_reveal": "第102章"
}
],
"chapter_card": {
"chapter_no": 100,
"title": "缺页",
"goal": "岑青找到签到簿缺失页的线索",
"must_happen": [
"姚知知交出画本",
"岑青发现画本夹层里有一页旧纸",
"陈淑蘅第一次失控"
],
"ending_hook": "纸页上不是一个名字,而是五个名字"
}
}
```
这个上下文即使写到第 500 章,也可以控制在 **40008000 字**以内。
---
# 四、上下文不是越多越好,而是越准越好
很多人误以为:
> 传越多,AI 越不会乱。
其实不一定。
真正有效的是:
```text
重要信息完整
无关信息少
当前任务明确
禁止事项清楚
```
你给模型塞 30 万字前文,它不一定抓得住重点。
但你给它一份高质量上下文:
```text
当前主线
当前人物状态
当前伏笔
上一章结尾
本章目标
不能写什么
```
它反而更稳。
---
# 五、你系统里要做“记忆压缩器”
每写完一章,就让 AI 或程序生成一份压缩记忆。
比如第 20 章正文有 3000 字,压缩成:
```json
{
"chapter_no": 20,
"summary": "岑青在旧仓库找到签到簿,发现林照名下有五种笔迹。",
"character_updates": [
{
"name": "岑青",
"update": "开始怀疑林照不是单一人物"
},
{
"name": "陈淑蘅",
"update": "看到签到簿后明显紧张,但拒绝解释"
}
],
"new_foreshadows": [
{
"code": "F020",
"title": "被撕掉的一页",
"surface": "签到簿中间缺了一页",
"hidden_truth": "缺页记录了火灾当晚真实值班名单"
}
],
"next_chapter_must_continue": [
"岑青需要追查缺页",
"陈淑蘅不能立刻说出全部真相"
]
}
```
以后第 50 章、第 100 章需要这个信息时,系统从数据库查这条摘要,不用查完整正文。
---
# 六、上下文传递应该有 4 个等级
## L1:每次必传
```text
小说圣经摘要
文风规则
禁用规则
本章章节卡
```
---
## L2:经常传
```text
最近 3-5 章摘要
当前卷纲
当前主线进度
```
---
## L3:按需传
```text
本章出场人物状态
本章相关伏笔
本章相关场景
本章相关道具
```
---
## L4:特殊情况才传
```text
某一章原文片段
某个角色上次出场完整段落
某个伏笔首次出现原文
某段重要对白
```
只有当模型需要复刻细节时,才传原文片段。
比如本章要回收第 12 章的一句台词,那就检索第 12 章相关原文片段传进去。
---
# 七、成本大概怎么控制?
假设一章 3000 字。
错误做法:
```text
写第100章时传前99章全文
≈ 30万字上下文
```
这非常贵,也不稳定。
正确做法:
```text
固定核心上下文:1500字
最近5章摘要:1500字
人物状态:800字
伏笔:800字
章节卡:800字
风格规则:500字
```
总共大概:
```text
5900字上下文
```
后续写到第 300 章,也还是差不多 5000–8000 字上下文。
成本是可控的。
---
# 八、你要加一个 Context Budget 机制
系统里要给每次调用设置上下文预算。
比如:
```json
{
"max_context_tokens": 12000,
"budget": {
"bible_summary": 2000,
"recent_summaries": 2000,
"character_states": 2000,
"foreshadows": 1500,
"chapter_card": 1500,
"style_rules": 1000,
"retrieved_original_snippets": 2000
}
}
```
如果超过预算,系统自动压缩。
优先级:
```text
本章章节卡 > 人物当前状态 > 最近章节摘要 > 相关伏笔 > 小说圣经摘要 > 原文片段
```
不是所有东西都平等。
---
# 九、你现有系统可以这样落地
你当前项目已经有 `MemoriesModule`,也有小说章节管理、故事圣经、角色、分集、脚本、分镜这些模块。文档里也提到后续需要把小说、故事圣经、角色抽取、分集、脚本、分镜等文本步骤统一成更严格的 schema、重试、验证和 Prompt 版本管理。
所以你现在应该补:
```text
NovelContextBuilderService
NovelMemoryCompressorService
NovelRetrievalService
NovelContextBudgetService
```
职责如下:
```text
NovelMemoryCompressorService
每章写完后,把正文压缩成摘要、人物变化、伏笔变化。
NovelRetrievalService
写新章前,从数据库检索相关人物、伏笔、场景、章节片段。
NovelContextBudgetService
控制本次 API 输入不要超预算。
NovelContextBuilderService
把所有信息拼成最终 Prompt。
```
---
# 十、一个稳定的 Context Builder 流程
```text
准备写第 N 章
读取小说圣经摘要
读取当前卷纲
读取最近 5 章摘要
读取章节卡
根据章节卡识别出场人物
读取这些人物当前状态
根据章节卡识别相关伏笔
读取这些伏笔状态
如有需要,检索原文片段
按 token 预算压缩
拼成最终 API prompt
调用模型写作
```
这样章节再多,也不会爆。
---
# 十一、最重要的数据库设计
你至少需要这几个表:
```text
NovelContextMemory
NovelCharacterState
NovelForeshadow
NovelChapterSummary
NovelAgentRunContext
```
如果你不想多建表,也可以先把它们合并进一个 `NovelContextMemory`,用 `memory_type` 区分。
例如:
```text
memory_type = bible_summary
memory_type = chapter_summary
memory_type = character_state
memory_type = foreshadow
memory_type = style_rule
memory_type = timeline
```
第一版这样就够。
---
# 十二、最终答案
你的担心是对的:
> **如果每次都传全部章节,章节越多,API 参数一定越来越多。**
但专业系统不会这么做。
专业系统是:
```text
全文入库
摘要常用
相关内容检索
上下文预算控制
每章写完更新记忆
每次调用只传必要信息
```
一句话:
> **小说全文存在数据库里,不存在 Prompt 里。
> Prompt 里只放当前模型完成任务必须知道的内容。**
这样写 30 章、300 章、1000 章,API 输入都可以保持稳定。