512 lines
9.4 KiB
Markdown
512 lines
9.4 KiB
Markdown
|
||
如果这样,那章节越多,后续要传递给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
|
||
小说一句话核心
|
||
世界观规则
|
||
主角核心人设
|
||
主要角色不可改动项
|
||
文风规则
|
||
禁用桥段
|
||
短剧改编规则
|
||
```
|
||
|
||
控制在 **1000–2000 字**。
|
||
|
||
这部分相当于小说宪法。
|
||
|
||
---
|
||
|
||
## 第二层:近期记忆
|
||
|
||
每次只传最近 3–5 章摘要。
|
||
|
||
比如写第 80 章,只传:
|
||
|
||
```text
|
||
第75章摘要
|
||
第76章摘要
|
||
第77章摘要
|
||
第78章摘要
|
||
第79章摘要
|
||
```
|
||
|
||
不传全文。
|
||
|
||
每章摘要控制在 150–300 字。
|
||
|
||
总共大概 **1000–1500 字**。
|
||
|
||
---
|
||
|
||
## 第三层:检索记忆
|
||
|
||
这部分不是每次都传全部,而是按本章需要查。
|
||
|
||
比如第 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 章,也可以控制在 **4000–8000 字**以内。
|
||
|
||
---
|
||
|
||
# 四、上下文不是越多越好,而是越准越好
|
||
|
||
很多人误以为:
|
||
|
||
> 传越多,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 输入都可以保持稳定。
|