【Code With SOLO】用 SOLO 从0开发一款 AI 小说写作工作台——用软件工程解决 AI 辅助网文创作的四大顽疾

【Code With SOLO】用 SOLO 从0开发一款 AI 小说写作工作台——用软件工程解决 AI 辅助网文创作的四大顽疾


一、摘要

我是一名产品经理,也是一位网络小说爱好者。在使用各种 AI 写作工具辅助创作时,我发现了一个普遍痛点:AI 能写文字,但无法理解你的整本书。人物会"失忆"、情节会"穿越"、上下文会"断裂"。为了从根本上解决这些问题,我用 TRAE SOLO 从零开发了一款桌面端 AI 小说写作工作台「春水桃花路」,用软件工程的手段——结构化数据管理、记忆检索系统、上下文工程——系统性地解决了 AI 辅助网文创作中的四大顽疾。目前已有可运行的桌面程序。


二、背景

我是谁:产品经理,日常工作中擅长需求分析和系统设计,业余时间是一位狂热的网络小说爱好者,自己也尝试创作过网络小说。

AI 辅助写作的四大顽疾

在用 ChatGPT、DeepSeek 等 AI 工具辅助写小说时,我反复遇到以下问题:

  1. 上下文窗口不够用:一本网文动辄几十万字,AI 的上下文窗口根本塞不下,导致 AI 写到后面就忘了前面发生了什么
  2. 人物设定"崩塌":AI 不记得角色之间的关系变化,明明第10章已经表白了,第30章还在写"暗恋"
  3. 情节前后矛盾:角色已经获得的道具、已经学会的技能,AI 会反复"遗忘",导致逻辑漏洞
  4. 每次都要重复"喂"设定:每次开新对话都要重新粘贴大纲、人物卡、世界观,效率极低

我的思路:这些问题本质上是数据管理问题,不是 AI 模型的问题。如果能用软件工程的方式,把小说的结构化数据(大纲、人物、事件、记忆)管理好,在每次调用 AI 时自动组装精准的上下文,就能从根本上解决这些问题。

目标:开发一款专为网文创作设计的桌面应用,核心不是"让 AI 写小说",而是**“让 AI 理解你的小说”**。


三、实践过程

3.1 技术选型与架构设计

作为产品经理,我擅长做需求拆解和系统设计,但编码能力有限。TRAE SOLO 成了我的"技术合伙人",帮我完成了从架构设计到编码实现的全流程。

技术栈

  • 桌面壳:Electron 41(本地文件系统访问能力)
  • 前端:Vue 3 + TypeScript + Element Plus
  • 编辑器:Tiptap 富文本编辑器
  • 状态管理:Pinia(按功能模块拆分 12 个 Store)
  • AI 引擎:DeepSeek API(SSE 流式输出)
  • 记忆检索:关键词匹配 + BM25 算法 + AI 摘要(三级检索)

核心架构——结构化项目目录

小说项目/
├── 设定/
│   ├── 人物.json        # 角色卡片(姓名/性格/状态/禁止行为)
│   ├── 世界观.md         # 世界观设定
│   ├── 记忆库.md         # AI 记忆(角色状态/关系进展/剧情线索/禁止重复行为)
│   ├── 事件日志.json     # 章节事件记录
│   └── 项目.json         # 结构参数配置
├── 正文/
│   └── 第一卷/
│       └── 第一章/
│           └── 第一节.md  # 每个小节独立文件
├── 大纲.md               # 卷→章→节 树形结构
├── .snapshots/           # 版本快照
└── .agent/
    └── conversations.json # AI 对话持久化

设计理念:每一份数据都以结构化方式存储,AI 调用时可以精准检索和组装,而不是每次都把所有内容塞进上下文。

3.2 用软件工程解决四大顽疾

顽疾一:上下文窗口不够用 → 结构化上下文组装系统

问题本质:AI 的上下文窗口有限(通常 8K-128K token),但一本小说可能有 50 万字。简单粗暴地把前文塞进去,要么塞不下,要么塞进去了但关键信息被淹没在大量无关文本中。

解决方案:不是把"所有前文"给 AI,而是智能组装"当前章节需要的上下文"。

AI 续写时的上下文组装流程:

1. 定位当前章节在大纲树中的位置
2. 提取前3个章节的摘要(不是全文,只是摘要)
3. 提取当前章节的标题、摘要、关键情节点
4. 提取后3个章节的摘要(让 AI 知道故事走向)
5. 提取上一节正文的最后150字(保持文风连贯)
6. 检索记忆库中与当前章节相关的内容
7. 组装成 System Prompt 发送给 AI

核心代码——叶子节点路径计算:

// outline.ts - 智能上下文提取
export function getLeafPath(nodes: ProjectNode[], targetId: string): LeafPathResult {
  // 1. 遍历大纲树,找到所有叶子节点(实际写作单元)
  // 2. 定位当前节点在叶子序列中的位置
  // 3. 取前3个和后3个节点的摘要
  // 4. 加载上一节正文的最后150字(保持文风衔接)
  
  const prevLeaves = leaves.slice(Math.max(0, targetIndex - 3), targetIndex)
  const nextLeaves = leaves.slice(targetIndex + 1, targetIndex + 4)
  
  return { previous, next, prevChapterEnd, isFirst, isLast, leafIndex, totalLeaves }
}

效果:无论小说写多长,AI 每次收到的上下文都控制在合理范围内(约 2000-4000 字),且每一条信息都是与当前章节高度相关的。


顽疾二:人物设定"崩塌" → 事件驱动的记忆系统

问题本质:AI 没有跨章节的"记忆"。第5章角色A和B成了朋友,第15章AI又让他们像陌生人一样对话。这不是 AI 的问题,是没有人帮 AI “记笔记”。

解决方案:设计了一套事件驱动的记忆系统,自动追踪角色状态变化。

核心数据结构

// types/index.ts - 章节事件定义
export interface ChapterEvent {
  id: string
  chapterId: string
  description: string           // 事件描述:"林小夏和苏北辰在天台交换了秘密"
  affectedCharacters: string[]  // 涉及的角色ID
  type: 'relationship' | 'state_change' | 'milestone'  // 事件类型
  autoExtracted: boolean        // 是否由AI自动提取
  confirmed: boolean            // 是否已确认(写入记忆库)
}

// 角色状态追踪
export interface Character {
  id: string
  name: string
  stateEntries: CharacterStateEntry[]  // 角色状态变化记录
  forbiddenActions: string[]           // 禁止重复的行为
}

工作流程

写作完成 → AI 自动提取章节事件 → 用户确认 → 
  ├→ 更新角色状态(stateEntries)
  ├→ 推导禁止行为(forbiddenActions)
  └→ 写入记忆库(记忆库.md)

禁止行为自动推导——这是我认为最有创意的部分:

// character.ts - 根据事件自动推导"禁止重复行为"
function deriveForbiddenActions(event: ChapterEvent): string[] {
  const desc = event.description
  const actions: string[] = []

  if (event.type === 'relationship') {
    if (/介绍|认识|得知|知道.*名字/.test(desc)) {
      actions.push('不要再出现询问对方名字的对话')
    }
    if (/信任|成为.*朋友|结盟/.test(desc)) {
      actions.push('不要再表现出对对方的不信任')
    }
  }

  if (event.type === 'state_change') {
    const woundMatch = desc.match(/包扎|处理|治疗(.{1,6}伤口|.{1,6}伤)/)
    if (woundMatch) {
      actions.push(`不要再出现${woundMatch[0]}的情节(伤口已处理)`)
    }
    const acquireMatch = desc.match(/获得|得到|学会|掌握(.+)/)
    if (acquireMatch) {
      actions.push(`不要再表现为没有${acquireMatch[1]}`)
    }
  }

  return actions
}

举例:当你在第10章写"苏北辰帮林小夏包扎了手上的伤口"并确认事件后,系统会自动推导出禁止行为——“不要再出现包扎手上伤口的情节(伤口已处理)”。之后 AI 续写时,这个禁止行为会被注入到上下文中,从根本上杜绝逻辑矛盾。


顽疾三:情节前后矛盾 → 三级记忆检索引擎

问题本质:记忆库会越来越大,不可能全部塞进 AI 上下文。需要一种方式,在大量记忆中精准找到与当前章节相关的部分。

解决方案:实现了三级递进式记忆检索引擎。

// memorySearch.ts - 三级检索策略
export async function searchMemory(
  memoryMd: string,
  query: string,
  budget: number,
  mode: MemorySearchMode,  // 'keyword' | 'bm25' | 'ai'
  characterNames?: string[],
  sendMessage?: Function
): Promise<string> {
  switch (mode) {
    case 'keyword':  // 第一级:关键词匹配(快速、离线)
      return keywordSearch(memoryMd, query, budget, characterNames)
    case 'bm25':     // 第二级:BM25 相关性排序(更精准)
      return bm25Search(memoryMd, query, budget, characterNames)
    case 'ai':       // 第三级:AI 语义理解(最精准,需要额外API调用)
      return aiSearch(memoryMd, query, budget, sendMessage)
  }
}

三级检索的设计思路

级别 算法 优势 劣势 适用场景
L1 关键词 TF 匹配 速度快,零成本 不理解语义 快速写作时
L2 BM25 BM25 相关性排序 精准度较高,离线 需要分词 日常使用
L3 AI AI 语义提取 最精准,理解上下文 额外 API 调用 关键章节

记忆库结构(Markdown 格式,人类可读可编辑):

# 记忆库

## 角色状态
### 林小夏
- 转学到青云中学(第一章 转学第一天)
- 与苏北辰成为同桌(第二章 意外的同桌)

### 苏北辰
- 在走廊帮林小夏捡起文具(第一章 转学第一天)

## 角色关系进展
- 林小夏、苏北辰:第一章 转学第一天 走廊初次相遇

## 剧情线索
- 图书馆发现夹着旧照片的书(第二章 意外的同桌,涉及林小夏)

## 禁止重复行为
- 不要再出现询问对方名字的对话
- 不要再表现为没有苏北辰的帮助

顽疾四:每次都要重复"喂"设定 → AI 引导式对话系统

问题本质:每次让 AI 生成大纲、创建角色、扩写章节时,都需要精心构造 Prompt,包括题材、目标读者、风格、现有大纲等。这个过程繁琐且容易遗漏。

解决方案:设计了 AI 引导式对话组件(AiGuidedDialog),让 AI 主动引导用户完成创作。

<!-- AiGuidedDialog.vue - AI 引导式对话 -->
<template>
  <el-dialog v-model="visible" :title="title" width="800px">
    <!-- 可编辑的系统提示词 -->
    <el-form-item label="系统提示词(可修改)">
      <el-input v-model="editablePrompt" type="textarea" :rows="4" />
    </el-form-item>
    
    <!-- 上下文信息(自动组装,可勾选) -->
    <el-form-item label="上下文信息">
      <el-checkbox v-for="opt in contextOptions" v-model="opt.enabled">
        {{ opt.label }}
      </el-checkbox>
      <el-input v-model="editableContext" type="textarea" :rows="4" />
      <!-- 上下文字数统计 + AI 压缩按钮 -->
      <span>{{ editableContext.length }} / {{ maxContextLen }}</span>
      <el-button @click="handleCompressContext">AI 压缩上下文</el-button>
    </el-form-item>
    
    <!-- 多轮对话 + 建议选项 -->
    <div class="chat-messages">
      <div v-for="msg in messages" :class="['chat-msg', msg.role]">
        <div class="msg-content" v-html="renderMarkdown(msg.content)" />
        <!-- AI 给出的建议选项,用户一键选择 -->
        <div v-if="msg.suggestions" class="msg-suggestions">
          <el-button v-for="s in msg.suggestions" @click="pickSuggestion(s)">
            {{ s }}
          </el-button>
        </div>
      </div>
    </div>
  </el-dialog>
</template>

这套系统解决的场景

场景 传统方式 引导式对话
生成大纲 手动写 Prompt 描述需求 AI 问你:什么题材?几卷几章?目标读者?
创建角色 手动粘贴大纲让 AI 生成 自动注入大纲上下文,AI 直接生成符合剧情的角色
扩写章节 手动粘贴前文+大纲+人物 自动组装上下文,一键生成
修改设定 重新描述需求 在已有基础上对话式调整

上下文预算控制——防止 Token 浪费:

// projectConfig.ts - 项目级配置
export interface ProjectConfig {
  volumes: number               // 卷数
  chaptersPerVolume: number     // 每卷章数
  sectionsPerChapter: number    // 每章节数
  wordsPerSection: number       // 每节目标字数
  memorySearchMode: MemorySearchMode  // 记忆检索模式
  maxExtraAiCalls: number       // 最大额外AI调用次数
  memoryContextBudget: number   // 记忆上下文预算(字数)
}

3.3 其他核心功能

结构化大纲编辑器

实现了卷→章→节三级树形大纲,每个节点包含标题、摘要、关键情节点、出场人物、续接提示。大纲与正文双向联动:

// 大纲 ↔ Markdown 双向序列化
export function outlineToMarkdown(nodes: ProjectNode[]): string { ... }
export function parseOutlineMarkdown(md: string): ProjectNode[] { ... }

// 大纲节点与正文文件的路径映射
// 正文/第一卷/第一章/陌生的铃声.md
function buildChapterDir(nodes, node): string {
  const volume = findVolumeAncestor(nodes, node)
  const parent = findDirectParent(nodes, node.id)
  return `正文/${volume.title}/${parent.title}`
}

游离章节检测

当大纲节点被删除或重命名后,对应的正文文件会变成"孤儿"。系统会自动检测并提示:

// 检测游离章节(大纲已删但正文还在的文件)
export interface OrphanChapter {
  oldNodeId: string
  title: string
  volumePath: string
  fileName: string
  reason: 'deleted' | 'renamed'  // 大纲已删除 / 标题已修改
}

写作统计与版本快照

  • 写作统计:全书总字数、大纲节点数、角色数、关系数,卷章结构概览
  • 版本快照:手动创建章节快照,随时回溯到历史版本

3.4 开发过程中的 SOLO 协作

作为产品经理,我的编码能力有限,但 SOLO 让我能以"产品设计"的方式驱动开发:

阶段 我做什么 SOLO 做什么
需求分析 描述痛点、定义功能 引导我梳理边界条件、设计数据结构
架构设计 画系统框图、定义模块关系 推荐技术栈、设计项目结构
编码实现 Review 代码、调整交互细节 生成组件代码、状态管理、API 封装
调试优化 描述 Bug 现象 定位根因、提供修复方案
打包发布 测试功能 配置 electron-builder,一键生成 .exe

SOLO 帮我踩过的坑

  • 大纲拖拽排序时状态混乱 → SOLO 建议改用唯一 ID 关联
  • AI 流式输出时内存泄漏 → SOLO 帮我加了 AbortController 中断机制
  • Markdown 序列化时格式丢失 → SOLO 设计了严格的双向转换规则
  • 上下文去重效率低 → SOLO 建议用 BM25 替代简单的关键词匹配

四、成果展示

4.1 应用界面

:house: 首页 - 项目管理

创建和管理多个小说项目,支持古风仙侠、校园言情、无限流等多种题材。


:clipboard: 大纲编辑(AI 辅助生成/展开/修正)

卷→章→节三级树形大纲,支持 AI 一键生成完整大纲结构,每个节点可独立进行 AI 展开和修正。

AI 生成大纲——通过引导式对话,AI 根据题材、目标读者、风格偏好自动生成结构化大纲:


:pencil: 正文写作(左侧大纲 + 右侧编辑器 + 节点详情)

分屏布局:左侧大纲快速导航,右侧富文本编辑器,上方节点详情面板显示摘要、关键情节点、出场人物。底部 AI 工具栏支持一键续写、扩写、润色、灵感、提取事件。

AI 辅助生成——核心亮点:可编辑的系统提示词 + 上下文按需勾选(大纲/人物/世界观/记忆库/前情/后续等)+ Token 预算实时显示 + AI 压缩上下文功能:


:bust_in_silhouette: 人物设定(角色卡片 + 关系图 + 状态追踪 + 禁止行为)

角色按主角/配角/反派/路人分类管理,支持 AI 一键生成符合剧情的角色设定。人物关系表清晰展示角色之间的复杂关系网络。

AI 生成角色——自动注入大纲上下文,生成与剧情高度契合的角色:

角色状态记录——追踪每个角色在各章节中的状态变化:

禁止重复行为——系统根据已确认事件自动推导"AI 不该再做什么",从根源上杜绝逻辑矛盾:

记忆库——结构化 Markdown 格式,记录角色状态、关系进展、剧情线索、禁止重复行为,人类可读可编辑:


:bar_chart: 写作统计

全书总字数、大纲节点数、角色数、关系数一目了然,卷章结构概览清晰展示全书进度。

4.2 核心功能清单

功能模块 核心能力 解决的痛点
多项目管理 创建/切换多个小说项目,独立目录 一台电脑管理多本书
结构化大纲 卷→章→节三级树形,AI 辅助生成/展开/修正 大纲混乱、结构不清
富文本编辑 Tiptap 编辑器,Markdown 双向转换 写作体验流畅
AI 续写 基于智能上下文组装的精准续写 AI “失忆”、文风不统一
AI 灵感 根据大纲和人物生成情节建议 卡文、缺乏创意
AI 润色 选中文本一键润色 文笔不够好
人物记忆系统 事件驱动 + 禁止行为自动推导 人物"崩设"、逻辑矛盾
三级记忆检索 关键词/BM25/AI 三级递进 记忆检索不精准
AI 引导式对话 多轮对话 + 建议选项 + 上下文自动组装 每次手动写 Prompt
上下文工程 预算控制 + AI 压缩 + 可编辑 Prompt Token 浪费、上下文过长
写作统计 总字数/节点数/角色数/结构概览 进度不清晰
版本快照 手动创建/浏览/回溯章节快照 误删内容无法恢复
游离章节检测 自动检测大纲与正文的不一致 文件管理混乱

4.3 可运行程序

  • 便携版春水桃花路-0.1.0-便携版.exe(已编译,可直接运行)
  • 技术栈:Electron 41 + Vue 3 + TypeScript + Element Plus + Tiptap + Pinia + DeepSeek API

五、效果与总结

5.1 这款应用的核心价值

市面上大多数 AI 写作工具的思路是:“给 AI 更大的上下文窗口”

「春水桃花路」的思路是:“用软件工程的方式管理小说数据,让 AI 每次只看到它需要的信息”

这两种思路的区别在于:

维度 塞更多上下文 结构化管理 + 精准检索
可扩展性 受限于上下文窗口 理论上无限(百万字级别)
精准度 信息淹没,信噪比低 每条信息都高度相关
成本 Token 消耗大 按需组装,成本可控
速度 上下文越长,响应越慢 上下文精简,响应快

5.2 SOLO 在我流程中的角色

作为一个产品经理,我能设计系统、定义需求,但如果没有 SOLO,这个项目永远只会停留在"想法"阶段。SOLO 在整个流程中的角色:

  1. 技术架构师:帮我选择合适的技术栈,设计项目结构和数据模型
  2. 主力程序员:生成了 80%+ 的代码,包括 12 个 Pinia Store、10 个 Vue 组件、完整的 IPC 通信层
  3. 算法顾问:帮我实现了 BM25 检索、事件驱动记忆、禁止行为推导等核心算法
  4. 调试专家:帮我定位和修复了数十个 Bug,从状态管理到异步流处理
  5. DevOps 工程师:配置了 electron-builder,一键打包生成 .exe

5.3 可复用的方法

  1. 产品驱动开发:先定义数据结构和交互流程,再让 SOLO 生成代码,效率最高
  2. Plan 驱动迭代:每个功能模块先写 Plan(项目中共产生了 25+ 个 Plan 文件),再按步骤实现
  3. 上下文工程思维:AI 应用的核心竞争力不在模型,在于如何管理和组装上下文
  4. 事件溯源模式:用事件日志驱动状态变更,天然支持审计和回溯

5.4 后续计划

  • EPUB/PDF 电子书导出
  • 写作日历热力图(ECharts)
  • 云端同步备份
  • 更多 AI 模型支持(Qwen\doubao 等)
  • 协作写作功能

六、技术栈

  • Electron 41 - 桌面应用框架(本地文件系统访问)
  • Vue 3 + TypeScript - 前端框架
  • Element Plus - UI 组件库
  • Tiptap - 富文本编辑器
  • Pinia - 状态管理(12 个 Store 按功能模块拆分)
  • ECharts - 数据可视化
  • DeepSeek API - AI 能力(SSE 流式输出)
  • BM25 - 记忆检索算法
  • Markdown-it - Markdown 渲染

感谢 TRAE SOLO,让一个产品经理也能从零做出一款完整的桌面应用!

这个厉害了,能开源么,我想试试软件 :face_with_monocle:

想学习下源码设计