实战 · 打造会记忆的AI 写作搭档(一):多 Agent 架构进化

写长篇小说时,最痛的不是“写不出来”,而是“写着写着就忘了自己写过什么”:伏笔埋没埋好?角色是不是上一章已经受伤?某个设定到底什么时候定下来的?当篇幅走到几十万字后,这些信息如果只靠人脑和零散笔记维持,很快就会失控。

FantasyNovelAgent 就是从这个需求出发,一点点长出来的:先是一个能跑的 Python 脚本,后来加上动态记忆与自动归档,再到支持多端同步,最后开始迈向前后端分离与云原生存储的雏形。本文复盘这条进化路径,并把关键取舍讲清楚,供同类项目参考。

如果你想先体验一下这个项目,这里有一个在线 Demo:demo online(欢迎试用)。为了避免滥用与泄露成本,Demo 需要你在设置里填写自己的大模型 API Key 后才会真正调用模型能力。

Demo online:模型配置与创作工作台


1. 核心功能:AI 如何像搭档一样写作?

在谈论技术架构之前,先来看看它能做什么。FantasyNovelAgent 并不是一个简单的“续写工具”,它更像是一个由多名专家组成的“写作工作室”。

1.1 灵感推演(Brainstorming)

当你卡文时,点击“自动推演”,系统会基于最近 10 章的剧情走向、未填的坑(未来规划)以及世界观设定,为你提供 3 个截然不同的剧情分支。你可以从中选择一个,或者融合它们的创意。

1.2 沉浸式写作(Writing & Polishing)

  • Muse(缪斯):负责“骨架”。它会根据你选定的大纲,快速生成 2000 字左右的正文初稿,重点在于情节推进和伏笔埋设。
  • Stylist(风格师):负责“皮肉”。它会将初稿进行深度润色,将平淡的“他出了一拳”改写为“拳风呼啸,裹挟着雷霆万钧之势…”,确保文风符合“现代玄幻爽文”的调性。

1.3 动态记忆系统(Active Memory)

这是本项目的杀手锏。你不需要手动维护“角色表”或“物品栏”。

  • Archivist(记录官) 会在后台默默工作。当你写完一章,它会自动分析文本:“主角获得了‘青云剑’”、“‘李四’重伤死亡”。
  • 这些信息会被提取为结构化数据,存入 SQLite 数据库。下一章写作时,AI 不会搞错主角手里拿的是刀还是剑。

记忆库与前情提要:写作时的上下文来源

graph TD
    User[用户输入] --> Router{意图路由}
    Router -->|写作| Muse[Muse 缪斯]
    Router -->|润色| Stylist[Stylist 风格师]
    Router -->|检查| Guard[Guard 守卫]

    Context[(上下文构建)] --> Muse
    Context --> Stylist

    Muse --> Result[生成内容]
    Result --> Archivist[Archivist 记录官]
    Archivist -->|提取更新| Memory[(记忆库/DB)]
    Memory --> Context
graph TD
    User[用户输入] --> Router{意图路由}
    Router -->|写作| Muse[Muse 缪斯]
    Router -->|润色| Stylist[Stylist 风格师]
    Router -->|检查| Guard[Guard 守卫]

    Context[(上下文构建)] --> Muse
    Context --> Stylist

    Muse --> Result[生成内容]
    Result --> Archivist[Archivist 记录官]
    Archivist -->|提取更新| Memory[(记忆库/DB)]
    Memory --> Context
graph TD
    User[用户输入] --> Router{意图路由}
    Router -->|写作| Muse[Muse 缪斯]
    Router -->|润色| Stylist[Stylist 风格师]
    Router -->|检查| Guard[Guard 守卫]

    Context[(上下文构建)] --> Muse
    Context --> Stylist

    Muse --> Result[生成内容]
    Result --> Archivist[Archivist 记录官]
    Archivist -->|提取更新| Memory[(记忆库/DB)]
    Memory --> Context

1.4 逻辑守卫(Logic Guard)

想让主角突然学会敌对门派的禁术?Guard 会立刻跳出来警告你:“检测到设定冲突:该禁术需要‘魔道血脉’,而主角目前是‘纯阳之体’。”

1.5 大模型策略(LLM Strategy)

为了达到最佳效果,我并未绑定单一模型,而是采用了 “各司其职” 的策略:

任务类型推荐模型理由
逻辑检查 / 复杂推演DeepSeek R1 / OpenAI o1这类“推理系”模型在输出前会进行长思维链(CoT)思考,非常适合发现剧情漏洞或设计复杂的智斗环节。
正文撰写 / 润色Claude 3.5 Sonnet / GPT-4o文笔优美,语感自然,尤其擅长环境描写和情感渲染。
记忆提取 / 摘要Gemini Flash / DeepSeek V3速度快、成本低、上下文窗口大,适合处理大量文本的分析任务。

大模型管理:单一模型多种模型切换


2. 架构演进:从文件到数据库

在项目初期,为了快速验证想法,我采用了最简单的 “文件系统存储” 方案。

  • 章节:每一章都是一个 .txt 文件。
  • 记忆:角色卡、世界观、剧情大纲分别存储为 character_db.jsonworld_settings.md 等。
  • 优势:开发极快,Git 版本控制友好,人眼可读。
  • 劣势:随着章节增多(比如写到第 100 章),data/ 目录下会散落成百上千个小文件。文件 I/O 变得频繁,且难以进行复杂的查询(比如“搜索所有提到‘青云剑’的章节”)。

3. 功能完善与自动化

随着核心逻辑跑通,我引入了更多工程化特性:

  • 意图路由(Intent Router):根据用户的自然语言指令(“帮我写个打斗场景” vs “检查一下这章有没有 Bug”),自动调度不同的 Agent。
  • 用量追踪:集成 Token 消耗统计,让创作成本一目了然。
  • 自动化归档:用户点击“保存”的那一刻,系统不仅写入文件,还会触发一连串后台任务——更新摘要链、检查未来规划完成度等。

4. 部署:把 AI 装进树莓派

为了能随时随地写作,我把项目部署到了家里的 树莓派(Raspberry Pi) 上。

  • 内网穿透:利用 Cloudflare Tunnel,无需公网 IP 也能通过自定义域名安全访问。
  • 自动化运维:编写 systemd 服务脚本,实现开机自启和进程守护。
  • 一键部署:开发 deploy.sh 脚本。在 Mac 上写完代码,一条命令即可自动完成 Git 提交、代码同步(Rsync)和远程服务重启。

5. 关键转折:SQLite 架构重构

这是项目近期最大的一次底层改造。

随着“文件即数据库”模式的弊端日益显现,我决定引入 SQLite

5.1 为什么要改?

  1. 数据完整性:文件系统缺乏事务支持,写入中断可能导致 JSON 损坏。
  2. 查询能力:我需要更强大的检索能力来支撑 AI 的“长期记忆”。
  3. 部署复杂度:同步 1000 个小文件远比同步 1 个 .db 文件更容易出错。

5.2 改造方案

我设计了一个 抽象存储层(Storage Layer)

  • 接口化:将 memory_manager.py 中的业务逻辑与底层 I/O 解耦。
  • 数据迁移:编写脚本将旧有的 JSON/TXT 数据无缝导入 novel.db
  • 混合架构
    • 核心数据(章节、记忆、草稿)→ SQLite
    • 配置与日志(API Key、Logs)→ 独立 JSON 文件(便于 Git 忽略与日志轮转)

5.3 双向同步流

为了防止“在树莓派上写了新章节,却被 Mac 上的旧代码覆盖”的惨剧,我在部署脚本中加入了 数据回滚保护

  1. Sync Back:部署前,脚本先从树莓派拉取最新的 novel.db 到本地。
  2. Backup:自动将拉取的数据提交到私有仓库备份。
  3. Push:只有在数据安全的前提下,才推送新代码到树莓派。
sequenceDiagram
    participant Mac as 本地 Mac
    participant GitHub as 备份仓库
    participant Pi as 树莓派

    Note over Mac: 运行 deploy.sh
    Mac->>Pi: 1. 拉取远程数据(Sync Back)
    Pi-->>Mac: 返回最新 novel.db
    Mac->>GitHub: 2. 备份数据
    Mac->>Pi: 3. 推送新代码 & DB(Rsync)
    Mac->>Pi: 4. 重启服务(Systemd)
sequenceDiagram
    participant Mac as 本地 Mac
    participant GitHub as 备份仓库
    participant Pi as 树莓派

    Note over Mac: 运行 deploy.sh
    Mac->>Pi: 1. 拉取远程数据(Sync Back)
    Pi-->>Mac: 返回最新 novel.db
    Mac->>GitHub: 2. 备份数据
    Mac->>Pi: 3. 推送新代码 & DB(Rsync)
    Mac->>Pi: 4. 重启服务(Systemd)
sequenceDiagram
    participant Mac as 本地 Mac
    participant GitHub as 备份仓库
    participant Pi as 树莓派

    Note over Mac: 运行 deploy.sh
    Mac->>Pi: 1. 拉取远程数据(Sync Back)
    Pi-->>Mac: 返回最新 novel.db
    Mac->>GitHub: 2. 备份数据
    Mac->>Pi: 3. 推送新代码 & DB(Rsync)
    Mac->>Pi: 4. 重启服务(Systemd)

6. 过渡阶段:前后端分离(The Great Decoupling)

在迈向更“服务化”的架构之前,我意识到目前的 Streamlit 单体应用(Monolith)已经有些臃肿:UI 渲染、业务逻辑、数据库操作都挤在一个入口里。

为了支持未来可能的移动端 App 或多用户协作,我制定了 前后端分离 计划:

  1. 后端 API 化:引入 FastAPI,将 MuseGuard 等 Agent 的能力封装为标准 REST 接口(如 /api/v1/brainstorm)。
  2. 前端轻量化:Streamlit 退化为纯粹的“前端面板”,只负责展示与发请求;未来也可以替换为 React/Vue。
  3. 独立部署:后端可单独运行在 Docker 容器中,为多个前端提供服务。

这一步虽然不涉及底层存储的变更,却是系统从“脚本”走向“平台”的关键跳板:一旦边界清晰,系统就能更自然地向多用户、权限隔离、灰度发布、异步任务等平台能力扩展。


7. 未来展望:云原生架构(Cloud Native)

阶段二:检索升级(SQLite + 向量检索的双系统)

当篇幅越来越长,单纯“把事实记住”还不够。我需要系统既能守住结构化事实(谁拿着什么、谁受了什么伤、哪些设定已生效),又能在写作时进行模糊召回(类似桥段、氛围语料、伏笔/回忆触发、人物语气一致性)。因此,我把下一阶段的目标定义为 SQLite + 向量检索的双系统

  • SQLite 继续负责“事实与结构化记忆”:角色状态、设定、时间线等可校验、可追溯、可做约束判断的数据。
  • 向量检索负责“模糊召回”:相似片段、相关对话、同类场景的写作参考,以及能激活“伏笔/回忆”的语义关联内容。

对应的交付物会更工程化、更可迭代:

  • 一套可插拔的检索模块:对上层暴露统一接口 retrieve(query) -> passages[],底层可以替换实现(SQLite 内置 / sidecar 索引 / 远程向量库)。
  • 上下文拼装规则:写作/润色/问答时,统一按“结构化事实 + 向量召回片段(TopK)+ 最近章节”的优先级拼装上下文,保证既可靠又有灵感来源。

渐进式实现上,我会优先走一条“本地闭环 → 再替换”的路径:

  • 先本地:在 SQLite 增加 embeddings 表,或使用 sidecar 文件索引,先把“向量召回闭环”跑通,验证 chunk 切分、召回质量与上下文拼装策略是否有效。
  • 再替换:当需要多设备/多用户/更大规模时,再迁移到 pgvector/Milvus/Pinecone 等更适合在线检索与并发的系统。

这里有两个我认为必须守住的设计原则:

  • chunk 切分策略比“选哪家向量库”更重要:按段落、事件、对话来切,往往比单纯按固定字数切,能显著提升召回的可用性(尤其在“人物语气一致性”和“伏笔回收”这类任务上)。
  • 事实优先(Conflict Resolution):当向量召回的片段与 SQLite 的结构化事实冲突时,以 SQLite 为准。向量召回提供灵感与上下文,而不是修改世界观的“事实来源”。

阶段三:云原生雏形(数据库 + 对象存储)

SQLite 只是第一步。随着小说篇幅增长到百万字级别,我仍然会规划 “数据库 + 对象存储” 的形态:

数据类型存储方案理由
元数据/索引Cloudflare D1 / AWS RDS章节列表、角色关系图等需要高频、复杂的结构化查询。
正文/素材Cloudflare R2 / AWS S3小说正文、插图体积大但读写简单,分离存储可显著降低数据库负载。

为了让“多端写作 + 多端同步”真正可靠,下一阶段的核心将不再是“能不能生成”,而是“能不能长期稳定地治理创作资产”:数据一致性、备份与回滚、权限与审计、成本与可观测性,都会逐步成为架构演进的主旋律。

结语

FantasyNovelAgent 的进化史,也是一个开发者从“能用就行”到追求“架构之美”的缩影。每一次重构,都是为了让 AI 助手更稳定、更聪明,从而让我能专注于最重要的事情——讲好一个故事