
用大模型写小说前两章往往惊艳第三章开始露馅写到第五章你会怀疑是不是所有角色都被同一个灵魂附体了冷静克制的人设开始讲人生大道理跳脱活泼的人设突然深沉得像哲学家。这几乎是所有尝试用 AI 辅助长篇创作的人都会遇到的瓶颈。真正的问题不是大模型不会写而是长篇创作本身是一个“约束守恒”任务人物设定、故事脉络、语言风格、叙事节奏四类约束要在几万字甚至几十万字里保持稳定。单次 Prompt 记不住这些约束上下文窗口再大也有上限光靠“把上一章复制进去再生成下一章”的粗暴做法早晚会崩。这篇文章不打算争论“AI 能不能写小说”而是把《雾雾恋综》这个双女主恋爱综艺题材小说当成一个技术项目来处理。我会从工程角度拆解一套可落地的 AI 辅助长篇小说创作工作流角色卡怎么设计、章节怎么生成、上下文怎么管理、质量怎么校验、内容安全怎么把关。整个过程包含可复用的 Python 代码和 Prompt 模板你可以直接搬到自己的创作项目里。1. 为什么 AI 写长篇小说总是半路崩掉很多人第一次用 AI 写小说做法都很相似把角色设定和第一章剧情粘贴进去让模型生成第二章生成完之后再把第二章粘贴进去继续生成第三章。前几章效果不错因为模型还能看到原始设定到了第五章、第六章对话历史越来越长模型开始遗忘早期信息人设就慢慢漂移。这个过程的本质问题有三个。第一上下文窗口是有限的。主流大模型的上下文窗口从 4K、8K 到 128K、1M 不等但“窗口大”不等于“都用得上”。当对话里堆满了前几章的正文模型要花大量注意力在无关的日常对话上早期设定早就被挤出了有效范围。第二长文本生成不是一次性任务。写一封邮件、写一段总结是典型的“一次生成”任务模型只需要理解当前输入输出结果即可。长篇小说是“多轮决策”任务每个章节都是在上文约束下做决策任何一次跑偏都会被后续章节放大。创作不是生成而是“带约束的连续生成”。第三缺少质量反馈闭环。很多写作者把生成的文字直接当成成品没有做一致性检查、风格检查和安全过滤。AI 生成的文字表面上语法通顺、逻辑自洽但在长篇语境里错一个细节后面会错一串。所以我的核心判断是AI 写不出长篇不是模型能力问题而是流程问题。我们需要把“让模型写一章”这件事拆成“设定约束 → 分章拆解 → 生成起草 → 校验反馈 → 入库记忆”的闭环。这跟写代码是一个道理——没有自动化测试的代码库会腐化没有质检流程的小说也一样。这篇文章的读者应该是正在尝试用 AI 辅助创作、但苦于角色崩塌和剧情重复的内容创作者以及想了解 LLM 在“多轮生成 知识管理”场景下如何落地的技术开发者。2. 核心概念角色卡、上下文窗口与记忆库动手之前先统一几个术语。这些概念在整个工作流里反复出现理解它们之间的差别后面看代码才不会晕。角色卡Persona Card角色卡是一份结构化的角色设定文件相当于小说角色的“配置文件”。它描述角色的姓名、年龄、职业、性格、语言习惯、关系网络等。在代码工程里角色卡是长期不变的静态信息每次调用模型时都会重新注入。角色卡的关键不是信息多而是信息要能被模型稳定读取和复用。上下文窗口Context Window模型一次能“看到”的 Token 数量。写入 Prompt 的所有内容都会占用上下文窗口。长篇创作里最重要的是管理“什么该写进上下文、什么不该写”。不是信息越多越好而是相关信息越多越好。记忆库Memory Bank把已经生成的章节压缩成结构化摘要或关键事件列表下次生成时只带着摘要去写新章节。记忆库解决的是“信息已经存在但上下文中放不下”的问题。RAGRetrieval-Augmented Generation检索增强生成。简单说就是先从一个外部知识库里检索出与当前章节最相关的设定碎片再把它拼进 Prompt。创作场景里用得不多但如果你的小说有庞大世界观设定RAG 会比“全量摘要”更高效。一致性检查检查生成内容是否和角色卡、前文情节、世界观设定冲突。可以用规则实现比如关键词检测也可以用另一个 LLM 来审核。工程上任何自动化检查都无法完全替代人工审阅它只能帮你快速标记可疑内容。这几个概念的关系可以这样理解角色卡是“宪法”记忆库是“档案”上下文窗口是“办公桌”RAG 是“档案馆管理员”。每次开始写作时办公桌上放的应该是角色卡 本章大纲 前文摘要 必要的世界设定而不是把几十万字的历史统统堆上去。3. 创作架构设计导演-编剧-剪辑三层模型如果你看过剧组的工作方式会发现一个剧组里有完整的决策链导演掌握全局方向编剧负责具体剧本剪辑负责把素材整理成成片。这个分工在 AI 写作里同样适用。我推荐把整个自动创作流程拆成三层。导演层Director负责长期设定。包括项目元信息、角色卡、世界观、分卷大纲。这些内容不参与模型生成的每一轮对话而是作为配置文件存在。导演层的核心产出是“本章大纲”每个章节开始之前先明确这一章的目标、场面、主视角角色和关键事件。编剧层Writer负责具体的章节生成。每一次调用模型接收四类输入角色卡、本章大纲、前文摘要、写作风格规范。编剧层只负责把这一章写完不负责推翻前面设定。它像剧组里的编剧拿到的不是整本小说而是这一集的剧本任务。剪辑层Editor负责生成后的质量校验。检查格式是否合规、角色语言是否人设、剧情是否偏离大纲、是否包含敏感或不合规内容。质检没通过的内容不能进入记忆库也不会被当作成稿。数据流是单向的导演层输出大纲编剧层基于大纲生成章节剪辑层审核章节审核通过后写入记忆库下一次编剧层再从记忆库读取压缩摘要。这个架构最大的好处是每一层都可以独立替换和调试。比如你觉得角色说话太像 AI可以直接改编剧层的 Prompt 模板不需要动整个流程。从工程实现角度看这套架构并不复杂。目录结构建议如下misty_love_project/ ├── config/ │ ├── project.yaml │ ├── characters.json │ ├── outline.json │ └── style_rules.md ├── memory/ │ └── chapter_summaries.json ├── output/ │ └── chapters/ ├── src/ │ ├── director.py │ ├── writer.py │ ├── editor.py │ └── memory.py └── main.pyconfig目录存放所有长期设定memory存放已生成章节摘要output存放正式章节稿src放三个层级的实现代码。这样的目录结构本质上就是一个“面向小说创作的内容管理后台”。4. 环境准备与 LLM 基础调用方式在开始写完整代码之前先准备环境。本文示例使用 Python 3.10 和 OpenAI 兼容接口。目前国内很多大模型服务都提供 OpenAI 兼容的 API 地址具体接入方式略有差异但思路一致。依赖安装pip install openai pyyaml python-dotenv将 API Key 写入项目根目录的.env文件LLM_API_KEYsk-xxxx LLM_BASE_URLhttps://api.deepseek.com/v1 LLM_MODELdeepseek-chat注意.env文件不要提交到 Git 仓库。建议在.gitignore中加入.env。基础调用代码如下这份代码在示例中负责所有模型访问# 文件路径src/llm.py import os from openai import OpenAI from dotenv import load_dotenv load_dotenv() def get_client(): return OpenAI( api_keyos.getenv(LLM_API_KEY), base_urlos.getenv(LLM_BASE_URL), ) def chat( system_prompt: str, user_prompt: str, temperature: float 0.8, max_tokens: int 3000, ) - str: client get_client() response client.chat.completions.create( modelos.getenv(LLM_MODEL, deepseek-chat), messages[ {role: system, content: system_prompt}, {role: user, content: user_prompt}, ], temperaturetemperature, max_tokensmax_tokens, ) return response.choices[0].message.content注意几点temperature控制随机性。草稿阶段可以设 0.8 到 1.0让语言更生动在大纲生成或摘要压缩阶段建议降到 0.3 以下保证信息准确。max_tokens不能设得太小。单章输出通常在 1500 到 3000 字之间中文一个字大概对应 1 到 2 个 Tokenmax_tokens3000是一个比较稳的起点。如果你的服务商不支持base_url参数直接删除那行使用默认 OpenAI 地址即可。如果调用失败第一步要检查的是.env文件名是否正确、环境变量是否加载成功。load_dotenv()默认从当前工作目录读取.env如果你从项目根目录运行脚本一般没有问题如果从其他目录运行需要调整路径。5. 双女主角色卡设计与提示词模板角色卡是整个创作系统的地基。地基层面如果偷懒后面所有章节都会跟着出问题。以《雾雾恋综》为例这个项目是双女主结构两位女主角的性格差异要足够鲜明否则模型很容易把她们的语言混成一锅粥。下面是一份可直接使用的角色卡 JSON{ project: 雾雾恋综, genre: 现代都市 / 恋爱综艺, narrative_mode: 双女主并行视角, characters: [ { id: ji_wu, name: 纪雾, role: 恋爱综艺节目导演, age: 27, personality: 理性克制追求完美习惯掌控场面的节奏, expression: 语速偏慢多用短句很少使用感叹号, speech_pattern: 陈述事实时逻辑清晰情绪波动时会突然停顿, forbidden_behavior: 不会大声喧哗不会使用廉价鸡汤式安慰, backstory: 从纪录片导演出身第一次接手恋爱综艺希望做出真实感 }, { id: su_wu, name: 苏雾, role: 综艺节目新晋嘉宾, age: 26, personality: 热情直率想象力丰富对镜头有天然表达欲, expression: 语速快喜欢用比喻口语感强偶尔用网络热词, speech_pattern: 兴奋时句子会变长容易跑题但总能绕回来, forbidden_behavior: 不会显得心机深沉不会被一次失败打倒而极度消沉, backstory: 自由职业者抱着观察人类样本的心态报名节目 } ], relationship: { type: 从对立到理解, initial_state: 导演对嘉宾的不可控感到头疼嘉宾觉得导演太死板, turning_point: 第三次节目录制中的突发事件让两人第一次真正交流 } }角色卡里的每个字段都要能被模型用到。这里容易被忽略的是forbidden_behavior也就是“角色绝对不会做的事”。模型在开放生成时很容易把角色写得过于“模板化”加入显式的禁忌行为可以很大程度避免角色崩坏。角色卡写好后还需要一套系统提示词模板把所有静态约束组装成一次 Prompt你是小说《雾雾恋综》的合作编剧。你的任务基于以下设定完成指定章节的起草。 ## 全局设定 - 题材现代都市 / 恋爱综艺 - 叙事模式双女主并行视角 - 章节写作要求不要提前揭露未在本章展开的情节不要替读者做总结 ## 角色卡 {characters_json} ## 本章大纲 {chapter_outline} ## 前情摘要 {previous_summary} ## 写作风格规范 1. 语言自然避免“不禁”、“仿佛”、“心底涌起”等套路化表达 2. 对话优先同一场景内至少有 60% 内容使用对话推进 3. 视角明确本章采用 {pov_character_name} 的视角不随意切换到其他角色内心 4. 字数范围{min_words}-{max_words} 字这份模板的关键在于{pov_character_name}是动态传入的。双女主结构里如果这一章写纪雾视角苏雾的内心活动就不该被直接写到如果写苏雾视角纪雾的情绪只能通过外部行为表现。这个视角约束能显著减少“全知全能后遗症”——很多 AI 小说读起来像上帝在讲故事就是因为视角没有限制。具体使用时把角色卡 JSON 转成字符串填入{characters_json}大纲和摘要也按文本填入组装成user_prompt传入chat()函数即可。6. 章节生成与记忆管理完整实现环境、角色卡、提示词模板都有了接下来把完整流程串起来。先实现导演层它负责从分卷大纲中取出当前章节的写作要点# 文件路径src/director.py import json def load_outline(pathconfig/outline.json) - dict: with open(path, r, encodingutf-8) as f: return json.load(f) def get_chapter_outline(outline: dict, chapter_index: int) - dict: 从分卷大纲中提取指定章节的写作要点 for vol in outline[volumes]: for ch in vol[chapters]: if ch[index] chapter_index: return { title: ch[title], goal: ch[goal], scene: ch[scene], key_events: ch[key_events], pov: ch[pov], } raise ValueError(f章节 {chapter_index} 不存在于大纲中)大纲文件config/outline.json可以这样设计{ volumes: [ { volume_title: 第一卷开拍, chapters: [ { index: 1, title: 镜头前的第一面, goal: 纪雾作为导演首次见到苏雾节目录制前的矛盾初现, scene: 演播厅后台, key_events: [纪雾核对流程表, 苏雾迟到, 两人第一次冲突], pov: ji_wu } ] } ] }再实现记忆管理模块。记忆管理的基本思路是不保存正文只保存结构化摘要。每次写完一章就把这一章压缩成 100 到 200 字的摘要并整理出关键事件列表。# 文件路径src/memory.py import json import os from llm import chat MEMORY_PATH memory/chapter_summaries.json SUMMARY_SYSTEM_PROMPT 你是小说章节压缩器只输出结构化摘要不要进行任何文学创作。 def load_memory() - dict: if not os.path.exists(MEMORY_PATH): return {chapters: [], events: []} with open(MEMORY_PATH, r, encodingutf-8) as f: return json.load(f) def save_memory(memory: dict) - None: os.makedirs(os.path.dirname(MEMORY_PATH), exist_okTrue) with open(MEMORY_PATH, w, encodingutf-8) as f: json.dump(memory, f, ensure_asciiFalse, indent2) def compress_chapter(chapter_text: str) - str: prompt ( 提取下面章节的关键信息输出格式\n - 事件转折\n- 角色状态\n- 悬念点\n\n 章节内容\n chapter_text ) return chat(SUMMARY_SYSTEM_PROMPT, prompt, temperature0.2, max_tokens600) def add_chapter_to_memory(chapter_index: int, chapter_text: str) - None: memory load_memory() summary compress_chapter(chapter_text) memory[chapters].append({ index: chapter_index, summary: summary, }) save_memory(memory)最后是编剧层的生成函数。这一步把前面所有模块组装起来# 文件路径src/writer.py import json from llm import chat from memory import load_memory WRITER_SYSTEM_PROMPT 你是小说《雾雾恋综》的合作编剧。你的任务是严格基于角色卡、大纲和前情摘要起草指定章节。 要求 1. 不要新增角色 2. 不要改变已设定的人物关系 3. 不要写出角色卡中 forbidden_behavior 列举的行为 4. 对话要有生活感避免书面腔 5. 本章结尾如果有悬念点要符合大纲设定 def generate_chapter( characters: dict, outline: dict, style_rules: str, ) - str: memory load_memory() previous_summary if memory[chapters]: previous_summary memory[chapters][-1][summary] pov_mapping { ji_wu: 纪雾, su_wu: 苏雾, } pov_name pov_mapping.get(outline[pov], 纪雾) user_prompt f 角色卡 {json.dumps(characters, ensure_asciiFalse, indent2)} 本章大纲 标题{outline[title]} 目标{outline[goal]} 场景{outline[scene]} 关键事件{, .join(outline[key_events])} 本章视角{pov_name} 前情摘要 {previous_summary} 写作风格规范 {style_rules} 请写出本章完整内容。 return chat( WRITER_SYSTEM_PROMPT, user_prompt, temperature0.85, max_tokens3500, )主流程main.py把导演层、编剧层、剪辑层串起来# 文件路径main.py import json from director import get_chapter_outline, load_outline from writer import generate_chapter from memory import add_chapter_to_memory from editor import check_chapter_quality with open(config/characters.json, r, encodingutf-8) as f: characters json.load(f) with open(config/style_rules.md, r, encodingutf-8) as f: style_rules f.read() outline load_outline() chapter_info get_chapter_outline(outline, chapter_index1) chapter_text generate_chapter(characters, chapter_info, style_rules) quality_report check_chapter_quality(chapter_text, characters) if quality_report[passed]: with open(foutput/chapters/chapter_01.md, w, encodingutf-8) as f: f.write(chapter_text) add_chapter_to_memory(1, chapter_text) print(章节生成并入库成功) else: print(质检未通过问题如下) for issue in quality_report[issues]: print(- issue)这里我把editor模块留到了下一节。质量校验是整个流程里最容易被省略、也最不该被省略的环节。7. 质量校验与内容安全审核质检环节从两个层面处理。第一层是硬件规则用代码做确定性检查第二层是模型审核用另一个 LLM 从一致性角度找问题。硬件规则检查包括角色名是否出现在错误场景是否包含禁用词或敏感词是否达到最低字数是否缺少对话内容是否出现 Markdown 乱码或未闭合的符号# 文件路径src/editor.py import re SENSITIVE_WORDS [色情词汇示例, 违法词汇示例, 血腥暴力词汇示例] def check_chapter_quality( text: str, characters: dict, min_words: int 800, ) - dict: issues [] if len(text) min_words: issues.append(f字数不足当前 {len(text)} 字要求至少 {min_words} 字) for word in SENSITIVE_WORDS: if word in text: issues.append(f包含违规词{word}) for char in characters[characters]: name char[name] for forbidden in char.get(forbidden_behavior, []): # 简单近似如果文本中出现明显的越界行为关键词则标记 if forbidden[:4] in text: issues.append(f角色 {name} 出现疑似越界行为{forbidden}) dialog_count len(re.findall(r“|”|「|」, text)) if dialog_count 10: issues.append(对话内容偏少建议增加对话推进剧情) return {passed: len(issues) 0, issues: issues}这里标题中提到的“敏感词”列表我只是示意没有实际列举具体违禁词。真正落地的项目里你应当从平台规则、行业规范出发整理自己的敏感词库并且保持更新。重要的是一个原则任何自动过滤都可能出现误判和漏判LLM 生成的内容在上架前必须经过人工审核。第二层模型审核适合用一次性 Prompt 完成# 文件路径src/editor.py 追加部分 from llm import chat REVIEW_SYSTEM_PROMPT 你是严格的小说编辑只审阅不修改输出 JSON 格式的审阅意见。 def ai_review_chapter(text: str, characters: dict) - dict: user_prompt f 请检查以下章节是否符合要求 1. 纪雾是否保持理性克制的语言风格 2. 苏雾是否保持热情直率的语言风格 3. 是否存在剧情跳跃或逻辑矛盾 4. 是否存在明显 AI 套话如“仿佛内心有什么东西被点燃” 角色设定 {json.dumps(characters, ensure_asciiFalse, indent2)} 章节内容 {text} 输出格式 {{ passed: true/false, issues: [问题1, 问题2] }} result chat(REVIEW_SYSTEM_PROMPT, user_prompt, temperature0.1, max_tokens800) # 实际使用时建议对 result 做 JSON 解析和容错 return result需要特别说明的是模型审核的输出不保证稳定符合 JSON 格式实际工程里建议用正则提取json片段或者增加一次解析失败的重试逻辑。在本文的简化版本里我们保留核心思路不做过度设计。8. 常见问题与排查方法问题现象可能原因排查方式解决方案生成章节中角色语言风格趋同角色卡缺失forbidden_behavior或提示词模板没有注入角色卡检查组装后的完整 Prompt确认角色卡被写入在角色卡中强化语言习惯并在系统提示词中明确视角限制上下文不清剧情接不上前情摘要未写入或记忆文件为空查看memory/chapter_summaries.json是否存在非空记录检查add_chapter_to_memory是否在每章生成成功后调用章节生成速度慢输入 Prompt 太长、输出长度过大检查实际 Token 消耗看看是不是摘要信息太多对记忆库做裁剪只保留最近 3 章摘要 全局关键事件生成内容包含违规词敏感词库不完善运行初筛代码查看issues输出扩充敏感词库并增加人工审核流程API 调用报错返回 401.env文件缺失或 Key 错误检查环境变量是否加载成功打印os.getenv(LLM_API_KEY)前几位重新配置.env确保不提交到 Git同一角色在不同章节目名变化角色卡被修改且没有同步历史章节核对角色的id字段是否稳定使用为角色建立固定 ID任何修改都走配置变更记录这些问题是真实使用中容易遇到的。最关键的是要形成检查习惯生成失败先看输入再看输出最后看记忆库。绝大多数问题都出在Prompt 组装不对或记忆库没写入而不是模型本身。9. 最佳实践与工程化建议如果要在团队或长期项目里维护一套 AI 辅助创作系统下面几条建议值得参考。提示词也要做版本管理。把角色卡、风格规范、大纲都看成代码。任何修改都要走 Git改了什么、为什么改、谁改的都要能追溯。很多创作项目的角色卡会在几百章后大改没有版本管理会导致你完全不知道“人设是什么时候漂移的”。控制上下文成本。记忆摘要不是越长越好。一个章节的摘要建议控制在 200 字以内关键事件列表不超过 5 条。如果小说世界观特别庞大优先考虑引入 RAG 检索而不是把所有设定一次性塞进 Prompt。每次调用模型都是成本能省的地方要省。建立人工审阅流程。自动化质检只能拦截确定的错误无法判断文学质量。AI 生成内容在正式发布前至少要经过一次人工通读。不要抱有“让 AI 自动发布长篇小说”的幻想。从内容安全、版权、平台规则多个角度人工审核都是不能省略的环节。分阶段使用不同参数。草稿生成用高温度让语言更放松大纲拆解和摘要压缩用低温度保证信息准确改写润色阶段可以再提高温度增加表达变化。不要在一条链路上用固定参数打天下。给角色卡留足冗余。角色卡是模型理解角色的最小集合但不要过度极简。至少包含性格关键词、表达方式、禁忌行为、关系状态、背景故事一句话。每个字段都要服务于模型输出避免写一堆模型用不上的理论分析。注意内容来源与版权。如果使用了其他作品的设定、角色名、剧情结构作为参考要注意版权边界。AI 生成内容本身的可版权性在不同地区、不同平台有不同标准务实做法是把 AI 当成协作者而不是完全替代人脑的“自动生成器”。10. 总结从“生成文本”走向“约束工程”回过头看围绕“双女主《雾雾恋综》”这个示例跑通的整套流程本质上不是教模型写小说而是制定一套约束体系角色卡提供角色约束大纲提供剧情约束记忆库提供历史约束质检模块提供质量约束。四层约束一起作用长篇创作才能从“碰运气”变成“可重复、可回滚、可改进的工程流程”。如果你现在正被 AI 写作的角色崩塌问题困扰下一步建议先做两件事第一把你的人物设定改写成包含forbidden_behavior的结构化角色卡第二为你最近写的三章做一个 200 字以内的摘要然后从第四章开始强制带着摘要生成。你会发现光是这两个改动就能把剧情连贯性提升一大截。再往后你可以尝试在记忆库里加入关键事件时间线、人物关系状态机甚至用向量数据库承载世界观检索。到了那个阶段你就不再是“用 AI 写小说”而是在搭建一个属于创作者的智能内容管理引擎。这套思路和你在代码项目里引入 CI/CD、配置中心、灰度发布时做的事情本质上是同一件事。