基于大语言模型与向量数据库的智能写作辅助系统搭建指南
1. 项目概述:当AI成为你的专属写作教练
写长篇小说的过程,就像一场孤独的马拉松。你不仅要构思宏大的世界观和复杂的人物关系,还要确保几十万甚至上百万字的剧情前后连贯,人物性格不“精分”。更头疼的是,当你文思枯竭,对着空白的文档发呆时,那种挫败感足以让任何一个创作者抓狂。传统的写作软件,无论是Word还是Scrivener,本质上都是“记录工具”,它们能帮你整理素材、管理章节,却无法在你卡壳时推你一把,也无法在你写偏时及时提醒。
这正是“自研长篇小说写作Skills”想要解决的问题。它不是一个成品软件,而是一套你可以自己搭建、甚至根据个人写作习惯深度定制的“智能写作辅助系统”。这套系统的核心,是三个相互协作的“超能力”(Skills):参考文风学习、自动续篇启发、剧情连续性检测。简单来说,它能让AI理解你的文风,在你需要时提供符合语境的灵感续写,并像一个尽职的“剧本医生”,时刻帮你盯着剧情逻辑和人物设定是否前后一致。
我花了相当一段时间,将网上零散的工具和思路整合起来,摸索出了一套相对稳定、可实操的搭建方案。整个过程并不需要你成为算法专家,但需要对AI模型(特别是大语言模型)的基本使用、文本处理逻辑有一些了解。最终实现的效果是:你可以导入自己过往的作品或喜欢的作家文风,让AI学习;在写作中随时调用“续写”功能获取灵感火花;并且在完成一个章节后,快速得到一份关于剧情漏洞、人物OOC(脱离角色)风险的“体检报告”。这极大地提升了创作效率和作品质量,尤其适合网络小说作者、独立创作者以及希望进行系统性故事练习的写作爱好者。
2. 核心设计思路:模块化与工作流驱动
在开始动手之前,明确整体设计思路至关重要。我们不能把它做成一个“黑箱”式的庞然大物,而应该采用模块化设计,让每个核心功能(Skill)相对独立,再通过一个清晰的“写作工作流”将它们串联起来。这样不仅易于开发和调试,也方便未来单独升级某个模块。
2.1 三大核心模块解析
整个系统的骨架建立在三个核心模块之上:
文风学习与模仿模块:这是系统的“人格”基础。它的目标不是让AI代替你写作,而是让AI生成的任何文本都尽可能贴近“你的味道”。实现上,它需要一个“训练”阶段。你需要提供一个足够质量的文本库(比如你已完成的20万字小说),通过特定的技术手段(如文本嵌入、风格特征提取或微调小型模型)来构建一个“文风模型”。这个模型的核心产出是一个“风格向量”或一组“风格规则”,用于在后续环节中约束AI的输出。
上下文感知的自动续篇模块:这是系统的“灵感引擎”。它需要在用户给出当前段落(可能是最后几句,甚至是一个开头句子)时,结合已学习的“文风”,生成若干条后续内容的建议。关键在于“上下文感知”。它不能只看最后一句,而应该考虑当前章节的完整内容、甚至前几章的关键情节摘要,以确保续写的建议在剧情逻辑上是合理的。这个模块通常直接调用大型语言模型的API(如GPT-4、Claude 3或国内的大模型),但需要精心设计提示词(Prompt),将“文风”和“上下文”作为强约束条件注入。
剧情与人物连续性检测模块:这是系统的“质量监控官”。它的任务是对比最新写就的文本与已有的“故事知识库”,找出潜在的不一致之处。例如:
- 剧情矛盾:第三章说“主角从未学过武功”,但第五章突然写他“使出一套娴熟的剑法”。
- 人物设定偏移(OOC):一个设定为“沉默寡言、生性多疑”的角色,在新章节里突然变得话痨且轻易相信他人。
- 时间线/地理错误:上午还在京城,下午没有交代任何行程就到了江南。 这个模块的实现相对复杂,需要先从一个“信息抽取”子模块开始,从已有文稿中自动提取并结构化存储关键信息(人物档案、地点、重要事件、物品等),形成知识库。当检测新文本时,同样进行信息抽取,然后与知识库进行比对和逻辑推理。
2.2 工作流设计:如何让模块协同工作
模块是零件,工作流是组装说明书。一个高效的写作辅助工作流应该是非侵入式的,无缝嵌入到你的写作习惯中。我设计的工作流如下:
初始化阶段:导入你的代表作或目标文风文本,运行“文风学习模块”,生成你的专属文风配置文件。同时,如果你有已完成的旧稿,可以运行“连续性检测模块”的信息抽取功能,初始化你的“故事知识库”。
日常写作阶段:
- 写作中:在写作软件(如Obsidian、Typora或甚至VS Code)中,通过快捷键或侧边栏插件,调用“自动续篇模块”。系统会获取当前光标前500-1000字作为上下文,结合你的文风配置,向AI模型请求生成3-5条续写建议。你从中获得灵感,而非直接照抄。
- 章节完成后:将刚写完的章节全文提交给“连续性检测模块”。模块会快速扫描,并与知识库对比,生成一份报告,高亮显示所有潜在的矛盾点、设定偏移和遗漏的伏笔。你根据报告进行修改。
- 更新知识库:修改确认无误后,将该章节内容正式“录入”故事知识库,为后续章节的检测和续写提供更丰富的上下文。
注意:务必牢记,AI是“辅助”而非“主体”。所有模块的输出都应视为“建议”和“预警”。最终的决定权必须牢牢掌握在作者手中。这套系统的价值在于放大作者的创意和减少低级错误,而不是取代创作本身。
3. 技术选型与工具链搭建
明确了设计思路,接下来就要选择趁手的“兵器”。技术选型的原则是:在效果、成本、易用性和隐私性之间取得平衡。以下是我经过多次试验后总结出的推荐方案。
3.1 核心模型与API选择
这是整个系统的大脑,直接决定了续写质量和检测的智能程度。
- 自动续篇模块的首选:OpenAI GPT-4系列或Anthropic Claude 3 Opus。它们的上下文长度长(最高支持128K tokens),对复杂指令的理解能力强,在创造性写作和逻辑推理方面表现最佳。对于成本敏感的场景,可以考虑GPT-3.5-Turbo或Claude 3 Haiku,但在处理长上下文和复杂文风模仿时,效果会有可感知的下降。
- 连续性检测模块的利器:Claude 3 Sonnet或GPT-4。这个任务需要强大的文本理解、信息提取和逻辑推理能力。Claude系列在长文档处理和遵循复杂指令方面口碑很好,非常适合这项任务。
- 文风学习的平民方案:如果不想为API调用频繁付费,可以考虑在本地部署开源模型。Qwen1.5-7B-Chat、Llama 3 8B这类尺寸的模型,在消费级显卡(如RTX 4070)上可以流畅运行。通过对你的文本进行LoRA微调,可以在较小成本下获得不错的文风模仿能力。虽然生成内容的创造性和流畅度可能不及顶级商用API,但作为文风约束器来用,已经足够。
成本考量:纯使用GPT-4等顶级API,长期创作的成本不低。一个折中的架构是:文风学习用本地微调的小模型,续篇和检测用API。这样大部分时间消耗的是本地算力,只有在你主动寻求灵感和进行质检时才调用API,成本可控。
3.2 开发环境与框架
对于个人开发者或有一定技术背景的作者,我推荐以下轻量级技术栈:
- 编程语言:Python是不二之选。其丰富的AI库(如OpenAI, Anthropic, LangChain)和文本处理库(NLTK, spaCy)生态无人能及。
- 应用框架:Gradio或Streamlit。这两个库可以让你用极少的代码快速构建出美观的Web界面。你可以在浏览器里拥有一个专属的写作面板,集成续写按钮、文档上传和检测报告展示,体验远胜于命令行。
- 本地知识库与向量检索:为了实现连续性检测,我们需要存储和快速检索故事要素。ChromaDB或FAISS这类轻量级向量数据库是理想选择。我们可以将抽取出的“事件-人物-地点”三元组或段落摘要转换成向量存入,检测时进行相似性搜索和比对。
- 项目结构与版本控制:使用Git进行代码管理,项目结构清晰划分模块,例如:
novel_assistant/ ├── core/ │ ├── style_learner.py # 文风学习模块 │ ├── continuator.py # 自动续篇模块 │ └── continuity_checker.py # 连续性检测模块 ├── knowledge_base/ # 存放向量数据库文件 ├── configs/ # 配置文件(API密钥、模型路径) ├── app.py # Gradio/Streamlit主应用 └── requirements.txt # 项目依赖
3.3 关键依赖库清单
创建一个requirements.txt文件,核心依赖如下:
openai>=1.0.0 anthropic>=0.25.0 langchain>=0.1.0 langchain-openai langchain-anthropic chromadb>=0.4.0 sentence-transformers>=2.2.0 gradio>=4.0.0 # 如果使用本地模型 torch transformers accelerate peft # 用于LoRA微调安装只需一行命令:pip install -r requirements.txt。这个环境搭建起来后,就具备了连接各大模型、处理文本和构建界面的所有基础能力。
4. 核心模块实现细节与代码剖析
理论说得再多,不如一行代码。这一部分,我将深入每个模块,分享具体的实现思路、代码片段以及那些容易踩坑的细节。
4.1 文风学习模块:不只是词频统计
简单的词频和句式统计无法捕捉文风的精髓。文风包括用词偏好、句式长短、修辞手法、段落节奏乃至情感基调。我的实现方案分为两步:
第一步:风格特征提取使用sentence-transformers库中的预训练模型(如all-MiniLM-L6-v2),将你的文本分割成句子或段落,转化为高维向量。这些向量编码了语义和风格信息。计算所有这些向量的“平均向量”或“中心向量”,可以作为一个粗略的“整体风格向量”。
from sentence_transformers import SentenceTransformer import numpy as np model = SentenceTransformer('all-MiniLM-L6-v2') # 假设`style_texts`是你的文风文本列表 style_embeddings = model.encode(style_texts, convert_to_tensor=True) # 计算平均风格向量 avg_style_vector = np.mean(style_embeddings.cpu().numpy(), axis=0) # 保存这个向量 np.save('configs/my_style_vector.npy', avg_style_vector)第二步:构建风格化提示词模板将风格向量直接用于模型很难。更有效的方法是,通过分析文本,总结出可描述的“风格规则”,注入到后续所有调用模型的提示词中。我们可以让AI自己总结。
from openai import OpenAI client = OpenAI(api_key="your_key") def analyze_style(text_sample): prompt = f""" 你是一位资深的文学编辑。请分析以下文本的写作风格,并用一个“风格描述”总结出来。 风格描述应包括:语言基调(如:冷峻、诙谐、华丽、朴实)、常用句式特点(如:多短句、善用长复合句)、修辞偏好(如:比喻、排比)、视角特点等。 文本样本: {text_sample[:2000]} # 截取部分进行分析 请直接给出风格描述,不要有其他内容。 """ response = client.chat.completions.create( model="gpt-3.5-turbo", messages=[{"role": "user", "content": prompt}] ) return response.choices[0].message.content style_description = analyze_style(your_novel_text) # 将style_description保存到配置文件这样,我们就得到了一个文本化的风格描述,如:“语言冷峻犀利,多用短句和断行营造紧张感,擅长使用具象的比喻,视角以主角内心活动为主,夹杂锐利的第三方评论。” 这个描述比向量更直观,也更容易被大模型理解。
实操心得:文风学习样本的质量和数量至关重要。建议使用你已完成的最能代表你风格的3-5万字内容。样本太少缺乏统计意义,样本太多且风格不一反而会干扰模型。确保样本是纯净的正文,去掉章节标题、作者说等无关内容。
4.2 自动续篇模块:提示词工程的艺术
这是与AI交互最直接的部分,提示词的设计决定了续写建议的可用性。一个强大的提示词需要整合上下文、文风、写作指令和输出格式。
def generate_continuation(context, style_desc, character="主角名", genre="玄幻"): client = OpenAI(api_key="your_key") prompt = f""" 你是一位擅长创作{genre}小说的资深作家。请根据以下给定的“上下文”、“写作风格要求”和“故事背景”,为故事生成3条可能的后续发展建议。 # 上下文(最近500字): {context} # 写作风格要求: {style_desc} # 故事背景与人物备忘: - 主角:{character},性格坚毅,目前正在... - 当前章节核心矛盾:... # 你的任务: 1. 严格遵循上述写作风格进行创作。 2. 生成3条截然不同的后续情节走向建议。 3. 每条建议请以“【建议X】”开头,后跟一段50-100字的具体描写片段,让这个情节“活”起来。 4. 最后,用一句话总结每条建议的核心冲突或转折点。 请开始生成: """ response = client.chat.completions.create( model="gpt-4-turbo-preview", messages=[{"role": "user", "content": prompt}], temperature=0.8, # 温度稍高,鼓励创造性 max_tokens=800 ) return response.choices[0].message.content关键参数解析:
temperature(温度):控制随机性。0.0最确定、保守,可能重复;1.0更随机、有创意。续写建议通常设在0.7-0.9之间,以获取多样性。max_tokens:限制生成长度。根据你需要建议的详细程度来定,200-500通常足够。- 上下文截取:不要无脑传入全部前文。模型有token限制(如128K),且无关的远古信息会干扰判断。通常截取当前章节的末尾部分(500-1000字)加上前一章的摘要,效果最好。
4.3 连续性检测模块:从规则到智能体
这是技术实现最复杂的一环。一个简单的实现是规则匹配(如关键词扫描),但太死板。我采用“AI智能体”的思路,分两步走:
第一步:构建并维护故事知识库每当完成一个章节,就运行一次信息抽取,将结构化信息存入向量数据库。
import chromadb from chromadb.utils import embedding_functions def extract_and_store_knowledge(chapter_text, chapter_id): # 使用LLM抽取结构化信息 extraction_prompt = f""" 从以下小说章节中,提取所有关键信息,并以JSON格式返回。 需要提取的信息包括: 1. 出现的人物及其在本章中的行为、对话、情绪状态、外貌变化。 2. 发生的新事件(时间、地点、涉及人物、结果)。 3. 新出现或发生变化的物品、地点。 4. 设定的补充或变更(如功法升级、新规则揭示)。 5. 埋下的伏笔或悬念。 章节内容: {chapter_text[:10000]} JSON格式示例: {{ "characters": [{{"name": "张三", "action": "击败了李四", "emotion": "愤怒", "trait_change": "左臂受伤"}}], "events": [{{"description": "宗门大比决赛", "location": "演武场", "outcome": "张三获胜"}}], "items": [{{"name": "青云剑", "status": "出现裂痕"}}], "setting_changes": ["修真界灵气开始复苏"], "foreshadowing": ["李四落败时眼神充满不甘,似乎另有隐情"] }} """ # 调用LLM获取extraction_result (JSON字符串) # ... # 解析JSON,并存储到ChromaDB chroma_client = chromadb.PersistentClient(path="./knowledge_base") embedding_func = embedding_functions.SentenceTransformerEmbeddingFunction(model_name="all-MiniLM-L6-v2") collection = chroma_client.get_or_create_collection(name="novel_knowledge", embedding_function=embedding_func) # 将每条信息(如一个事件描述)单独作为一个文档存入,并附带元数据(章节ID、类型) for event in extraction_result['events']: collection.add( documents=[event['description']], metadatas=[{"type": "event", "chapter": chapter_id}], ids=[f"event_{chapter_id}_{i}"] ) # 对characters, items等做类似处理...第二步:检测新章节的连续性当新章节写完后,同样进行信息抽取,然后将每条新信息与知识库中的历史信息进行“比对询问”。
def check_continuity(new_chapter_text, previous_chapter_id): # 1. 抽取新章节信息,得到new_knowledge # 2. 从知识库中查询相关历史信息 collection = chroma_client.get_collection("novel_knowledge") # 例如,检查新出现的“张三精通剑法”是否矛盾 query_results = collection.query( query_texts=["张三 不会 武功 张三 不懂 剑法"], # 构造查询,查找历史中关于张三能力的负面描述 n_results=3 ) # 3. 将新信息与查询到的历史信息一起,提交给LLM进行逻辑矛盾分析 analysis_prompt = f""" 你是一个严格的剧本医生。请判断以下“新情节”是否与“已知故事事实”存在逻辑矛盾。 已知故事事实: {query_results['documents']} 新情节描述: “张三在危机时刻,使出了一套精妙的‘流云剑法’,击退了敌人。” 请只回答是否存在矛盾。如果存在,请明确指出矛盾点。 """ # 调用LLM进行分析 # 4. 汇总所有检测到的矛盾点,生成报告这种方法结合了向量检索的效率和LLM的理解能力,比纯规则检测更智能,能发现“张三之前说自己讨厌吃鱼,现在却津津有味地吃鱼”这类隐含矛盾。
5. 集成应用与界面构建
模块完成后,我们需要一个统一的界面来使用它们。使用Gradio可以快速搭建一个本地Web应用。
import gradio as gr from core.continuator import generate_continuation from core.continuity_checker import check_continuity # 加载你的文风配置 with open('configs/style_description.txt', 'r') as f: MY_STYLE = f.read() def ui_continue_writing(context, genre): if not context.strip(): return "请先输入一些上下文内容。" suggestions = generate_continuation(context, MY_STYLE, genre=genre) return suggestions def ui_check_continuity(full_chapter): if not full_chapter.strip(): return "请粘贴需要检测的完整章节内容。" report = check_continuity(full_chapter, "latest_chapter") return report with gr.Blocks(title="长篇小说写作助手") as demo: gr.Markdown("# 📖 我的智能写作助手") with gr.Tab("灵感续写"): with gr.Row(): with gr.Column(scale=2): context_input = gr.Textbox(label="当前上下文(建议粘贴最后300-500字)", lines=10, placeholder="在这里粘贴你刚写的内容...") genre_dropdown = gr.Dropdown(["玄幻", "都市", "科幻", "历史", "言情"], label="作品类型", value="玄幻") generate_btn = gr.Button("生成续写建议", variant="primary") with gr.Column(scale=3): output_suggestions = gr.Markdown(label="生成的续写建议") generate_btn.click(fn=ui_continue_writing, inputs=[context_input, genre_dropdown], outputs=output_suggestions) with gr.Tab("连续性检测"): chapter_input = gr.Textbox(label="完整章节内容", lines=20, placeholder="粘贴整个章节的文本...") check_btn = gr.Button("开始检测", variant="primary") report_output = gr.Markdown(label="检测报告") check_btn.click(fn=ui_check_continuity, inputs=chapter_input, outputs=report_output) gr.Markdown("---\n**使用提示**:续写建议仅供参考,请以你的创意为主。检测报告标出的问题请仔细斟酌。") if __name__ == "__main__": demo.launch(server_name="0.0.0.0", server_port=7860, share=False) # 本地运行运行python app.py,在浏览器打开http://localhost:7860,你就拥有了一个专属的写作辅助面板。左边写作,右边随时点一下获取灵感,写完一章再丢进去做个体检,整个流程非常顺畅。
6. 避坑指南与效能优化
在实际搭建和使用过程中,我踩过不少坑,也总结出一些提升体验和效果的技巧。
6.1 成本与效能的平衡术
- API调用优化:续写和检测是成本大头。对于续写,可以设置一个“灵感阈值”,比如当用户连续写作超过2分钟无输入,或主动点击按钮时才调用,避免无意义的频繁调用。对于检测,可以设置为每写完一个章节(而非一段)才触发一次全面检测。
- 上下文精炼:传给API的上下文不是越长越好。在调用续写前,可以用一个小模型(或简单的文本摘要方法)对前文进行摘要提取,只保留最相关的人物状态、当前场景和立即冲突,这能显著减少token消耗并提升续写相关性。
- 本地缓存:对于文风向量、角色档案等不常变化的数据,一定要本地缓存,不要每次请求都重新计算。
6.2 提升续写质量的技巧
- 提供“种子词”:在提示词中,除了上下文和风格,可以额外提供你希望接下来出现的1-3个“种子词”或“情绪关键词”,如“背叛、雨夜、决裂”。这能给AI更明确的导向。
- 多轮迭代:不要指望一次生成就得到完美建议。可以设计一个简单交互:AI生成3个建议 -> 你选择最感兴趣的一个 -> AI基于这个建议再展开生成更详细的片段。这种“对话式”续写往往能碰撞出更好的火花。
- 风格“过拟合”的防止:如果发现AI续写完全照搬你旧文的套路,缺乏新意,可以在提示词中加入“在保持上述风格基调的前提下,请尝试引入一些新的情节元素或表达方式,避免重复”。
6.3 确保检测准确性的要点
- 知识库的“纠错”机制:检测系统可能会误报。必须有一个界面,允许作者标记某条“矛盾”报告为“误报”,并选择“以此为准更新知识库”。这样系统就能自我修正,越来越懂你的故事。
- 关注核心设定:初期,不要让系统检测所有细节,否则报告会充斥大量无关紧要的“噪音”(如“角色上次喝了红茶,这次喝了绿茶”)。应优先关注核心设定:人物核心能力、性格、关键关系、世界观基本法则、主线关键事件。
- 人工复核必不可少:无论检测系统多智能,它都只是一个辅助工具。对于它提出的每一个矛盾点,作者都必须结合创作意图进行最终判断。有时,“矛盾”恰恰是伏笔或人物成长的表现。
6.4 常见问题与排查
- 续写内容完全偏离风格或剧情:
- 检查:提示词中的风格描述是否准确、上下文是否过短或包含无关信息。
- 解决:强化提示词中的约束,例如:“必须严格以上下文最后一句作为续写的唯一开头。” 增加上下文长度至500-800字。
- 连续性检测漏报严重:
- 检查:信息抽取的提示词是否设计得当?知识库的向量检索相似度阈值是否太高?
- 解决:优化抽取提示词,要求提取更细粒度的信息。调低检索相似度阈值,召回更多相关历史信息进行比对。
- 系统响应速度慢:
- 检查:是否在循环中频繁调用大模型API?本地模型加载是否耗时?
- 解决:对API调用进行异步处理或队列管理。对于本地模型,考虑使用
text-generation-inference(TGI)这类高性能推理服务器常驻内存。
搭建这样一套系统,更像是在培育一个专属的“写作伙伴”。它不会取代你的创意核心,但能替你扛下那些繁琐的、消耗心力的重复性劳动和基础质检工作,让你能更专注地投入在故事的灵魂——情感、人物和思想的表达上。从一行代码开始,逐步让它理解你的世界,这个过程本身,就充满了创造的乐趣。