执笔 (ZhiBi)
AI 写草稿,人做定稿 —— macOS 原生(SwiftUI)小说写作软件。核心是人机协同:AI 可以搭骨架、写整章草稿、记台账、查矛盾、给建议;所有 AI 正文都以提案形态存在,作者审查、修改、采纳后才进入 prose.md——可以一键写完一章,但不能绕过人的裁决。
完整设计文档见 ARCHITECTURE.md。
官网:https://asdshuaishuai.github.io/zhibi/ —— 源码在本仓库 docs/(单文件静态页,无构建步骤),由 GitHub Pages 从 main 的 /docs 发布。
亮点功能速览
- 专注模式(⌘⇧F):全窗只剩稿纸,侧栏/骨架/速记全部退场;
- 每日目标:按净增字数记账(删字扣回、导入不计入),头部进度环 + 写作统计页(14 天柱状图 / 连续天数);
- 分段写作:3000 字以上一次性生成,后半段必然退化(句子复读、结尾草草收掉、骨架后几拍被压成一两句交代)。分段按骨架节拍切块,每块带着上一块的实际结尾续写,最后拼成一份草稿提案;每段字数可调(600–2400);
- 一键成章(⌘↩):真一键——草稿 → 一致性审查 → 去AI味 自动串到底,产出全进收件箱,停在「采纳」之前。骨架不在自动串的范围里:它是写前契约、属于正典决定,必须作者亲自批准(没有已批准骨架时,这一步只出骨架提案并停下提示你)。面板里也保留了逐步手动跑与「按意见修复」;
- 创作法典:13 个流派档案(惯例/禁区/爽点形态/开篇律/节奏参数/体系通胀控制)+ 网文创作法(黄金三章、期待感管理、打脸循环、金手指代价律、卷弧结构、主角能动性)+ 传统文学创作法(草蛇灰线、白描、意象、留白、视角与叙述距离、典型环境中的典型人物、春秋笔法、起承转合、文气、复调),按能力裁剪后注入每一次 AI 调用;
- 卷骨架:一次规划 20-40 章的卷级弧光(起承转合 + 章级路标 + 伏笔收支表 + 期待感账),认可后再逐章细化;
- 骨架闸门:批准前用确定性代码给骨架打分——到期伏笔有没有进合同、钩子是否具体、连续多章钩子是否同型、视角有没有漂移、同一时间有没有人分身两地、字数预算是否合理;
- 全书连贯性审查 + 埋点修复:死者复出 / 位置跳跃 / 人称漂移 / 时间线倒挂 / 伏笔台账烂账(种下原文对不上、兑现逾期、疑似已收未记账、动作日志指向不存在的章)→ 每条烂账配一个可一键采纳的修复动作(补埋/改期/回收/搁置/放弃/校正原文/补登记);
- 大纲实时对账:把「建书时的计划」与「正文里实际发生的」逐事件对账,算出剧情线健康度(健康/放缓/停滞/断线/待收束)、事件偏移、阶段完成度,产出大纲更新提案——采纳后大纲才是活文档;
- 全书搜索(⌥⌘F):跨章节正文 / 伏笔 / 设定 / 时间线 / 记忆,点击直达;
- AI 协作面板(⌘⇧J):右侧常驻「对话 / 轨迹」双窗。对话窗让作者直接问书里的任何事——AI 先检索资料库,回答带章节/设定/伏笔来源,并把回答里的短引用对齐到完整出处;来源芯片可点击直达章节或台账,失败可一键重试、已答可重新生成。可以选择对话针对的章节,从零写整章草稿、读取该章最新草稿与你的历次意见后提交完整修订版,也能搭/改骨架、做一致性验证、写档案卡或提议大纲更新,全部只登记提案。对话记录可导出为 Markdown,也可一键归档到作品目录(
chat-archive-<时间>.md)后清空;应用内「查看归档」可回看、恢复到当前对话、在访达中定位或删除,支持按文件名/日期/大小筛选与多选批量清理;归档同时写 Markdown 与可恢复 JSON,导出/归档会附带本次对话登记过的提案快照。轨迹窗把每次 AI 运行的完整链路像聊天一样展开——上下文与工具面准备、每次工具调用与结果回灌、流式输出实时滚动、明确的「完成 / 失败」收尾;跨会话保留最近 200 条;
- 资料库 + 向量记忆引擎:正文、章摘要、章节骨架、设定、档案卡、伏笔、事实、时间线、故事线、阶段统一切片建索引;关键词 BM25 + 本地哈希向量(离线可用)+ 可选 OpenAI 兼容 embedding 远程重排。AI 对话、搭骨架、写草稿、审校、对账都能调用
search_knowledge 找回长程细节,回答会标来源;
- AI 结果就地反馈:设定归类、整理旧稿、短篇成稿、导入后归类等 AI 产出都在触发的那个窗口里直接过目 + 一键采纳,不用绕道收件箱;提案同时在收件箱留痕(铁律不变);
- 去AI味 25 项确定性检测 + 三 pass:叙事架构 → 篇章 → 措辞,配模型指纹、网文结构信号(对白占比/信息倾倒/章末钩子强度/情绪曲线/张力密度)与过度修正反检(去AI味去成通篇破碎短句,本身就是新指纹);
- 导出:合并稿 / oh-story 目录回写 / 分卷 TXT(每 20 章一卷);
- 删除即废纸篓:章节与整本书都可从废纸篓找回。
人机协同边界(产品铁律)
铁律不是「AI 不能写正文」,而是「AI 的一切产出(含整章草稿)只能以提案形态存在,作者采纳前不落盘,采纳时自动快照可回滚」。
| AI 可以(会改书的产出全部以提案交付) | AI 仍然不可以 |
|---|
| 构建核心大纲 / 事件时间线(作者真相 | 读者已知双栏) | ❌ 提案未经作者采纳就改任何台账、大纲或正文 |
| 盘点伏笔 / 埋点登记(F 编号、五档节奏、种下原文) | ❌ 替作者做正典决定 |
| 搭章节骨架(场景层节拍 + 章尾钩子 + 硬交付 + 伏笔触点合同) | ❌ 在作者拒绝后保留数据 |
| 规划卷级弧光(多章路标 + 伏笔收支 + 期待感账) | ❌ 声称"已完成/已保存/已采纳"——以落盘为准 |
| 一键写完整章草稿 / 按意见修订草稿(草稿提案,采纳才进正文) | ❌ 绕过提案与审查直接写 prose.md |
| 在右侧对话里查书、找伏笔、给下一步建议,必要时提交整章草稿提案 | ❌ 改正文而不留快照 |
| 提取记忆 / 旁路记录(写完点"让 AI 记一笔") | ❌ 评风格好坏来代替作者判断(审校只查客观错误) |
| 一键验证 / 全书连贯性审查(只查客观错误,只报告不代改) | |
| 埋点修复方案(只改台账与动作日志,不动正文) | |
| 大纲同步建议(只提案,采纳才写回大纲) | |
| 去AI味(逐处建议,逐条采纳,采纳前自动快照) | |
| 一键召回(上下文包 + 写作备忘) | |
| 编辑对话(查书、找伏笔、给下一步建议,引用资料库来源;可提交草稿/骨架/验证/档案卡/大纲更新提案) | ❌ 把聊天回答当成已落盘的修改 |
一切 AI 产出进入 提案收件箱,由作者接受 / 拒绝;骨架、伏笔、设定等采纳后仍可在对应台账继续修改。完成与否以落盘为准,不信模型口头声明(InkOS 纪律)。
Agent 基座
按 fx (libfx) 的「模型提议、宿主裁决」模型设计,Swift 侧用 OpenAgentSDK 承载 agent 会话:
- 宿主三提供:指令(PromptLibrary)、工具(仅
propose_* + 只读查询,见 NovelTools)、凭据(macOS 钥匙串)。
- 传输:OpenAI 兼容 SSE + tool-calling(兼容 DeepSeek / GLM / Kimi / OpenAI / Ollama 与本地端点)。没有单独的 ACP 子进程通道;模型不调用工具时,宿主会解析围栏 JSON 兜底登记提案。
- 对话:右侧「对话」窗复用同一套 Agent 工具循环(最多 10 轮),流式输出、可中断、工具调用在「轨迹」窗可回看;
get_latest_draft 让对话能拿到最新草稿全文与作者历次意见,get_chapter_skeleton 能读任意章骨架,再提交完整修订版;也能用 propose_skeleton 搭/改选中章骨架、propose_validation 提交本章客观错误、propose_dossier 写长程记忆卡、propose_outline_updates 提议大纲更新。回答里的【第12章】会被对齐到「第12章《雾隐》」这类完整出处;对话历史随项目保存在 chat.json,每条消息即时落盘,下次打开继续聊。
- 记忆检索:
search_knowledge 是横跨正文/章摘要/设定/档案卡/伏笔/事实/时间线/故事线/阶段的只读工具;对话预取 6 条资料再回答(按上下文预算自动收缩历史与资料),搭骨架/草稿/审校/对账也都能主动查。
- 向量:本地哈希向量永远可用;在设置里填
embeddingModel 后,资料库用 OpenAI 兼容 /embeddings 做远程向量重排,失败自动回退,不阻塞回答。远程请求按 16 条分批,向量按「端点 + 模型 + 原文」在进程内缓存;资料库页会明确显示本次是远程成功还是已回退本地。
- 会话状态:每次任务独立,不持久化 SDK checkpoint;对话上下文由项目内的
chat.json 重放,checkpoints/ 仍为预留目录。
资料库与记忆引擎
- 索引来源:每一章正文(按段落到约 600 字切片)、章摘要、章节骨架(含场景层/钩子/伏笔触点)、每篇设定、章档案卡、伏笔、事实三元组、时间线事件、故事线、阶段。
- 关键词层:中文双字/三字滑窗 + 英文数字整词 → 倒排索引 → BM25 排序;零网络、零额外成本。
- 向量层:本地 256 维哈希向量用于离线召回与重排;设置里填
embeddingModel 后,走同 Base URL / Key 的 OpenAI 兼容 /embeddings 做远程重排,按 16 条分批、按原文缓存,超时或失败自动回退并在资料库页标出。
- 缓存:索引是派生数据,按正文/账本的真实内容签名自动失效(同长度改字也会重建),不写盘、不污染作品目录;切片/分词/向量化在后台任务里执行,资料库页显示确定百分比,百万字书稿不会卡住界面;可手动「重建索引」。
- 消费方:右侧对话预取 6 条资料;搭骨架按本章指令/上一章摘要/近章钩子自动召回 4 条,一键写作按主线/骨架/伏笔触点自动召回 5 条,分段落写作每段召回 4 条;
search_knowledge 工具对搭骨架、写草稿、修订、审校、连贯性审查、大纲对账开放,让 AI 在长书里找回具体名词与原文。
- 可见性:侧栏「资料库」页可直接检索全部来源,按来源芯片筛选,显示相关度、命中词与可核对的原文;每条命中都能「前往」到对应章节或台账,章内命中会自动滚动、闪烁并持续高亮原文,直到你移动光标或开始打字;也可以一键「交给 AI」,把出处与原文摘录带进右侧对话继续提问或续写。
构建
cd zhibi
xcodegen generate
xcodebuild -scheme ZhiBi -configuration Debug build # App(执笔.app)
xcodebuild -scheme ZhiBiCli -configuration Debug build # 无头自检 CLI
xcodegen generate 会重写工程文件,顺带清掉 swift-mcp / swift-json-schema 的宏审批状态,之后构建会失败在
Macro "MCPMacros" must be enabled before it can be used。加 -skipMacroValidation 即可(或在 Xcode 里点一次允许)。
运行 App:从 Xcode 打开运行,或 open 构建产物 执笔.app。
App Icon
Icon 由 CoreGraphics 程序化生成(Scripts/make_icon.swift),设计即产品隐喻:宣纸底 · 圆点骨架导轨与关键节点(AI 搭骨架)· 实心墨迹笔画(作者定稿的正文)· 朱砂「执」印。
swift Scripts/make_icon.swift ZhiBi/Sources/Assets.xcassets/AppIcon.appiconset # 重新生成 1024 母版
# 再用 sips 派生 16~1024 各尺寸(见 appiconset 内现有文件),xcodebuild 重编译即可
母版预览:icon_preview.png。
无头自检(不打开 GUI、不碰真实数据)
ZhiBiCli --real-workspace <你的小说目录> # 只读扫描真实工作区验证导入
449 项自检全通过,覆盖:字数统计、AI味 lint 分级(25 项检测器)、章节名解析、容错 JSON、项目存取回环(含骨架/状态跨重启不丢)、快照回滚、伏笔合同验证、跨章重复检测、上下文造包、提案接受入库、归档清空后不复活、坏 JSON 隔离、写签名缓存核对磁盘、合并稿 / oh-story / 分卷导出(含档案卡、对账状态与场景层字段往返)、回退解析器、真实工作区识别,以及:老 JSON 向后兼容(project/骨架/时间线/伏笔/事实/设定/故事线/章节 meta/提案缺新键也必须解得出来,否则用户既有数据会整份丢失)、创作法典流派匹配与钩子度量、去AI味新检测器与「干净文本不误伤」、骨架闸门(合格/烂骨架/分身两地/钩子轮换)、全书连贯性 20 类检查的正反例、埋点修复落库与幂等、大纲对账(已发生/偏移/未发生/排期未到/断线/待收束)的正反例、工具面 schema 合法性与「每个能力都有生产者」、资料库十类来源索引 / 具体名词召回 / 无关词不硬凑 / 哈希向量归一化 / 同长度改字也会重建索引 / 回答短引用对齐完整出处 / 引用可定位到章节或台账 / 命中片段能在原文里定位 / 命中可交给 AI 续问 / 对话记录即时落盘与清空不复活 / 撤掉回复即时落盘 / 对话可导出 Markdown 与归档后清空 / 归档可列出回读、筛选、批量安全删除与恢复当前对话 / 导出附带提案快照 / 旧对话缺提案字段仍能解 / 对话读取最新草稿与作者意见 / 任意章骨架与场景层读取 / 对话按选中章提交草稿与骨架。
宿主往返自检(不需要 API Key)
python3 Scripts/mock_model_server.py 8799 /tmp/zbdump & # 起 mock 模型端点
ZhiBiCli --mock-agent http://127.0.0.1:8799/v1 /tmp/zbdump # 122 项,退出码 0 = 通过
其余自检都是纯函数与内存 store,唯独「宿主把工具面交给模型 → 模型回调工具 → 宿主把 payload 落成提案」这条主链跑不到。而这条链上有个静默失败点:ProposalToolBridge 在 parametersJSON 解析不了时会降级成空 schema,模型拿不到字段定义、产出必然不合格,宿主却一声不响。mock 端点让它变成一条可重复的确定性回归,验证:
- 骨架工具往返后场景层(视角/地点/时间/出场/转折)、钩子形态、爽点类型、所属卷都真的解析出来了;
- 连贯性审查的 AI 六类发现与宿主确定性发现合并落库,埋点修复方案可单条采纳且只改台账不改正文;
- 大纲同步把宿主对账与 AI 补充的建议合并,采纳后故事线状态真的变了;
- 一键写作的草稿采纳前正文一个字没动、采纳时自动留快照;
- 一键成章:没有批准的骨架时不往下串也不代批,批准后草稿/审查/文风一路跑完、正文仍一个字未动;
- 编辑对话:资料库预取 + Agent 工具循环真的跑通,回答带来源;AI 可以提交整章草稿与整章骨架提案,且都绑定对话选中的章;采纳前正文一个字没动;
- 对话重试/重新回答:撤掉旧回复但保留原问题,不堆叠用户提问,并重新登记提案;
- 向量:mock
/embeddings 端点被真实调用,远程向量重排后仍能召回「断刀」;重复文本只请求一次;40 条输入分批请求后仍按输入顺序返回;远程不可达时回退本地并标记;
- 后台索引:重建后进度归位 100%、
isBuilding 复位,索引确实产出片段;
- 分段写作:按节拍切成 3 段、拼装后没有围栏与开场白残渣、续写段的请求里确实带着上一段的实际结尾与场景层、没有批准骨架时拒绝执行;
- 出网请求里确实带着创作法典(题材档案/禁区/期待感管理/起承转合/白描/文气)、工具 schema 不是空壳、工具结果被回灌给模型(agent 循环闭合)。
⚠️ 不要并发跑多个 ZhiBiCli。 它们会抢同一个导出路径 ~/Documents/执笔导出,
全部卡死在 Disk.write → FileManager.replaceItemAt(sample 抓栈停在 _URLReplaceObject → CFURLCopyResourcePropertyForKey),
看起来很像 iCloud/FileProvider 故障,其实清掉僵尸进程(pkill -9 -f ZhiBiCli)后单独跑 60 秒内就完成。
注意 stdout 重定向到文件时是块缓冲的,进程没结束就看不到任何 ✅,别误以为它挂了。
数据与磁盘
<书名>.zhibi/
├── project.json # 书名/题材/作者意图/当前焦点/文风主权
├── canon/ # 设定(三态确定度:已定/暂定/有意留白)
├── outline.json # 故事线 L 编号 + 事件 E 编号(作者真相|读者已知)+ 阶段
├── clues.json # 伏笔台账
├── memory.json # 双时态事实三元组 + 人物别名
├── dossiers.json # 长程记忆:每章档案卡(场景/人物/推进/拐点/钩子/物件)
├── chat.json # 作者与 AI 的对话记录(项目级,最近 200 条)
├── cover.svg # AI 封面(作者采用后落盘)
├── proposals/inbox.json # AI 提案收件箱
├── proposals/archive.json # 已裁决提案归档(清空后不复活)
└── chapters/ch-NNN/
├── meta.json # 状态/骨架/摘要/随手记
├── prose.md # 正文(权威,纯 markdown,随时可带走)
└── snapshots/ # 版本快照(去AI味采纳前自动创建,可回滚)
导入:一等支持 oh-story 目录规范(大纲/ 设定/ 正文/ 追踪/_tracking-state.json),含容错解析(字符串内裸换行、未闭合引号可自动修复);通用 markdown/txt 按 第N章 启发式分类,逐项确认后入库。
导出:① 合并稿单文件;② oh-story 目录回写(大纲/设定/正文/追踪 JSON + 伏笔.md + 上下文.md),与社区工作流互通;③ 与 AI 的对话记录导出 Markdown 或归档到作品目录,并在应用内回看归档。
去AI味
三层(综合 SkillHub Humanizer v4.1 / oh-story 7 Gate / InkOS ai-tells / sepia 三 pass + 网文结构信号):
- 确定性扫描 25 项(零 LLM 成本,随打字更新):
- 措辞层:一级禁用词、"不是A而是B"三毒、NNY 变体、堆叠副词、三字鉴定词、套话填充、公式化转折密度、双音节垫话、三连排比、段首套话、短语复读(一章内同一 4 字短语反复出现=签名句);
- 心理层:心理告知占比、认知动词堆叠("他知道/他明白/他意识到")、抽象名词密度(概念先行,缺可拍摄的东西);
- 结构层:段落等长(变异系数)、句长平坦(连续近等长句)、段首同构与段首复读、对话标签密度、对白占比(<12% 判说明文腔,>68% 判对白灌水)、信息倾倒(连续 900 字无对白)、转场缺失(有时间跳跃却无分节符)、万能过渡句密度;
- 网文命门:章末钩子空泛(钩子必须挂在具体物件/动作/人身上,不能挂在"命运/未来/一切")、情绪曲线平坦(四分法张力落差过小说明全章一个速度);
- 反向保护:过度修正检测——把句子全打碎(平均句长 <9 字且过半是 6 字内短句)本身就是一种"人味指纹",同样要报。
- 五维分级:轻/中/重度(取最高档)。
- AI 逐处建议:original/replacement/gate/reason,只改"怎么说"不改"说什么",逐条采纳,首次采纳前自动快照。
创作法典(CraftCodex)
「吸收经典网文与传统文学的创作风格、哲学、理念」不是往 prompt 里塞一段鸡汤,而是沉淀成可被代码消费的知识:
- 13 个流派档案:玄幻/仙侠/武侠/都市/科幻/悬疑推理/历史/言情/无限流/游戏竞技/灵异惊悚/纯文学/通用。每份含读者预期、题材禁区、可用爽点形态、开篇律、节奏参数、体系通胀控制。作者填的自由文本题材会模糊匹配(长别名优先,"都市异能"不会退化成"都市")。
- 网文创作法:黄金三章、期待感管理(三层期待并行 / 挂账销账 / 期待要可验证 / 拖欠要有利息)、爽点类型学、打脸循环四拍、金手指代价律、卷弧结构、主角能动性。
- 传统文学创作法:草蛇灰线伏脉千里、白描、意象与象征、留白、视角与叙述距离、典型环境中的典型人物、春秋笔法、起承转合、文气与节奏、复调。
- 断章钩子类型学:悬念/危机/反转/信息差/承诺/情绪/登场,每种都带"最容易写砸的方式";连续多章同型会被骨架闸门判为套版感。
- 按能力裁剪注入:搭骨架拿到期待感管理与起承转合,写草稿拿到白描与文气,去AI味拿到白描与节奏(并额外提醒"别把网文改成散文"),审校只拿题材禁区作为设定违背的判据——不把整部法典塞进每次调用。
- 同一套法典也驱动确定性度量:
CraftCodex.hookConcreteness / classifyHook / tensionDensity 被 AILint 与 SkeletonGate 直接调用,零 LLM 成本。
章节生命周期
未规划 → [AI 搭骨架·提案] → 骨架已定(人批准) → 写作中(人写,可按拍填草稿再合入)
→ 初稿 → [一键验证] → 已验证 → [去AI味·逐条采纳] → 已润色 → 定稿
↘ [让 AI 记一笔] → 记忆/伏笔提案 → 人确认入库
设计来源
- InkOS:模型提议/宿主裁决、伏笔五档节奏与账本、hook debt 原文回灌、结算铁律、
author_intent/current_focus 控制文档
- NarraCat:账房/花/尺分界、双时态事实、ContextPack 确定性造包、审校只查五类客观错误
- oh-story:细纲=写前契约、双时间线(作者真相 vs 读者已知)、强制停靠点、单一 JSON 权威
- SkillHub 去AI味技能(Humanizer v4.1 等):三毒判定、L1 硬规则、五维分级、禁用词表
- 网文创作传统:黄金三章、期待感管理、爽点类型学、打脸循环、金手指代价律、卷弧结构、断章钩子类型学
- 传统文学创作论:脂批「草蛇灰线,伏脉千里」、鲁迅推崇的白描、意象与留白、恩格斯「典型环境中的典型人物」、春秋笔法、韩愈「气盛言宜」、巴赫金复调
许可
Apache License 2.0 —— 全文见 LICENSE(与 apache.org 原文逐字节一致,未作修改)。
Copyright 2026 kelthas
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
选它的理由(对一个人写出来的工具最合适的三点):可闭源商用(不像 AGPL 那样强制衍生品同样开源)、
带显式专利授权(第 3 条,避免日后被专利反咬)、改动必须注明(第 4 条,fork 出去的必须说明改了什么,保住上游署名)。
衍生作品保留 LICENSE 与 NOTICE、并在改动处注明即可。