简介面向零基础网文写作者与老书虫的AI辅助小说创作方案采用Harness架构将创作流程拆解为扫榜、拆文、写作、去AI味、封面生成等专项Agent覆盖创作全流程。包内共103个文件以Markdown笔记、Python脚本、JSON配置、PNG样例图、文本说明为主整体336KB轻量易部署。已有36人学习适合网文爱好者与小型工作室。资源内置百万级语料微调写作模型与27类文风调控权重支持起点、晋江、番茄等平台调性去AI味模块采用三轮对抗式重写封面生成集成SDXL定制LoRA模型。所有Agent通过统一消息总线通信可自由增删模块附带Docker部署脚本、GPU加速指南及四大品类500组训练提示词库能构建从灵感到数据看板的端到端工作流。1. 这个 .zip 不是小说成品而是一条 AI 网文流水线Harness 架构想解决什么拿到那个.zip之前我以为里面是一本写完的网文。解压之后才发现交付物不是小说而是一条“能把网文从零写到上架”的 AI 写作流水线一个用 Harness 架构思想搭出来的多专项 Agent 协作工程。它里面没有动辄几万字的正文只有几段 Python 脚本、一批 prompt 模板、一个状态文件以及一组各管一摊的专项 Agent——有人负责世界观有人负责角色有人负责章节。对完全没有写作经验的小白它把“想故事”变成了“填任务卡”对读过几千本的老书虫它把脑子里那些黑匣子式的灵感拆成了可干预、可修改的中间产物。这篇文章会把这条流水线拆开告诉你 Harness 架构思想到底是什么多个 Agent 怎么协作以及从解压到跑通要躲开哪些坑。2. Harness 与专项 Agent 的分工为什么单个 Agent 写网文会越写越崩先说结论Harness 不是某个新模型也不是某个必须引入的重型框架而是一种“把多个 Agent 组织起来干活”的架构思想。很多开源项目喜欢给自己加harness后缀比如 DeepSeek Harness、某某 Harness其实都在做同一件事在模型调用外层加一套可控制的流程把“谁先跑、传什么、共享什么、失败怎么办”全部定下来。网文写作正好是这类架构最典型的应用场景因为单 Agent 写网文的翻车方式大家太熟悉了。2.1 Harness 和 Agent 的区别编排层才是多 Agent 协作的主心骨做 Agent 开发的人经常问harness 和 agent 到底有什么区别我的回答是Agent 是干活的人Harness 是工地上的项目经理加图纸加安全制度。一个 Agent 本质上是“一个大模型 一份 prompt 一次调用”它只能完成一件事给一个输入产出一个输出。你让它写一千字开篇它写得出来但你让它接着写十万字它就开始出现“三章前主角还叫林澈五章后变林彻”这种低级问题。原因是单个 Agent 的上下文窗口有限记忆会漂移而且它没有“这是第几卷、这条伏笔埋了没有、这个配角是不是已经死了”这种全局状态。Harness 的价值就在这里。它不负责写小说它负责管理参与写小说的所有 Agent决定谁先执行把上一个 Agent 的结构化输出变成下一个 Agent 的输入把共享状态世界观、人物卡、大纲集中放在一个地方还能在关键节点停下来等人确认。网文写作最怕的不是某一章写得不好而是前后不一致、节奏混乱、人物行为逻辑断裂。这些问题靠单个模型本身解决不了只能靠编排层从流程上兜住。很多人第一次看到“Harness 架构思想”觉得高深其实落到代码上它是一个循环、一个状态字典、一张执行顺序表。后面我会给一个 30 行的最小调度循环先记住这句话Harness 是把多个 Agent 串成流水线的胶水也是防失控的安全带。2.2 一个网文 Harness 的角色表谁产出世界观谁产出章谁又负责当“监工”在动手写代码之前先把职责边界画清楚。常见的落地做法是拆成六个专项 Agent每一个只负责一个窄任务产出必须是结构化数据。Agent核心职责输入输出世界观 Agent构建力量体系、地理、势力、核心冲突用户一句“创作愿望”world.json结构化设定角色 Agent设计主角、配角、反派的人物卡world.json 用户人设偏好characters.json人物档案大纲 Agent把设定拆成卷和章节的节奏world.jsoncharacters.jsonoutline.json每章目标章节 Agent按大纲产出正文草稿世界观摘要 角色卡 本章大纲chapter_{n}.md一致性审查 Agent检查人名、时间线、战力、约定是否冲突最新章 历史设定问题清单 修改建议润色 Agent文风打磨、节奏调整、口语化原始章 style_guide.md可发布的章稿表格里最容易被忽略的是“一致性审查 Agent”。很多初版方案只有前四个结果写出来的东西照样前后打架。后来我学乖了把审查 Agent 单独拆出来让它在每个章节写完后跑一遍专门当监工。为什么不让章节 Agent 自己审查因为生成和评估是两个方向放在同一个 prompt 里会互相干扰模型既要写得热血又要理性核对最后往往两头都不到位。除了职责拆分还要注意不同 Agent 的参数差异。世界观 Agent 需要发散temperature可以调到 0.9章节写作要稳定temperature调到 0.7 左右一致性审查必须精准temperature接近 0。这就是为什么不能所有 Agent 共用一个模型配置。2.3 最小调度循环用 30 行 Python 把 Agent 串起来下面这个骨架是所有流程的核心。它做的事情很简单按照顺序执行 Agent每个 Agent 从共享状态里取输入产出的结果写回状态字典失败时重试。# harness_core/scheduler.py from dataclasses import dataclass, field from typing import Dict, Callable dataclass class Harness: agents: Dict[str, Callable] # 每个专项Agent的入口函数 state: Dict field(default_factorydict) # 全局共享记忆 order: list None # 执行顺序如 [world, characters, outline] max_retries: int 2 # 单个Agent失败后的重试上限 def run(self, stop_afterNone): if self.order is None: raise RuntimeError(Harness 必须指定 agent 执行顺序) for idx, agent_name in enumerate(self.order): if stop_after and idx stop_after: break for attempt in range(self.max_retries 1): try: output self.agents[agent_name](self.state) self.state[agent_name] output break except Exception as e: if attempt self.max_retries: raise RuntimeError(f{agent_name} 连续失败 {self.max_retries1} 次: {e}) print(f[retry] {agent_name} 失败正在重试…) return self.state这段代码有四个参数值得细看。agents是每个 Agent 的人口函数实际工程里它们通常会读prompt_templates/下的模板、调用大模型接口、再把结果解析成字典。state是唯一真源所有 Agent 都从它读输入、写回输出不要搞第二套状态。order是执行顺序网文流水线一般固定为世界观 → 角色 → 大纲 → 章节但你可以通过改这个列表来决定先写哪部分。max_retries必须限制我看过有人默认设成 3结果大模型接口一次超时整条流水线卡了五分钟实际上重试 1 次就够了连续失败说明 prompt 或接口有问题再重试也是烧钱。这个骨架看起来简单但它已经具备了断点能力stop_after参数可以在跑完某个 Agent 后停下来让人检查state里的产物再继续。很多人以为多 AI 协作一定要上分布式框架实际上网文创作这种场景十几章的量级一个文件型状态字典完全够用。3. 把这套 .zip 跑起来目录解压、配置模型密钥与第一个 Agent 调用聊完架构思想现在进入落地。拿到.zip的第一件事是解压然后按目录结构认识工程。不要一上来就双击.py先把每个目录为什么存在搞清楚。3.1 交付物目录长什么样目录设计即 Agent 边界我见过不少 Agent 工程把提示词、脚本、状态全混在一起改一个 prompt 要翻半天代码。这个.zip代表了一种更好的做法目录划分直接对应 Agent 边界。novel_harness/ ├── start.py # 一键启动入口 ├── requirements.txt # 依赖清单requests、pyyaml ├── config.yaml # 模型端点、密钥、temperature 默认值 ├── llm_client.py # 统一的大模型调用封装 ├── harness_core/ │ ├── scheduler.py # 上面的最小调度循环 │ └── state_manager.py # 共享记忆读写与变更日志 ├── agents/ │ ├── world_builder.py │ ├── character_designer.py │ ├── outline_creator.py │ ├── chapter_writer.py │ └── consistency_checker.py ├── prompt_templates/ # 所有 prompt 都在这里改提示词不用动代码 ├── state/ # 运行时生成不要手工编辑 │ ├── world.json │ ├── characters.json │ ├── outline.json │ └── changes.log ├── overrides/ # 老书虫的追加要求优先级最高 └── output/ # 生成的章节 Markdown这个目录结构最值得学习的是prompt_templates/和overrides/。前者把所有提示词从代码里拿出来新手改设定不用找逻辑后者是给用户“插嘴”的地方后面会细讲。state/不用手工维护但changes.log很重要它记录每一步谁改了什么设定遇到问题能回溯是哪儿改崩的。3.2 初始化环境与模型接入DeepSeek Harness 的常见调用姿势解压之后先建虚拟环境不要直接往系统 Python 里装依赖避免污染其他项目。Mac/Linux 和 Windows 的激活命令不一样我一般会在start.py里自动做这一步但手工跑一遍有助于理解。unzip novel_harness.zip cd novel_harness python -m venv .venv source .venv/bin/activate # Windows 用 .venv\Scripts\activate pip install -r requirements.txt依赖通常只有两个requests和pyyaml因为大模型调用建议走 HTTP不引入重型 SDK。模型接入是这套工程里最容易出问题的地方。常见做法是把“调模型”封装成一个统一函数所有 Agent 都走这个入口而不是每个 Agent 自己去拼请求。# llm_client.py import os, yaml, requests def load_config(pathconfig.yaml): with open(path, encodingutf-8) as f: return yaml.safe_load(f) def call_llm(messages, temperature0.8, max_tokens1500): cfg load_config()[model] resp requests.post( cfg[base_url] /chat/completions, headers{Authorization: fBearer {cfg[api_key]}}, json{ model: cfg[name], messages: messages, temperature: temperature, max_tokens: max_tokens }, timeoutcfg.get(timeout, 120), ) resp.raise_for_status() return resp.json()[choices][0][message][content]这里三个参数你需要根据自己的场景调。temperature是生成随机性的核心世界观任务给 0.9章节写作给 0.7一致性审查给 0.1不要全用默认值。max_tokens要按产出长度来写一章正文至少 2000提取人物卡 500 就够设置太短会被截断成半句话。timeout要留到 120 秒因为长文生成经常超过 60 秒提前断开只会浪费一次请求。如果你用的是 DeepSeek 这类 OpenAI 兼容接口config.yaml里的base_url换成对应地址就可以/chat/completions的请求结构不变。也可以把它指向本地模型网关代码不用改。3.3 跑通“世界观 Agent”从一份 prompt 模板到一份结构化设定第一个要跑通的是世界观 Agent。这个 Agent 的任务是把用户一句“创作愿望”扩展成一份可用于后续所有 Agent 的结构化设定。它依赖一份模板文件而不是把 prompt 写在代码里你是网文世界观架构师。请基于以下“创作愿望”生成世界观设定。 创作愿望 {user_seed} 要求 1. 输出必须是JSON字段为world_name, power_system, geography, factions, history, core_conflict 2. 每个字段不超过100字使用中文 3. 必须把“冲突”写得具体不要只说“正邪对抗” 4. 如果有{extra_requirements}必须合并进对应字段对应的 Agent 代码如下# agents/world_builder.py from llm_client import call_llm def build_world(seed: str, extra: str ) - dict: with open(prompt_templates/world_builder.md, encodingutf-8) as f: template f.read() prompt template.replace({user_seed}, seed).replace({extra_requirements}, extra) text call_llm( [{role: user, content: prompt}], temperature0.9, max_tokens800, ) # 只提取JSON块防止模型在回答里加点评。 import json, re match re.search(r\{.*\}, text, re.S) world json.loads(match.group(0)) with open(state/world.json, w, encodingutf-8) as f: json.dump(world, f, ensure_asciiFalse, indent2) return world这里有几个细节新手容易翻车。用replace而不是 f-string是因为模板里有大量花括号直接格式化会炸。用正则先抠出 JSON 块是因为很多模型会在 JSON 外面包一段“好的我来帮您”或者 markdown 代码块标记直接json.loads会报错。state/world.json一旦生成后面所有 Agent 都从它取设定所以这个文件是整个流水线的第一块基石。跑通后你会看到state/目录下多了一个world.json里面是结构化的世界观。到这一步你已经完成了“输入一句话产出设定库”的闭环。4. 让多个专项 Agent 协作产章状态文件、任务卡与断点续写单个 Agent 跑通不算本事多个 Agent 协作才是这套工程的核心。很多单 Agent 写网文写到一万字就开始飘是因为它在脑内维护人物小传而多 Agent 流水线的核心是把“记忆”搬到磁盘上用状态文件共享信息。4.1 用 state.json 当共享记忆每个 Agent 只读自己需要的那一块我在自己的工程里会写一个state_manager.py专门负责状态读写。它解决两个问题一是防止所有 Agent 都往全局字典塞东西导致混乱二是实现“上下文裁剪”——每个 Agent 只拿自己需要的那一小块设定而不是把整个世界观灌进 prompt。# harness_core/state_manager.py import json, os, hashlib STATE_DIR state def _path(name): return os.path.join(STATE_DIR, name .json) def get_slice(name, keysNone): with open(_path(name), encodingutf-8) as f: data json.load(f) if keys: return {k: data[k] for k in keys if k in data} return data def merge_slice(name, updates): with open(_path(name), encodingutf-8) as f: data json.load(f) data.update(updates) with open(_path(name), w, encodingutf-8) as f: json.dump(data, f, ensure_asciiFalse, indent2) # 记录一行变更日志方便回溯哪一步改了设定 with open(os.path.join(STATE_DIR, changes.log), a, encodingutf-8) as log: log.write(hashlib.sha256(json.dumps(updates, ensure_asciiFalse).encode()).hexdigest()[:8] name \n)这个模块的get_slice支持只读指定字段。例如章节 Agent 写作时只需要power_system和factions你就不必将整个历史设定都塞进去。这能显著降低 token 消耗也能减少模型被无关信息误导的概率。merge_slice在写入时同步记录变更日志每次 Agent 改了设定都能定位到具体是哪一步做的。补充一个参数经验当state/world.json超过几千字时不要全量读取。可以在config.yaml里设max_context_chars: 4000然后对json.dumps结果做截断并在 prompt 末尾补一句“以下设定超出长度已省略只保留与本幕相关部分”。粗暴但有效。4.2 从大纲到第一章完整跑一节“世界设定 - 角色 - 章节”的链路现在把前面的模块串成一个真正的流水线。顺序是先建世界观再设计角色再写大纲最后循环写章节。# pipeline.py from agents.world_builder import build_world from agents.character_designer import design_characters from agents.outline_creator import create_outline from agents.chapter_writer import write_chapter from harness_core.state_manager import get_slice def run_first_batch(seed, num_chapters3): build_world(seed) design_characters() create_outline(num_chapters) for ch in range(1, num_chapters 1): # 每次只取该章大纲和必要设定避免上下文膨胀 world get_slice(world, [power_system, factions]) chars get_slice(characters) outline get_slice(outline, [fchapter_{ch}]) md write_chapter(ch, world, chars, outline) with open(foutput/chapter_{ch}.md, w, encodingutf-8) as f: f.write(md)在这里角色 Agent 的输出characters.json和大纲 Agent 的输出outline.json是承上启下的关键。大纲的结构建议用下面这种紧凑格式让章节 Agent 一眼看懂本章任务{ chapter_1: { title: 第一巴掌, goal: 让主角穿越后第一次用新获得的能力解决问题, climax: 主角当众揭穿村长私吞灵石, twist: 看似普通的村童其实是上界探子 } }章节 Agent 拿到这份任务卡后再结合world和chars切片生成正文。注意这里只传了outline.chapter_1没有传整个大纲文件目的是防止章节 Agent“提前知道太多”导致剧透式的平淡写法。这个流程跑完你会得到output/chapter_1.md。但此时千万不要急着让整条流水线刷完十卷。第一次跑通后先看一章再决定要不要把num_chapters调大。4.3 人工干预点老书虫在哪个环节塞私货最有效全自动不是目标落地要给用户“插嘴”的机会。尤其老书虫脑子里有大量网文套路和喜好如果 Harness 不让他们干预生成的文再流畅也是死的。这就是overrides/目录存在的意义。# harness_core/read_override.py import os def read_override(slot: str) - str: path foverrides/{slot}.md if os.path.exists(path): with open(path, encodingutf-8) as f: return f.read() return def inject_override(prompt: str, override: str) - str: if override: prompt \n\n### 你的追加要求优先级最高\n override return prompt这个机制的参数很灵活。slot可以对应某个具体章节比如overrides/chapter_2.md也可以对应某个角色比如overrides/character_leader.md。Harness 在生成下一个节点前把用户写好的要求追加到 prompt 末尾并注明“优先级最高”。为什么放在末尾因为在长上下文里模型对末尾内容的注意力往往最强放在开头容易被后续指令稀释。这一步是整套架构的分水岭它把“多个 AI 协作”变成了“人 多个 AI 协作”。小白可以只填空老书虫可以在关键设定上亲自把关两边都不痛苦。5. 多 Agent 写作最容易踩的 5 个坑现象、原因与排查解法跑通和跑好是两回事。我在这类 Harness 工程上踩过的坑几乎都集中在上下文管理和工程化交付上。下面这 5 条按“现象 → 原因 → 解决”写清楚希望能帮你少走弯路。5.1 上下文与记忆类故障设定漂移、风格漂移坑 1主角写到一半改名战力体系崩了。现象第 3 章主角还叫“林澈”第 5 章变成“林彻”第 2 章刚说了筑基后期第 4 章直接金丹。原因章节 Agent 只拿到了当前章的大纲没有从state里读取角色卡和最新境界或者角色卡太长被上下文裁剪挤掉了。解决在章节写作的 prompt 里强制加一段“开始正文前先列出本章涉及的人物与当前状态”让模型先输出一段核对清单再动笔。同时让一致性审查 Agent 在每章写完后跑一次发现不一致就打回重写。不要以为这是多余网文读者对这种人名和战力错误非常敏感。坑 2每章文风不一样像换了个人在写。现象第 2 章热血打斗第 3 章突然抒情散文化对话方式也变了。原因多个 Agent 各自为政没有共享一份“风格指南”或者风格指南写得太抽象比如只有“要有网感”四个字。解决在 State 里放一份style_guide.md包含硬约束和软参考两部分。硬约束写死第三人称、过去时、每章结尾停在悬念处软参考给三段范例文字明确告诉模型“学这个味道”。然后把它作为公共片段注入到每个生成类 Agent 的 prompt 里。5.2 工作流与工程化故障环境跑不起来、token 烧得太快、用户指令被覆盖坑 3小白拿到.zip跑不起来报ModuleNotFoundError。现象双击start.py控制台立刻报缺依赖。原因交付物里没有requirements.txt或者有但用户没激活虚拟环境就直接跑。解决start.py开头自动检查缺少的包提示“正在安装缺失依赖请稍候”不要只在文档里写命令因为小白会在错误的 Python 环境里反复尝试。另外脚本内部用sys.executable而不是写死python避免多版本混用。坑 4token 消耗爆炸写三章烧掉一个月的预算。现象每章生成前调了好几次模型账单涨得飞快。原因每个 Agent 都把整套世界观、全部角色卡、前面所有章节原文塞进 prompt失败重试默认设成 3 次一次超时接着再烧两次。解决在state_manager.get_slice里做上下文裁剪只传当前章节必要的字段把max_retries从 3 降到 1章节 Agent 输出时不要重复粘贴大纲原文。还有一个容易被忽视的点一致性审查 Agent 不要读整章正文只读“设定快照 新增章”就能判断节省一半 token。坑 5老书虫的私货被 Agent 无视。现象用户明确在overrides/里写“这章不要让女主角出场”结果女主角还是出场打了一架。原因用户指令放在 prompt 开头模型在长文生成中把它当弱约束忽略了。解决把 override 内容追加到 prompt 末尾并标记“最高优先级”生成后做一次关键词校验如果指令包含“不出场”这类要求检查输出里是否出现对应人名出现则触发重写。这不是玄学而是让用户追评成为硬约束的工程手段。如果你排查时发现某一步莫名其妙先别怀疑模型去看state/changes.log。多 Agent 协作里 80% 的问题都能追溯到“上一个 Agent 写坏了状态文件”。6. 进阶把人工“改稿权”做成断点让 Harness 跟着老书虫的思路走6.1 检查点不是暂停而是面向老书虫的“软路由”我在自己的工程里加了一个检查点机制每写完一章流水线自动暂停把当前章节的故事状态摘要写出来然后读取老书虫对下一章的要求。这个机制不是用来打断生成而是把人类经验插在模型最容易跑偏的地方。# checkpoint.py from harness_core.state_manager import merge_slice import os def checkpoint_after_chapter(chapter_no): summary f第{chapter_no}章完成当前人物关系/战力/已埋钩子见state/checkpoint.json merge_slice(checkpoint, {fchapter_{chapter_no}: summary}) note_file foverrides/next_chapter_{chapter_no 1}.md if not os.path.exists(note_file): with open(note_file, w, encodingutf-8) as f: f.write(# 你对下一章的要求\n\n) print(f已生成 checkpoint {chapter_no}请编辑 {note_file} 后按回车继续) input()这个断点设计的核心是“Harness 不要自作主张”。我一般每写 3 章停一次让老书虫改一版“下一章方向”再继续。看起来慢了但实际上避免了后面 10 章全部推倒重写。很多人以为多 Agent 就是全自动其实把它当成“带审稿环节的流水线”才不容易崩。我以前迷信全自动让 Harness 一口气跑完十章结果主角性格曲线完全失控女主中途换了三次名字。后来我把检查点加回去才发现真正有价值的是“在关键处让人进来把关”而不是让模型自己一条路走到黑。希望帮到你。本文还有配套的精品资源点击获取