从0开始把PDF教材喂给AI:一条交互式教程生成管线的实战指南
笔者手边有一本 700 多页的英文教材——Real-Time Rendering 第四版,业界简称 RTR4。这本书写得很扎实,图形学的方方面面几乎都覆盖了,但说实话,每次翻到第三章就犯困。不是书写得不好,是那种学术教材特有的密度和语调——每一句都在传递信息,每一句也都像在催眠。
如果你跟我一样,硬盘里躺着几本永远"在计划中"的技术 PDF,你会理解这种感觉:这些书的内容本身没问题,但阅读体验像是盯着混凝土墙看。而手动把笔记整理成博客教程?工程量大到让人望而却步——一本 27 章的书,光排版就要耗掉几个周末。
后来我想了一件事:如果我能把 PDF 直接丢给 AI,让它用我喜欢的那种风格——带吐槽、带踩坑预警、带"我们"而不是"读者应当"的语气——重写成一篇篇能让人读下去的教程呢?
这件事如果做成了,不只是我一个人的阅读问题被解决了——任何一个有技术 PDF 或者 Wolai 笔记文档的人,都可以用同样的方式把"看得懂但读不下去"的资料变成"想继续读下去"的交互式教程网站。
这个想法最后变成了一个叫 Grimoire 的开源项目(GitHub:https://github.com/charliechen114514/grimoire),整条管线从解析到生成到打包成网站全部自动化,中间还夹了一套质量审查机制来盯住 AI 的手。接下来笔者想把这个项目拆开来讲——不只是展示它能做什么,更想聊清楚它为什么必须被设计成这个样子。
先别急着丢给 ChatGPT
这件事最直觉的做法是:把每一章的内容粘贴到 ChatGPT,说"帮我重写成教程风格"。
笔者最开始也是这么干的。然后发现这条路走不通,原因不止一个。
第一道墙是 token 截断。一本正经的技术教材,一章动辄几万字,LLM 的 8K token 输出上限根本兜不住。你让 AI 重写一章内容,它写到一半就停了,后半截直接消失,连个"未完待续"都没给你留。
第二道墙更隐蔽——跨章的概念连续性。第一章提到"渲染管线"的时候给出了一种解释,到第四章再提的时候 AI 已经忘了自己之前怎么说的了,直接换了一套说法。术语不统一这件事在教程里是致命的,读者会在第四章突然怀疑自己是不是看的同一本书。
第三道墙是质量控制。AI 写出来的东西你总得检查吧?27 章的内容,你不可能一章一章手动审。但如果你不审,鬼知道它会在哪一章突然开始用论文腔写东西。
这三道墙拼在一起,指向一个核心认知:"教程生成"不是一个 Prompt 问题,而是一个工程问题。它实际上是五个子问题的组合——概念提取、教程正文生成、练习题创建、要点总结,外加一层质量审查和自动修复。每个子问题需要的上下文不同、策略不同、质量标准也不同。
所以我们需要的不是一个更大的 Prompt,而是一条结构化的管线。
拆解:一条教材变教程的管线长什么样
Grimoire 的管线分四个阶段,每个阶段干一件明确的事,像一条工厂流水线一样首尾衔接。
第一阶段是解析(Parse)。输入可以是 PDF 文件,也可以是网页 URL。PDF 走PDFParser提取文本和图片;网页走引擎系统——Wolai、静态 HTML、Playwright SPA 渲染三选一,也可以自动检测。解析的产物是一份chapters_raw.json,把整本书按章节拆好,后续所有阶段都围着这份结构化数据转。
第二阶段是批量生成(Batch Generate),这是管线的核心。每一章会经历四个 Agent 的接力:ConceptAgent先跑,从原文中提取 10 到 25 个核心概念,同时维护一份跨章节的全局术语表。概念提取完之后,WritingAgent和ExerciseAgent同时启动——一个写教程正文,一个出分级练习题,互不依赖所以并行跑。两者都完成后,TLDRAgent收尾,把全章提炼成最多 5 个要点。多个章节之间也可以并行处理,用--workers N控制并发数,术语表通过快照策略保证并发安全。
第三阶段是质量审查(Review)。独立的ReviewAgent从风格一致性、难度曲线、概念密度三个维度给每章打分,低于 7 分的不及格章节会被送进FixAgent做最小化的定向修复,修完重新送审,循环迭代直到通过或达到最大重试轮次。
第四阶段是打包(Package),把所有生成的教程 Markdown 打包成一个可以直接部署的 MkDocs 静态网站。
这条管线的架构不是拍脑袋决定的。有几个地方的设计决策值得展开说,因为它们直接决定了输出质量。
先看 Phase 2 里 Agent 之间的依赖关系。ConceptAgent必须先跑——它负责从原文中提取 10 到 25 个核心概念,还要区分哪些是本章新出现的、哪些是前面章节已经定义过的。这些概念信息会被后续的WritingAgent和ExerciseAgent消费,所以它是一个前置依赖。但概念提取完成之后,教程正文和练习题之间就没有依赖了——它们各自消费同一份概念列表,互不干扰,所以管线把它们做成并行的,用asyncio.gather同时跑。这一步直接把每章的耗时砍掉了大约 25% 到 30%。
跨章节的术语表(glossary)是一个更微妙的设计。当多个章节并行跑的时候(--workers 4意味着最多 4 章同时处理),每章都能读到术语表,但它们不能同时往术语表里写新概念——否则就会出现竞争条件,A 章和 B 章可能对同一个术语给出不同的定义。Grimoire 的解法是快照策略:所有并行章节拿到的是同一份术语表快照,各自处理完之后,新概念在锁的保护下延迟合并回全局术语表。这意味着并行章节之间不会互相干扰,代价是后跑的章节可能看不到前面章节刚刚提取的新概念——但实践中这个代价很小,因为术语通常在多个章节里重复出现,不会只在一个章节里被首次定义。
Phase 3 的审查环节也是被故意独立出来的。如果生成和审查是同一个 Agent 自己干的,那相当于让学生给自己判卷——你永远不知道它会不会自我感觉良好。独立的ReviewAgent用一套完全不同的评分维度来审视输出,而FixAgent只做最小化的定向修改,不会把整章推翻重写。这个"审查与修复分离"的设计,是保证批量输出质量一致性的关键。
从零开始:5 分钟跑通你的第一个教程
环境搭建很快。笔者的开发环境是 WSL2 上的 Ubuntu,Python 3.12+,整个过程不超过三分钟。
先把项目 clone 下来,创建虚拟环境:
gitclone https://github.com/charliechen114514/grimoire.gitcdgrimoire python-mvenv .venvsource.venv/bin/activate pipinstall-e.这里pip install -e .会以开发模式安装所有核心依赖。如果你还需要 OCR 增强的 PDF 解析或者 Playwright 的 SPA 渲染,可以换成pip install -e ".[all]",一步到位。
接下来是 API 密钥。项目根目录有一个.env.template模板文件,复制成.env然后填入你的 Anthropic API Key 就行:
cp.env.template .env# 编辑 .env,填入 ANTHROPIC_API_KEY=你的密钥如果你用的是第三方代理(比如智谱、DeepSeek 的兼容接口),也可以在.env里设置ANTHROPIC_BASE_URL指向代理地址,Grimoire 会自动走代理。
好了,所有准备工作到这里就结束了。下面这一行命令会把整个管线从头跑到尾——解析、生成、审查(含自动修复)、打包成网站:
python-mcli all books/your-textbook.pdf--slugMYBOOK如果是 Wolai 上的教程网页,把 PDF 路径换成 URL 就行,管线会自动检测域名并选择对应的解析引擎:
python-mcli all"https://www.wolai.com/xxxxx"--slugRTR4--workers4这里的--workers 4开启 4 章并行处理。实测 RTR4 这本 27 章的教材,用 4 个 worker 跑完全部章节只花了大约 15 分钟——包含概念提取、教程正文生成、练习题创建和要点总结。
管线跑完之后,输出在output/MYBOOK/目录下。进到这个目录,用 MkDocs 起一个本地服务器就能预览成品了:
cdoutput/MYBOOK&&mkdocs serve# 打开 http://127.0.0.1:8000 预览到这里你的第一个 AI 生成的教程网站就跑起来了。
灵魂所在:让 AI 用你的风格写教程
如果说管线架构是骨架,那写作风格系统就是 Grimoire 的灵魂。
一般的 AI 写作工具给你一个文本框,你输入"用技术博客风格重写",AI 就按它理解的那个风格给你输出。问题是,AI 理解的"技术博客风格"和你理解的不是同一个东西——它可能给你整出一堆"好了,接下来让我们看看"这种一眼就能识别的模板过渡句,或者用学术论文腔把原本有趣的机制讲得比原文还无聊。
Grimoire 不走这条路。它用一份 600 多行的纯 Markdown 配置文件(config/writing_style.md)来精确控制生成风格的每一个维度——从人格定位、语气规则、叙事节奏到过渡句模板,全部可配。
举一个具体的例子。这份风格文件定义了三种叙事节奏模式,针对不同类型的内容自动切换。第一种叫"SICP 紧绷模式",用在章节引子和核心概念首次亮相的场景——句子短,留白多,一句话只讲一件事,讲完就停,强迫读者停下来思考。第二种叫"侯捷紧密模式",用在机制拆解和代码逐段讲解——每句话都有信息量,没有废话,读者像在跑步机上连续走,节奏紧凑但不留悬念。第三种叫"费曼流动模式",用在类比引入和踩坑故事——思路外放,像在跟朋友聊天,允许绕路和重复。
这套节奏机制解决的是 AI 生成文本最常见的病征——“起伏太平”。每个段落读起来密度一样、节奏一样,像心电图上画了一条直线。而一个好的技术教程,段落之间需要有张力的起伏:建立期待 → 推进展开 → 反直觉的转折点 → 释放和喘息。Grimoire 的风格配置里甚至有一节专门讲"段落张力曲线"的设计,要求每个超过 400 字的大段内建一条完整的张力弧线。
还有一个笔者特别满意的机制——类比回收规则。风格文件强制要求每个类比必须出现三次:第一次建立映射,第二次在讲完真实机制后揭示类比开始失效的边界,第三次在小节末尾用同一个类比检验读者的理解。这解决的是技术写作里最常见的"类比用完就丢"问题——读者看完类比觉得懂了,但一回到真实机制就又懵了,因为类比和现实之间的距离从来没被说清楚。
最终效果长什么样?这里是 RTR4 第二章的生成片段:
实时渲染这件事,本质上是一个残酷的数学游戏。
这听起来有点夸张,但让我们把这个画面拆解开来:你的显示器每秒钟需要刷新几十次(通常是 60 次甚至更多),每一次刷新,计算机都必须在不到 16.7 毫秒的时间里,完成从「这里有辆车」到「屏幕上这辆车该有的颜色和光影」的全部计算。
这不仅仅是算得快的问题。这是一场关于「感知」的战斗。
这不是原文的语气——原文是标准的英文学术教材体。Grimoire 把它重写成了一个带着叙事张力的开场,而风格文件同时控制了这种重写不会跑偏——它不会在第四章突然开始用"本节将介绍"这种官方文档腔。
如果你不喜欢默认的 SICP 叙事风,项目里还提供了第二套模板(writing_style2.template.md),是更接近工程师博客实战风的风格——更强调手把手推进、踩坑预警和"上号!"式的段落标题。复制过来覆盖默认配置就行,一行命令搞定。
不止 PDF:插件式引擎怎么吃掉一整个网站
Grimoire 最早只能吃 PDF,但笔者后来发现很多好的技术教程不是写在 PDF 里的——它们在 Wolai、Notion、各种静态网站上。于是 Web 解析引擎系统被设计成了插件式架构。
核心是一个叫BaseWebEngine的抽象基类,每个引擎只需要实现一个parse()方法——输入 URL,输出标准化的章节数据。引擎的选择逻辑也很直觉:如果命令行里显式指定了引擎名(--engine wolai),就用指定的;如果没有指定,就根据 URL 域名自动匹配(比如wolai.com自动走 Wolai 引擎);如果域名也没匹配上,就回退到静态 HTML 引擎用 httpx + BeautifulSoup 抓取。
内置的三个引擎各有各的绝活。Wolai 引擎是最快的——它不走浏览器渲染,而是直接调 Wolai 的公开 API 拿页面结构,27 章的内容大概 7 秒钟就全部解析完毕。Static 引擎适用于传统的服务端渲染网站,用 httpx 抓页面再用 BeautifulSoup 提取正文。Playwright 引擎最重但最通用,它启动一个无头 Chromium 浏览器来渲染 SPA 页面——React/Vue 那种内容全靠 JS 动态加载的网站,不用浏览器根本拿不到完整内容。
说实话,Playwright 引擎在开发过程中坑了笔者半天。标准的asyncio.sleep()和 Playwright 自带的page.wait_for_timeout()在某些 SPA 网站上会把主线程卡死——页面在那里等着,你的代码也在那里等着,两边互相等,最后一起超时。解决方案是绕开 Python 侧的 sleep,改用page.evaluate()注入一个浏览器内的Promise + setTimeout组合,让等待动作跑在浏览器的事件循环里而不是 Python 的事件循环里。这个坑真的很隐蔽,笔者在这里血压拉满。
如果你需要解析的网站不在内置引擎的覆盖范围内,自己写一个引擎也不难。20 行 Python 代码就够——继承BaseWebEngine,设置NAME和DOMAINS,实现parse()方法,把文件丢到src/parsers/engines/目录下,引擎就会被自动发现和注册,不需要手动配置任何东西。或者你也可以用--engine /path/to/my_engine.py直接指定一个外部文件。
27 章并行跑:断点续跑与并发加速
RTR4 有 27 章,如果串行处理——一章一章排着队跑——整个生成过程会非常漫长。Grimoire 提供了--workers N参数来开启章节级并行处理。
并行的核心挑战不是"怎么同时做多件事",而是"怎么同时做多件事且不出错"。术语表的并发竞争问题前面讲过了——快照策略配合延迟合并解决的。另一个需要处理的是全局 API 并发控制。4 个 worker 意味着最多 4 章同时处理,每章内部WritingAgent和ExerciseAgent又是并行的,所以实际的并发 API 请求数可能是 worker 数的两倍。Grimoire 用一个全局信号量(MAX_CONCURRENT_CHAPTERS * 2)来限制并发请求数的上限,配合指数退避做双重保护,避免被 API 限流直接打回来。
还有一个在工程上很重要的机制——断点续跑。每一章完成后,进度会被原子性地写入progress.json。这意味着你随时可以Ctrl+C中断处理——去吃饭、合上电脑、甚至断网——下次重新运行同一个命令时,管线会自动跳过所有已经完成的章节,从断点继续。对于一本几十章的大书来说,这个机制基本是必须的,因为你不可能保证一次性跑完几个小时的管线而不被打断。
审查 Agent:谁来看住 AI 的手
AI 生成的教程质量不稳定是常态,不是例外。同一套风格配置,第一章可能写得行云流水,到了第五章突然开始堆砌列表、用"本文将介绍"这种论文腔。如果没有审查机制,你需要一章一章手动检查,那自动化管线的意义就打了对折。
Grimoire 的审查系统由两个 Agent 配合完成。ReviewAgent从三个维度给每章打分:风格一致性(style)、难度曲线(difficulty)和概念密度(density),每个维度 1 到 10 分,三项都 >= 7 才算通过。它不只是给个分数——还会给出具体的问题定位,指出哪一段出了什么问题、严重程度如何、建议怎么改。
比如 RTR4 第一章的实际审查报告里,ReviewAgent发现了这样一个问题:练习题的参考答案部分用了"1.xxx 2.xxx"的编号列表体,出现了"根据图形渲染管线的定义……"这种教科书腔调。它给出的修复建议是把解析改写成连贯的叙述体——"如果你把整个流程看作数据在管道里流动,那么裁剪肯定是第一道关卡……"这种风格。
审查不通过的章节会被送给FixAgent,它做的事不是推翻重写,而是最小化的定向修改——只动有问题的段落,保留其余部分。修改完后重新送审,如果通过了就放行,没通过就再修一轮。默认最多修两轮(可通过--max-retries调整)。
这个"最小化修复"的设计是故意的。如果你让 FixAgent 推翻重写,它可能在修好原有问题的同时引入新的问题——相当于用一个新的未知数替换一个已知的问题。定向修改把变动范围控制在最小,每一轮修复的可预测性更高。
在all命令里,审查加自动修复是默认开启的。如果你只想要审查报告不想自动改东西,加一个--no-fix就行。
大章节的暴力拆解:Verbose 模式与自适应分节
标准模式下,Grimoire 对每章做一次压缩重写,输出大约是原文 20% 的篇幅。这个比例对于大多数"想要快速掌握要点"的场景已经够了,但如果你想要的是一份基本保留所有技术细节的忠实改写——比如你想用它替代原文来做学习参考——20% 显然不够。
这就是 Verbose 模式存在的理由。开启后(--verbose-mode),管线会用 PDF 的 TOC 层级结构来自适应分节:先按 L2 标题切分,如果某一节超过 30K 字符就展开到 L3 甚至 L4 子标题。切完之后,每一节独立调用 LLM 进行忠实改写,输出 token 上限也提到了 16K。最终结果是一章被拆成多个文件(ch05_1.md、ch05_2.md、ch05_3.md……),外加一个索引页把它们串起来。
内容保留率从 20% 跳到大约 75%,API 成本也相应地涨了 3 到 5 倍。这是预料之中的权衡——你想保留更多细节,就得花更多的 API 调用。
值得注意的是,即使不开启 Verbose 模式,管线也会自动检测大章节并做分节处理。对于从 Wolai 等网页来源获取的章节,如果原文里包含 Markdown 标题(比如### 12.1 图像处理),管线会按标题切分后逐节处理,防止单次 LLM 调用的输出 token 不够导致内容截断。这个机制对 PDF 来源同样安全——pymupdf 提取的 TOC 通常已经包含多级条目,会优先使用 TOC 数据来分节。
说点现实的:API 成本和耗时
笔者知道大家最关心的一个问题是:这玩意烧多少钱?
以 RTR4 为例,27 章,标准模式,使用sonnet模型,--workers 4并行处理。从progress.json记录的时间戳来看,整个生成阶段从08:44:16到08:59:13,大约 15 分钟。API 成本方面,标准模式下每章大约一次 WritingAgent 调用加一次 ExerciseAgent 调用(并行)加一次 TLDRAgent 调用,总计大约 3-4 次 LLM 调用。27 章加起来大概 80-100 次调用。
Verbose 模式的成本会涨到 3-5 倍,因为每章被拆成多节,每节独立调用。如果你用的是opus模型追求最高质量,价格还会再上一个台阶。
笔者的实用建议是这样的:先用--model haiku快速跑一遍看看整体效果和风格是否符合预期——haiku 的成本大约只有 sonnet 的十分之一,速度快很多。确认风格满意之后,再用 sonnet 正式生成。opus 可以留着给审查环节用(python -m cli review MYBOOK --fix -m opus),让最强的模型来负责质量把关,但不需要让它跑全部的生成任务。
另外,Grimoire 支持通过ANTHROPIC_BASE_URL接入第三方代理,所以如果你用的是智谱、DeepSeek 等提供 Anthropic 兼容接口的服务,直接配置 base URL 和对应的模型映射就行,不需要改任何代码。
魔改指南:插件、Prompt、模型全可换
Grimoire 的设计思路是"分层定制"——你可以不动一行代码就调整大部分行为,也可以深入到 Python 层做任意扩展。
最简单的定制是换写作风格。编辑config/writing_style.md,这是一个纯 Markdown 文件,你写的每一条规则都会被 Agent 当作风格指令来遵循。文件写得越详细,生成的教程风格就越一致。项目自带两套模板,一套是默认的 SICP 叙事风,一套是工程师博客实战风,复制过来改一改就能用。
再深一层是调整 Agent 的 Prompt。所有 Agent 的系统提示词和用户提示词都在prompts/system/和prompts/user/目录下,全部是纯 Markdown 文件——不涉及任何 Python 代码。这意味着你不需要理解项目的代码结构就能调整 Agent 的行为。想让练习题出得更难?改prompts/user/exercise_user.md。想让 TLDR 更精炼?改prompts/user/tldr_user.md。
最深的一层是代码扩展。Web 解析引擎前面已经展示过了——继承BaseWebEngine,20 行代码搞定一个新引擎。如果你想做更激进的事情,比如添加一个新的 Agent 类型或者修改编排逻辑,项目结构很清晰:每个 Agent 一个文件,编排逻辑在orchestrator.py,批处理在batch.py,都有充分的注释。
Prompt 与代码分离是整个定制系统里最重要的设计决策。它意味着一个不懂 Python 的人——比如一位专注于教学法的内容创作者——也可以通过编辑 Markdown 文件来精确控制 AI 的输出风格,而不需要碰任何代码。
还没完——接下来想做什么
Grimoire 目前还有一些局限,笔者不打算藏着掖着。PDF 解析依赖正则匹配Chapter N格式的章节标题,如果你的 PDF 没有这种格式(比如中文教材用"第 N 章"),需要改一下正则。所有的 Prompt 和风格配置目前是中文的,英文支持需要翻译 Prompt 文件。Playwright 引擎需要安装 Chromium 的系统依赖。
项目在 GitHub 上开源,MIT 协议,欢迎提交 Issue 和 PR。如果你有好的写作风格配置或者新的 Web 引擎实现,笔者非常乐意把它们集成进项目。
回到开头那个 700 页的 PDF
还记得开头说的那本 RTR4 吗?笔者现在已经能用大约 15 分钟把它从一本 700 页的学术教材变成一个 27 章的交互式教程网站——每章带着概念梳理、练习题和要点总结,写法是那种笔者自己愿意读下去的叙事风格,不是催眠的学术腔。教程正文生成之后还有一轮自动质量审查兜底,不达标的章节会被自动修复。
Grimoire 做的事情不是"让 AI 写东西"——市面上做这件事的工具已经太多了。它做的是把 AI 生成当作一个严肃的工程问题来对待:用多 Agent 管线分工协作、用独立的审查机制质量控制、用可配置的风格系统保证输出一致性、用断点续跑和并行加速处理工程实用性。这些设计决策没有一个是为了炫技——每一个都是为了解决"你拿到的那份 AI 输出到底靠不靠谱"这个核心问题。
如果你手边也有几本一直想啃但啃不下去的技术 PDF,或者有一堆 Wolai 笔记想变成更系统的教程,可以试试 Grimoire。毕竟,AI 时代了,我们不应该还在用最原始的方式啃教材。
GitHub:https://github.com/charliechen114514/grimoire — Star、Issue、PR 都欢迎。