☰
用Gemini大模型构建百万字小说生成器:工程化分层生成实战
2026/10/10 4:33:43 网站建设 项目流程

简介:这是一款基于Gemini大模型打造的多功能小说生成器,主要面向网络小说创作者、AI写作爱好者及大模型应用开发者,用于解决长篇故事创作中剧情连贯性弱、设定易前后矛盾等痛点。工具内置小说设定工坊,可完成世界观架构、角色设定与剧情蓝图设计;智能章节生成配合状态追踪系统,能持续维护角色发展轨迹与伏笔信息;语义检索引擎依托向量化检索保障长程上下文一致,同时支持本地知识库引用,并通过自动审校机制检测逻辑冲突,全程借助可视化工作台完成配置、生成与审校一体化操作。压缩包共30个文件,以20个Python脚本为核心,覆盖模型调用、章节生成、检索与审校等关键环节,另有txt配置、example示例及md说明文档辅助上手与二次开发,包体仅106KB,目录按src、models、generators、tools等模块化组织,结构清晰。目前已有139人学习下载,适合希望基于Gemini构建完整写作管线、研究长文本生成架构或快速搭建专属AI创作工具的开发者参考。

1. 用Gemini大模型做百万字小说,为什么注定不是“一次点击”的事

即使Gemini大模型的上下文窗口已经很宽,也改变不了一个基本事实:生成器是“生产内容的程序”,单次请求的输出token一定是有上限的。一百万字的网络小说,放在一次请求里既塞不下、也写不出,只能在程序层拆成几十上百次任务去接力完成。很多人下载这类标题里的zip包,打开后发现只有一个对话脚本和几个提示词模板,跑出来的东西前几千字还有模有样,到第三章就开始忘掉设定、人物对白千篇一律——这就是把“大模型能力”错当成了“工程能力”。

这套方案真正值钱的地方,是把Gemini大模型接入一个可管理的小说生成器:先出总纲、再分卷、再拆章,每一章带着前情摘要去续写,最后落盘成干净文本。对想批量产网文、做AI辅助写作工具或验证长文本可控生成的人来说,这才是能照着复现的路。往下我会用一套最小可运行的Python结构,把它一层层拆开。

2. “百万字”是工程问题不是模型问题:先算清token预算和分层生成

2.1 一段中文大概吃掉多少token,Gemini单次又能吐多少

中文在多数主流大模型的分词器里,一个汉字大约对应1到2个token,这是做长篇小说生成之前必须接受的换算关系。按保守估计,一万字的中文内容约等于1.5万到2万token。如果目标是两百万字的完本小说,那要处理的token总量就在三百万到四百万这个量级,远不是一次对话能覆盖的。Gemini这类大模型的长上下文确实能接收很长的输入,但接收长度和输出长度是两回事,不能把“能读一百万token”理解成“能写一百万字”。

单次输出的上限在不同模型版本、不同调用方式下差异很大,可能只有几千token,也可能到数万token。换算成中文,几千token就是几千字,这恰好是网文一章的体量。所以正确的做法不是去挑战单次输出上限,而是把一百万字的正文拆成“几百次章节生成任务”,每一次都当作独立请求来处理,再把上下文通过摘要、大纲和人物卡传递下去。只要请求之间的状态管理得当,最终拼起来的效果会比硬挤一次生成更稳定。

2.2 四层粒度:总纲、卷、章、段落各自承担什么

常见的做法是建立一条生成管线,从上到下分四层。最顶层叫总纲,只要几百字,说清楚世界观、主线冲突、结局落点;第二层是卷,网文里通常几万字一卷,每卷需要独立的阶段性目标;第三层是章,每章几千字,是真正调用Gemini大模型生成的单位;第四层是段落,一般不会单独去请求,而是在章节内通过多次续写完成。

如果跳过分卷,直接让模型从第1章一路写到第50章,模型会在几十章之后就忘记前面埋下的伏笔。因为把全部历史塞进提示词既不经济、也不现实,提示词越长,单次可用的输出窗口越小。所以每一层之间只保留“契约信息”:总纲给卷,卷给章,章与章之间靠章节摘要衔接。这套设计本质上是把大模型的注意力预算花在最该花的地方,而不是让它去重读几十万字来找设定。

2.3 为什么选Gemini而不是自己拼多模型协作

超长篇小说生成有很多技术路线可选。有人用多个小模型分工,角色对话用一个模型,场景描写用另一个模型,这种多AI协作方案很灵活,但工程复杂度和出错概率都会明显上升。一个模型输出格式不稳定,就可能让整条管线断裂。选Gemini大模型作为核心,最直接的原因是它的长上下文和结构化输出能力相对成熟,一个模型既能理解整体框架、又能生成细枝末节,省掉很多编排工作。

这条路线对个人开发者和中小团队尤其友好。不需要自己部署模型,也不用为角色调度写太多胶水代码,只要把提示词和状态管理做好,就能得到一个能持续产出的生成器。至于“免费大模型API”这类零成本路线,我一般不建议在生产型生成器里作为主力依赖,免费接口的限流和稳定性撑不住批量章节的连续调用,容易在半夜批量跑稿时突然断掉。Gemini这类商用API虽然要花钱,但算下来每章成本很可控,适合作为主力通道。

3. 跑通一个能写小说骨架的最小脚本:从SDK安装到逐章落盘

3.1 项目结构和环境变量,把底子一次配好

解压一个zip工程包之后,先别急着跑主脚本,先确认三件事:Python版本、Gemini SDK装上了没有、API密钥有没有通过环境变量注入。常见结构是根目录下放一个novel_gen目录,里面按职责拆成outline.py、chapter.py、state.py和main.py,输出目录output/按书名再分卷建子目录。第一次把环境配干净,后面调试会少很多问题。

mkdir novel_gen cd novel_gen python -m venv .venr source .venv/bin/activate pip install -U google-genai

这段命令先建虚拟环境再装SDK,避免污染系统Python。SDK名字在不同时期有过变化,如果google-genai在你的环境里装不上,优先看你手上的zip工程注释里锁的是哪个包名,Gemini的Python SDK曾有过命名调整,代码里import的模块和pip安装的包要保持一致。

import os from google import genai from google.genai import types GEMINI_API_KEY = os.environ["GEMINI_API_KEY"] MODEL_NAME = os.environ.get("GEMINI_MODEL", "gemini-2.5-pro") client = genai.Client(api_key=GEMINI_API_KEY)

API密钥通过环境变量注入是最稳的做法,不要把密钥硬编码在脚本里。多数批量生成失败是配额或权限问题,密钥走环境变量后,换账号、换项目都只改配置不改代码。MODEL_NAME用os.environ.get带默认值,不同地区、不同阶段能访问的模型名可能有差异,运行前检查一下当前账号可用的模型,比对着教程抄一个固定名字可靠。

3.2 核心生成函数:发送提示词的最小可用调用

所有章节生成最后都会落到同一个函数上:把系统指令、用户提示词、生成参数一起发给Gemini,拿到文本后做基础校验。下面这段代码是这套生成器里最核心的骨架,后续所有脚本都围绕它扩展。

def generate_text(system_prompt: str, user_prompt: str, temperature: float = 0.85) -> str: response = client.models.generate_content( model=MODEL_NAME, config=types.GenerateContentConfig( system_instruction=system_prompt, temperature=temperature, top_p=0.95, top_k=48, max_output_tokens=8192, response_mime_type="text/plain", ), contents=user_prompt, ) if not response.text: raise RuntimeError("生成结果为空,请检查内容命中安全过滤或模型返回异常") return response.text.strip()

system_instruction放写作规则和风格约束,user_prompt放本章的大纲、摘要、人物状态,两者分开能让模型更稳定地理解边界。max_output_tokens设为8192,中文环境大概能输出四千到六千字,够覆盖一章常规网文的体量。temperature放在0.85附近,既有文采又不会太飘。生成结果为空不一定是bug,可能是这一段内容触碰了安全过滤,这种时候抛出异常比静默重试更能暴露出问题。

3.3 大纲生成与解析:用结构化输出做状态传递

写长篇小说必须先有骨架,直接让模型自由发挥写大纲,后面很难解析。常见做法是要求模型输出JSON结构,包含卷名、章节数、每章的核心事件和章末钩子。这样程序可以把大纲当作数据去遍历,而不是当作文本去猜。

def generate_outline(book_idea: str, volume_count: int = 3) -> dict: schema = { "type": "object", "properties": { "book_name": {"type": "string"}, "volumes": { "type": "array", "items": { "type": "object", "properties": { "volume_name": {"type": "string"}, "chapters": { "type": "array", "items": { "type": "object", "properties": { "chapter_title": {"type": "string"}, "key_event": {"type": "string"}, "cliffhanger": {"type": "string"} }, "required": ["chapter_title", "key_event"] } } }, "required": ["volume_name", "chapters"] } } }, "required": ["book_name", "volumes"] } prompt = f"请为以下故事创意设计详细分卷大纲,共{volume_count}卷:\n{book_idea}" response = client.models.generate_content( model=MODEL_NAME, config=types.GenerateContentConfig( system_instruction="你是一位资深网文主编,擅长把故事创意扩展成结构清晰的分卷大纲。", response_mime_type="application/json", response_schema=schema, temperature=0.4, max_output_tokens=8192, ), contents=prompt, ) import json return json.loads(response.text)

关键在response_mime_type和response_schema这一组配置,它们让Gemini直接输出合法JSON,省去正则提取的麻烦。temperature在大纲阶段要压低到0.4,大纲是结构性的,过度随机会让后面每一章都跟着歪。cliffhanger字段是我特意加的,网文章节末尾必须留钩子,没有这个字段,模型写出来的章节常常像流水账。

3.4 批处理封装:几十章自动写下去的循环逻辑

拿到大纲JSON之后,主程序要做的事就简单了:遍历每个卷、每章,把章节信息和前情摘要拼进提示词,调用生成函数,写入Markdown或纯文本文件。批处理的核心是状态维护,每写完一章要生成一条短摘要存进状态文件,下一次续写时只带这条摘要,而不是把上一章全文灌进去。

def write_chapters(book_name: str, outline: dict) -> None: for vol_idx, volume in enumerate(outline["volumes"]): vol_dir = f"output/{book_name}/第{vol_idx+1}卷" os.makedirs(vol_dir, exist_ok=True) global_summary = "" for ch_idx, chapter in enumerate(volume["chapters"]): prompt = build_chapter_prompt( book_name=book_name, volume_name=volume["volume_name"], chapter_title=chapter["chapter_title"], key_event=chapter["key_event"], cliffhanger=chapter["cliffhanger"], prev_summary=global_summary, ) text = generate_text(SYSTEM_PROMPT, prompt, temperature=0.85) save_file(vol_dir, ch_idx, chapter["chapter_title"], text) global_summary = update_summary(text, global_summary)

这样的循环逻辑把“一键生成”变成了可断点续跑的任务。某一章因为网络超时或配额耗尽失败时,程序可以跳过它继续跑后面的章节,最后统一重试失败项。global_summary逐章滚动更新,既保留了故事连续性,又把每章的上下文开销控制在稳定范围。这个设计意味着即使中途断电,重新启动程序也能接着之前的状态往下写,不会从头再来。

4. 落地参数校准:temperature、topP与maxOutputTokens怎么搭配不翻车

4.1 从大纲到正文,temperature要按环节调而不是一套用到底

很多生成器从开场到完本都是同一组参数,这是新手最常见的误用。大纲和章节目录是结构产物,需要稳定和可预测,temperature高了会出现章节顺序错乱、事件重复的问题。正文是创意产物,需要一定的随机性避免千篇一律,temperature低了又会出现每章都一个套路的问题。所以我在实际工程里从来不会只设一个temperature。

生成环节temperaturetopP说明
总纲生成0.30.90结构优先,不要天马行空
分卷大纲0.40.95允许局部展开,但整体要稳
章节正文0.850.92均衡叙事流畅度与创意
高潮/反转段落1.20.98需要爆发力时放开限制
章节摘要0.20.90摘要必须忠实于原文

这套数值不是所谓的“黄金参数”,而是我跑了几百章之后沉淀的起点值。如果你发现模型总是写得很平淡,优先调正文那一档的temperature,不要动大纲那档。极端情况下,写关键反转段落可以临时把temperature调到1.2,但同一章里的日常过渡段必须调回来,否则人物性格会连续漂移,上一秒冷酷的男主下一秒就开始讲冷笑话。

4.2 topP和topK是双保险,不要只盯temperature

topP控制候选词的概率累加范围,topK控制模型排序中候选词的数量,两者作用方向一致但机制不同。很多开发者只调temperature,结果发现模型偶尔会蹦出完全莫名其妙的词,这正是因为topP和topK没有约束住长尾概率分布。在小说生成场景里,topP设到0.92到0.95之间比较合适,太低会让词汇选择过于保守,通篇都是安全但无聊的表达。

topK一般放在40到60这个范围。topK设太大会给低概率候选词太多机会,导致角色说出不符合人设的台词;设太小又会让语言缺乏变化,经常出现同一段落里连续出现相同的形容词。我的习惯是把topP当作主要控制旋钮,topK固定为一个中间值后就很少去动它,只有当模型出现明显的词汇重复时才把topK往低调。

4.3 maxOutputTokens与“截断再续”:别指望一次写完一整章

maxOutputTokens设得越高不等于能拿到越长的高质量输出。超过一定长度后,模型后半部分的注意力会明显松散,经常出现前面埋伏笔后面忘记收的情况。我的经验是单次请求的中文有效输出在三千到六千字之间,超过这个量级,宁可把一章拆成两段来写,也不要无限调大maxOutputTokens。

拆段续写的常见做法是:第一次请求生成章节前半部分,第二次请求把前半部分的最后一句作为起始内容,要求模型“从这句话开始自然延续”。这样拼接处虽然会有轻微割裂,但通过第二次生成时携带的上下文可以做到大部分时候无感衔接。关键是续写请求里一定要带上本章完整的大纲和人物状态,而不是只给最后一句话,否则模型会顺着最后一句自由发挥,完全偏离原本规划。

4.4 结构化输出只给计算机看,正文生成别开JSON模式

前文大纲生成用了response_mime_type="application/json",但正文生成绝对不能开结构化输出。正文是给读者看的文字,一旦强制JSON,模型会在段落里塞进不必要的引号和转义,轻则破坏阅读体验,重则漏掉部分情节。正文一律用text/plain,程序不需要解析正文的结构,只需要把文本原样落盘。

结构化输出的正确使用范围是:大纲、人物卡、章节摘要、状态更新。凡是要被程序读取并写入状态文件的,都走JSON模式;凡是最终落盘给人看的,都走纯文本模式。这个界限如果混淆了,轻则增加解析成本,重则把生成器变成一个事故现场。

5. 批量跑稿常见的五个坑:剧情飘、人设崩、复读机与断章

5.1 剧情从第20章开始飘离主线:原因在总纲没有进入每章提示词

现象是小说前15章都按套路走,到第20章左右突然开始在一个支线情节里没完没了地打转,主角要办的事被完全抛在脑后。这不是模型变笨了,而是每章的提示词里根本没有主线目标。章节生成时只带了本章事件,模型只对当前事件负责,当然不会主动往总纲上靠。

解决方法是把总纲压缩成一段不超过两百字的“主线锚点”,拼进每一章的system_instruction。锚点的作用是提醒模型这个故事最终要走向哪里。即使当前章写的是日常和支线,也必须包含推进主线的小步进。每次生成前检查一下上一章在哪一点轻微偏离了主线,在锚点里把这个偏差纠正过来。

5.2 角色OOC:人物卡只写了一句“性格冷酷”,模型当然守不住

小说明明写的是高冷男主,到后面对白变成了话唠,这是重灾区。原因很现实:提示词里对人物的描述太单薄。一大堆角色,每张卡只有一两句泛泛的形容词,模型无法区分他们在特定情境下的反应差异,最终所有角色的语言风格趋于同一——像同一个AI换了个名字。

人物卡要写的是行为反应模式,不是性格标签。比如“男主在别人问及过去时,会用沉默或转移话题来应对;只有面对特定条件才卸下防备”,这种描述模型更容易落实。章数一长还需要做人物状态的滚动同步:每次生成人物出场段落前,把该角色的“最近一次情绪状态”和“已公开的信息边界”写进提示词。一个角色已经向女主坦白过身世,后续遇到相关对话就不该再隐瞒,这类信息不靠模型记忆,靠程序维护的状态表。

5.3 高频词复读:“他微微一笑”一章出现六次

复读机效应的根源不是模型能力,而是提示词里缺少“禁止范围”。网文生成时,如果上一次生成中高频出现的动作、副词、过渡句没有被记录,模型会在新一轮里再次选中它,因为前文中该词的上下文被补全了,概率被推高了。这跟temperature无关,调低了反而更容易闷声重复。

常见做法是在系统指令里动态维护一个“近期禁用词表”,把最近三次生成里出现频率超过一定次数的词汇加进去,要求模型用同义表达替换。同时正文temperature不要长期低于0.8,否则输出分布会集中到概率最高的那几个词上。还有一招是人工校对时把高频词标注出来,每隔几章把这些标注词临时加入禁用词表,效果立竿见影。

5.4 断章断出两段八百字的前情回顾

现象是每章开头都有一段前情回顾式的内容,把上一章结尾发生的事情换个顺序又说一遍。原因在于续写的输入里带了上一章摘要,模型在和前文“asetment”,这坏习惯会累积,到后期每章有近三分之一内容是重复信息。

解决方式是压短摘要。章节摘要必须控制在两三百字以内,只保留事件事实、状态变化和下章需要承接的钩子,不要保留情绪性描写。其次在续写请求中加一句明确指令:“禁止复述上一章已发生的事件,直接从本章核心事件开始。”这句指令看着像玄学,但实测对抑制摘要复读有奇效。

5.5 批量跑到一半API报错:不是代码bug,是配额和频率问题

跑到第30章突然连续报错,通常不是提示词写错了,而是每分钟请求数超限或触发了配额阶梯。Gemini API的限频是按分钟算的,批量生成几十章时如果循环没有休眠,很容易在几分钟内把配额打满。代码里每两次请求之间加time.sleep(2)到5秒,问题就解决大半。

更隐蔽的一个坑是:单次请求超时没有设置重试。网络环境不稳定的时段,请求可能已经在服务端开始生成,但客户端连接中断了。重试时必须使用同一个Session或请求ID,避免重复生成。如果报错消息提到内容安全过滤,则要检查是哪个章节的哪段内容疑似触发了规则,调整措辞而不是盲目重试。

6. 一个能守住长篇秩序的技巧:滚动作家自我审校式验证

最后分享一个我长期使用的验证机制,它也是我每次批量生成后不翻车的前提条件。每写完一章,我不急着落盘,先让Gemini大模型生成一个不超过三百字的“严格审校报告”,对照本章大纲检查三条:核心事件是否完成、伏笔是否埋下或回收、下一章接续点是否清晰。这个报告同时作为下一章生成的前情摘要。

这套机制把生成器变成了一个带闭环的系统。原本的管线是“大纲进来、本章出去”,现在是“大纲进来、本章出去、审校报告再进下一章”。表面上多了一次API调用,多花了很少的钱,但长跑几百章时,面前的总有逐层递加的矛盾和后结局、别忘了先前的允诺,审校报告直接就从中捡起来。如果审校阶段发现哪一条没过,我就让程序自动带上一次的审校意见重新生成该章,而不是继续往后跑。

批处理脚本里需要在请求失败或审校不通过时停下来,不要把所有错误都堆到最后再查。这看起来是个很简单的教训,但我确实见过大量生成器跑完几十万字才发现第8章开始已经严重偏题,返工成本已经大到等于重写。现在我的习惯是第一轮跑通,第二轮精修;第一轮跑的时候不怕丑,目标是结构和章节完整,第二轮再逐章润色。只有第一轮根基稳了,润色才有意义。

打个比方,让Gemini大模型一口气写完一百万字是不现实的,但让它一章一章地在闭环里往复迭代,每一章都带着实现一致的上下文向前移动,才是这个超长篇小说生成器真正需要有的姿态。希望这套流程能帮你在自己的项目里少走几段弯路。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询