一个本地优先的 AI 小说辅助创作的跨端桌面应用,把「写一本书」拆成了一条可执行、可观测、可修订、可回滚、自动审定稿的自动化管线。
一、从聊天框到流水线
用过 ChatGPT 写小说的人大概都经历过这样的循环:复制角色设定 → 粘进对话框 → 生成一章 → 发现人物性格漂移 → 再补充设定 → 重新生成……
问题不在于模型不够聪明,而在于上下文是临时的。角色的性格、世界的规则、埋下的伏笔、章节的时间线,全都活在你的剪贴板和记忆里。
Mythpen 的出发点很简单:把这些东西变成结构化的项目数据,让 AI 在写作时通过工具主动读写,而不是靠你在 prompt 里反复复述。
于是「让 AI 写小说」这件事,被拆成了一条流水线:
了解项目 → 读大纲 → 创作 → 润色 → 审稿 → 定稿
每一步都有明确的输入、输出和完成条件,章节在 pending → writing → review → accepted 状态机中流转。AI 不再是「一段一段地生成文本」,而是在推进一个项目。
二、整体架构
Mythpen 是一个 Tauri v2 桌面应用,采用「前端 + 本地 sidecar」的三层结构:
┌─────────────────────────────────────────┐
│ Tauri v2 Shell (Rust) │
│ ┌───────────────────────────────────┐ │
│ │ React 19 + TypeScript + Zustand │ │
│ │ Vite + Tailwind CSS v4 │ │
│ └──────────────┬────────────────────┘ │
│ │ HTTP / SSE │
│ ┌──────────────▼────────────────────┐ │
│ │ Express 5 Sidecar :3001 │ │
│ │ AI Adapter / Tools / Routes │ │
│ └──────────────┬────────────────────┘ │
│ │ │
│ ┌──────────────▼────────────────────┐ │
│ │ sql.js (SQLite WASM) │ │
│ │ ~/.mythpen/ │ │
│ └───────────────────────────────────┘ │
└─────────────────────────────────────────┘
几个关键选择:
- Sidecar 而不是纯 Tauri IPC:AI 调用、工具循环、SSE 流式输出放在 Node/Express 里,比在 Rust 里重写一遍生态成熟得多;前端只消费 REST + SSE。
- sql.js 而不是原生 SQLite:整个后端可以打包成单个可执行文件,不需要用户机器上编译 native addon。
- 本地优先:数据库放在
~/.mythpen/,全局配置一个库,每个小说项目一个独立的.mythpen.db。没有云端,没有账号,数据始终在本地。
桌面端启动时,Rust 侧 spawn sidecar 并轮询端口就绪;退出时先请求 /api/shutdown 优雅关闭,等待 2 秒后再强制结束进程。
三、AI 引擎:双 Provider + 工具循环
双 Provider 自动适配
Mythpen 同时支持 OpenAI-compatible 与 Claude 两类接口。适配层会优先看配置里的 apiType,否则根据模型名前缀(claude / anthropic/)自动判定:
// server/ai-adapter.js(示意)
const isClaude = apiType === "claude" || /^claude|^anthropic\//.test(model);
两种协议的工具调用格式并不一样:OpenAI 是 tool_calls + role: "tool",Claude 是 tool_use / tool_result 内容块。适配层负责双向转换,上层的工作流代码完全无感知。
工具循环
AI 不是一个只会吐字的模型,它手里有 47 个工具:查询角色、更新章节状态、写大纲、管理伏笔、检索记忆、操作时间线……每轮请求返回 tool_calls 后,后端执行工具、把结果喂回模型,直到模型给出最终回答。
流式接口用 SSE 推送四类事件:
content_chunk → 文本增量
tool_call → 正在调用什么工具、参数是什么
tool_result → 工具执行结果
task_end → 本轮任务结束
前端 AI 侧栏因此能画出完整的「工具调用时间线」——用户看得见 AI 在查哪个人物、改了哪一章,而不是对着一个转圈圈的加载动画猜。
上下文注入
每次对话前,后端会从项目库里组装上下文:项目题材与篇幅、角色列表、章节概览、仍然活跃的伏笔。这意味着模型不需要在 prompt 里被重复投喂设定,它拿到的是一份实时的项目快照。
四、两套工作流
写作模式(writing)
适合已经有设定和大纲、要逐章推进的项目。系统提示词里定义了一条强约束的流水线:
- 判断当前待写章节(
pending) - 了解项目与已有内容
- 写大纲,并填写五个叙事维度
- 写正文,章节状态置为
writing - 润色
- 审稿
- 定稿,状态置为
accepted,继续下一章直到没有pending
提示词里明确写了「不得只写大纲」「必须逐章循环」「写完必须总结」这类约束——因为 LLM 非常擅长在第一步就宣布「大功告成」。
共创模式(collab)
适合从零开始的项目,AI 扮演的是「合著者」:
设定共创 → 分卷规划 → 前三章快速交付 → 交接写作模式
每个阶段都有明确的完成条件,并通过 update_project_phase 工具推进项目阶段。作者回复「ok」或「继续」即视为确认,避免 AI 反复确认、原地打转。
续写
编辑器里的「续写」走一个独立接口:取章节最后 1500 个字符作为上下文,以较高的 temperature(0.85)流式生成,生成完自动追加到正文并更新字数。它解决的是「坐在编辑器里,光标停在句号后面,不知道下一句写什么」的场景。
五、数据模型:让故事可计算
每个项目库有 15 张表,覆盖一本书的完整生命周期:
| 领域 | 表 |
|---|---|
| 结构 | project_meta / volumes / chapters |
| 人物 | characters / character_relations / chapter_characters |
| 世界 | world_entries / science_entries |
| 叙事 | foreshadows / timeline_events / clue_board / memories |
| 会话 | chat_sessions / chat_messages / token_usage |
我特别喜欢的一个设计是五维叙事字段。每一章除了正文,还要回答五个问题:
| 字段 | 问题 |
|---|---|
cognitive_frame | 这一章给读者换上了什么认知框架? |
emotional_anchor | 情绪落点在哪个人/物上? |
world_texture | 世界质感通过什么细节呈现? |
concrete_mystery | 留下了一个什么具体的谜? |
interpersonal_tension | 人与人之间的张力在哪里? |
它们不是给读者看的,而是给 AI(和作者)看的检查清单。当模型被要求显式回答这五个问题,生成的章节会更「有东西」,而不是流水账。
六、导出与本地化
写完的书可以导出为 EPUB(按卷分组、带封面)、HTML(封面 + 目录 + 打印样式,可直接存 PDF)、Markdown 和 TXT。
界面支持中英文双语,且「界面语言」与「写作语言」是两个独立维度——你可以用中文界面写英文小说。
七、写在最后
Mythpen 并不试图「一键生成一本小说」。它做的是另一件事:把长篇小说创作中那些容易丢失的东西——设定、伏笔、爽点、状态、关系、上下文——变成可持久化、可查询、可被 AI 操作的数据。
当写作从「对话」变成「流水线」,AI 才真正成为一个能陪你写完几十万字的合作者,而不是一个健忘的枪手。
技术栈:React 19 · TypeScript · Tailwind CSS v4 · Zustand · Express 5 · sql.js · Tauri v2