fedorthinks
全部项目
进行中2025 — 至今

PenFreely —— 用 LLM 写出整本书

一个面向整本书写作的工作室。LLM 能写好单独一页,却会在整本书的尺度上丢失情节;PenFreely 用自上而下的计划级联(书 → 部 → 章 → 节 → 页)加上自下而上的摘要来保持连贯,只在页这一层生成正文。模型无关,并配有一个跨平台桥,让你运行自己的本地模型。Rust 后端、SvelteKit、PostgreSQL + pgvector。

访问
角色
Solo founder-engineer
技术栈
Rust · SvelteKit · TypeScript · PostgreSQL · pgvector · Ollama · WebSocket · Tailwind
时间
2025 — 至今

问题所在

LLM 能写好一个段落,也能写好一页。可一旦到了整本书的长度,它就崩了。写到第九章,主角的眼睛 变了颜色,一条支线悄悄消失,结尾又和开篇自相矛盾。模型没有关于整体的记忆——它只看得见眼前的 那扇窗口。所以「给我写一部小说」要么给你一堆不连贯的漂移,要么给你一份含糊的梗概,永远不会是 一本真正、自洽的书。

PenFreely 正是为这个空白而生:在只能看见一本书一小部分的模型之上,把整本书的连贯撑住。

产品做什么

你描述这本书;PenFreely 自上而下搭出一份结构化计划——书 → 部 → 章 → 节 → 页——而且只在 这一层生成正文,每一页都以计划加上此前一切内容的滚动摘要为条件。结构把故事撑在一起;模型只管 一次写好一页。

它在设计上就是模型无关的:你自己挑选提供方和模型,随时切换——云端(OpenAI、Anthropic、 OpenRouter)或你自己的本地模型。每一次生成都会报告它的成本、速度和 token 用量,账单始终在你 掌控之中。而且这是你的书,跑在你的模型上——没有被强加的审查,没有任何平台来决定你能写什么。

我构建了什么

连贯引擎。 核心思路就是自上而下的计划级联,加上自下而上的自动摘要。因为正文只在页这一层 生成——以计划和简短摘要为条件,而不是整份手稿——上下文窗口保持得很小,成本被框住,而书在任何 长度下都保持自洽。

一个本地模型桥——免费且私密。 一个小巧的跨平台二进制文件(penfreely-bridge)让用户通过 Ollama 运行自己的模型,并在工作室里直接使用它。它只向后端发起一条 出站 的安全 WebSocket 连接,因此能在路由器和防火墙后工作,无需开放任何端口,而文字从不离开用户的机器。提供 macOS (Apple Silicon 和 Intel)、Windows 和 Linux 的二进制文件。

一个真实的产品界面。 一个用于规划与写作的 SvelteKit 工作室,提供方/模型选择、按次生成的 遥测,以及从计划到页的完整流程——背后是一个 Rust API。

架构选择

计划才是制品;正文是派生物。 真相之源是那份结构化计划,而不是生成出来的文本。这正是我到处 都在贯彻的 spec-driven 纪律:掌控好计划,任何一页都能重新生成而不破坏整本书。

少生成,保连贯。 只生成页这一层的正文,始终以计划加摘要为条件——绝不把整本书塞进上下文。 正是这一点,让书籍长度的产出既连贯又负担得起。

LLM 无关,直抵内核。 提供方和模型坐在一个端口之后;对系统其余部分而言,本地和云端是同一个 接口。换模型是一种选择,而不是一次迁移——这和我反复强调的「别跟某一个模型结婚」是同一个论点。

clean architecture,严格执行。 Rust 后端是一个分层的 workspace——一个没有 IO 的纯领域 crate,带 use-case 和端口的 application,infrastructure 适配器,以及 HTTP/WS 接口——配合 sqlx 迁移,以及一份和桥共享的带类型 wire 协议。SvelteKit 前端用 vitest 和 Playwright 做测试。从第 一天起就用 PostgreSQL + pgvector,这样检索和规模就不必事后再硬装上去。

当前状态

PenFreely 已经上线并在 penfreely.com 持续开发中。我是独立做的它—— 产品立意、架构和审查都是我的——通过指挥 AI 代理(跑在 Opus 上的 Claude Code、Codex)依据一份 分阶段的规格来产出,每个阶段都端到端构建并带测试。它又是一个可运行的例子,印证我一直在主张的 那件事:挑对结构,把模型 ground 在它之上,然后让它去做它真正擅长的那一件事——写出下一页。