
处理 AI Agent 相关项目时最先被消耗掉的往往不是耐心而是上下文窗口和账单上的 token 数量。尤其是需要把某本技术书里的知识变成模型能力时很多人第一反应是把整本书塞进 prompt结果要么超出上下文限制要么花费昂贵。book-to-skill 的思路正好相反先把技术书离线加工成结构化的 AI 技能包模型在回答问题时只按需加载当前问题对应的章节摘要、代码片段和知识索引而不是重新读取全书。这个思路在特定场景下可以把 token 消耗降到一个很低的量级项目标题里提到的 51 倍是作者在部分书籍上的实测结果不代表所有书都能复现但它确实点出了一个核心问题技术书不该作为上下文被投喂而应该被沉淀为技能。这篇文章会从 token 消耗的本质讲起然后完整拆解 book-to-skill 的技能包结构、转换流程、Agent 接入方式以及如何验证 Token 是否真的省下来了。文章最后会给出常见的转换坑位、生产环境落地清单和扩展方向。适合正在做 AI Agent、RAG 应用、企业知识库或者想把手头技术书变成可复用能力的开发者。1. 整本技术书直接投喂给大模型Token 消耗为什么不可控1.1 一个简单计算技术书的 Token 规模在讨论“省 Token”之前先要知道一本技术书在模型眼里到底有多大。Token 是模型处理文本的最小单元中文通常一个字或几个字对应一个 Token英文大约 4 个字符对应一个 Token实际比例取决于分词器。以常见的技术书为例书籍类型大致字数估算 Token 规模200 页入门教程15 万到 20 万字20 万到 30 万 Token400 页实战书籍25 万到 35 万字30 万到 50 万 Token600 页大部头参考书40 万字以上50 万 Token 以上这里还没有计算代码块、表格和重复摘要带来的膨胀。很多技术书里代码占了三分之一篇幅而代码的 Token 密度通常高于普通文字所以实际消耗只会比上面的估算更高。如果一本 400 页的书有 40 万 Token把它完整放进上下文窗口一次问答就要按 40 万 Token 计费。哪怕模型上下文支持 100 万 Token成本也不会因为“支持得很轻松”而下降价格是按实际输入 Token 数量计算的。1.2 上下文窗口和计费模型决定了“全量投喂”不可持续上下文窗口是多轮对话中模型能够看到的最大 Token 数。大多数 API 产品的计费方式分为输入 Token 和输出 Token输入 Token 不仅包含用户当前的问题还包含系统提示词、历史对话、检索结果和任何被拼进 prompt 的文档内容。这意味着喂入一本 40 万 Token 的技术书再问一个只有几十 Token 的问题账单上依然是 40 万 Token 量级的输入消耗。连续问 10 个问题如果每次都重新拼接整本书就是 400 万 Token 量级的消耗。更麻烦的是当另外还需要加入系统提示词、历史记录和工具返回结果时上下文会被快速占满模型真正用于“思考”的空间反而所剩无几。注意上下文长度不仅是一个“能不能放下”的问题还是一个“模型注意力如何分配”的问题。即使窗口足够大长文本尾部内容也容易丢失直接投喂整本书往往不是成本问题更是效果问题。1.3 核心矛盾不是“书太长”而是“大部分内容根本不相关”很多人以为如果把书完整塞给模型模型就能像读过整本书一样回答所有问题。实际上模型对上下文的利用是有限的它会根据用户问题去查找相关片段而不是对整本书做全局推理。一本几百页的书里真正与某个具体问题相关的内容可能只有几千字剩下的大部分内容此时都是噪声。所以问题的关键不是“如何压缩技术书”而是“如何让模型在回答问题时只看到最相关的那一部分”。这就是 book-to-skill 要解决的核心问题把技术书里的知识拆成细粒度、可检索、可加载的技能模块运行时再按需组装。2. book-to-skill 的思路把书转成按需加载的技能包2.1 技能包长什么样book-to-skill 不是简单地把 PDF 转成纯文本而是把一本书加工成一组相互独立、带有元数据索引的技能文件。一个典型技能包目录可以设计成下面这样book-to-skill/ books/spring-in-action/ source/spring-in-action.pdf raw/spring-in-action.txt chunks/ chapter-01.txt chapter-02.txt chapter-03.txt skills/ metadata.yaml index.yaml spring-boot-basics.md test-driven-development.md production-deployment.md api-quickref.md faq.md logs/build.log这里的skills目录就是最终给 Agent 使用的技能包。metadata.yaml描述整本技能包的基本信息index.yaml描述每个技能文件的触发关键词、用途、token 估算值后面的 Markdown 文件才是真正会被加载进模型上下文的内容。每个技能文件不应该被做成对应原始书籍的一整章而是应该按“能力”切分。例如“Spring 事务管理”“单元测试中的 Mock 技巧”“生产环境日志排查”是三个不同能力它们可能来自书中不同章节但在技能包里被重新组织成独立文件。2.2 为什么能省 Token从全量上下文变成“索引摘要代码片段”全量投喂时一次问答的输入 Token 约等于整本书的 Token 数。技能包方式下一次问答的输入 Token 由三部分组成输入 Token 固定系统提示词 用户问题 命中技能文件的 Token固定系统提示词通常只有几百到一千多 Token用户问题几十到几百 Token命中技能文件则按需加载。如果一个问题只需要加载一个 2000 Token 的技能文件那么总输入可能只有 3000 Token 左右。book-to-skill 节省 Token 的原理是离线阶段一次性生成摘要和索引这些成本只在构建技能包时发生一次。在线问答阶段不加载整本书只加载命中的技能文件。技能文件本身经过了压缩保留的是结论、关键步骤、代码示例和注意事项而不是原文的铺垫与重复内容。2.3 跟 RAG 的区别RAG检索增强生成通常会把文档切成小块存入向量数据库每次根据问题检索 Top-K 片段再拼进 prompt。book-to-skill 与 RAG 的目标类似但有几个明显差异维度传统 RAG 做法book-to-skill 做法处理粒度固定长度文本块按能力或主题划分的技能文件检索方式向量相似度检索关键词、标题和元数据索引也可配合向量检索内容形态原文切片摘要、清单、代码片段、FAQ、决策表在线成本每次检索多个切片精简单个或多个技能文件可维护性依赖文档原结构技能文件可单独更新、评估和版本管理RAG 适合数据量大、内容变化频繁、需要实时更新的场景。book-to-skill 更适合内容稳定、结构清晰、需要深度理解的技术书或规范文档因为这类内容在离线阶段付出较多处理成本是值得的。3. 搭建一个最小转换工具把一本书加工成技能文件3.1 环境准备和依赖下面这套示例用于说明 book-to-skill 的实现思路不依赖特定厂商能力。实际项目里可以根据自己的环境替换依赖版本。工具用途说明Python 3.10编写转换脚本文本处理生态最方便PyMuPDFPDF 文本提取也可以使用 pdfplumber、popplertiktokenToken 估算用于统计当前模型的分词结果gpt-4o-mini 或其他便宜模型生成摘要和索引离线任务优先选性价比模型YAML生成技能包元数据便于配置维护安装命令示例pip install pymupdf tiktoken pyyaml openai这里的openai库只用于调用 OpenAI 兼容接口如果你使用其他模型服务可以使用对应的 SDK。重点不是 API 供应商而是整个转换流程如何组织。3.2 文本抽取与章节清洗先用 PyMuPDF 把 PDF 抽取为纯文本。需要注意这一步得到的文本通常会有页眉、页脚、页码、换行混乱等问题不能直接拿去生成技能文件。import fitz # PyMuPDF def extract_pdf(pdf_path: str) - str: doc fitz.open(pdf_path) pages [] for page in doc: pages.append(page.get_text(text)) doc.close() return \n.join(pages)抽取后记录原始数据方便排查问题python extract.py --input books/spring-in-action/source/spring-in-action.pdf \ --output books/spring-in-action/raw/spring-in-action.txt检查点打开生成的 TXT 文件确认章节标题是否完整、代码块是否错乱、表格是否丢失。很多问题必须在这一步发现否则后续产生的技能文件质量会直接受影响。3.3 页面级摘要与关键词抽取原始全文不适合直接进入技能包因为即使是单章也可能超过模型上下文预算。因此先做页面级别或小节级别的清洗与切割再让离线模型生成摘要。一个合理的处理顺序按章节标题拆分全文。对超过阈值的章节做二次切分。对每个切分块调用摘要模型输出结构化 JSON。汇总 JSON 生成索引和技能文件。切割脚本的示意import re CHAPTER_PATTERN r^(第[一二三四五六七八九十百千0-9][章节篇]|Chapter\s\d) def split_chapters(full_text: str): lines full_text.splitlines() chapters [] current_title front-matter current_lines [] for line in lines: if re.match(CHAPTER_PATTERN, line.strip()): if current_lines: chapters.append({ title: current_title, content: \n.join(current_lines) }) current_title line.strip() current_lines [] else: current_lines.append(line) if current_lines: chapters.append({ title: current_title, content: \n.join(current_lines) }) return chapters这里正则只是示例不同书籍的目录格式差异很大。实际项目里建议先统计章节标题的规律再编写适合该书的规则。3.4 生成技能包目录和元数据每个章节块都可以通过一次模型调用来生成结构化摘要。Prompt 示例你是图书知识工程助手。请根据下面章节内容提取技术要点。 要求 1. summary 不超过 150 个汉字保留关键概念。 2. keywords 输出 3 到 8 个关键词尽量使用书中的原文术语。 3. examples 输出章节中的代码示例标题不用写完整代码。 4. decisions 输出该章节适合回答哪些问题用问句形式。 只输出 JSON不要输出其他内容。模型返回的 JSON 可以设计成{ title: Spring Boot 自动配置原理, summary: 自动配置基于 EnableAutoConfiguration 和 spring.factories 机制按条件注解判断是否生效。, keywords: [自动配置, Conditional, spring.factories], examples: [自定义 Starter, 条件装配], decisions: [Spring Boot 的自动配置是如何生效的, 如何自定义自动配置类] }所有章节处理完成后汇总生成index.yaml。每个技能文件保留标题、关键词、路径、预估 Token 数和关联问题。skills: - name: spring-boot-autoconfig title: Spring Boot 自动配置原理 path: skills/spring-boot-autoconfig.md estimate_tokens: 1200 keywords: - 自动配置 - EnableAutoConfiguration - Conditional trigger_questions: - 自动配置是如何生效的 - 如何自定义自动配置 chapters: - chapter-04这里的关键点是指定estimate_tokens用于后续运行时做预算控制。技能文件生成后需要检查整包 Token 规模是否远小于原书。如果相差不大说明摘要粒度太粗或重复内容太多。3.5 把技能包接入 Agent 的调用流程技能包不会直接放进 system prompt而应该通过一层“技能选择器”动态加载。最简单的方式是根据关键词表做匹配再配合最大 Token 预算过滤。import yaml from pathlib import Path SKILL_DIR Path(books/spring-in-action/skills) def load_skill_index(): with open(SKILL_DIR / index.yaml, r, encodingutf-8) as f: return yaml.safe_load(f)[skills] def estimate_tokens(text: str) - int: # 生产环境建议使用与模型一致的分词器 return len(text) // 2 # 中文场景的粗略估算 def select_skill(question: str, max_budget: int 4000): skills load_skill_index() query_tokens estimate_tokens(question) budget_left max_budget - query_tokens selected [] # 先按关键词匹配再按预算过滤 for skill in skills: hit any(kw in question for kw in skill[keywords]) if not hit: continue path SKILL_DIR / skill[path] skill_text path.read_text(encodingutf-8) skill_tokens estimate_tokens(skill_text) if skill_tokens budget_left: continue selected.append(skill_text) budget_left - skill_tokens return selected运行时只需要把命中技能文件拼到 system prompt 或 user prompt 前面你是一名技术专家。下面是本次回答可以参考的技能资料。 skill Spring Boot 自动配置基于 EnableAutoConfiguration 和 spring.factories 机制... /skill 用户问题Spring Boot 的自动配置是如何生效的这样既保留了对应知识又不需要把整本书放进来。生产环境里可以把关键词匹配替换成向量检索或使用模型判断需要加载哪些技能但核心思路不变先索引后加载加载量受预算控制。4. Token 节省效果怎么验证从统计到功能测试4.1 计算原始书籍与技能包的 Token 总量验证省 Token 的第一步是统计原始文本和技能包的 Token 规模。建议使用与线上模型一致的分词器。import tiktoken enc tiktoken.get_encoding(cl100k_base) with open(raw/spring-in-action.txt, r, encodingutf-8) as f: raw_text f.read() with open(skills/index.yaml, r, encodingutf-8) as f: skill_index f.read() print(raw_tokens, len(enc.encode(raw_text))) print(skill_index_tokens, len(enc.encode(skill_index)))如果要统计整个技能包还要把skills下所有 Markdown 文件都读出来。一个比较直观的对比表格如下对象Token 数说明原始书籍全文大约 38 万包含正文、代码、目录、页眉页脚技能包总大小大约 8000所有技能文件的 Token 总和单次问答命中技能1200 到 3000取决于问题的复杂度技能包总大小不等于单次问答消耗。真正要关注的是“单次问答平均消耗”因为不同问题命中的技能数量不同。4.2 按“单次问答”统计真实 Token 消耗全量投喂时无论问什么问题输入 Token 都接近整本书的 Token 数。技能包方案则要统计每次请求拼接后的实际 Token。可以设计一组测试问题记录每次请求的输入 Token 和输出 Token。测试问题建议覆盖书中显式提到的基础概念。隐藏在代码示例中的实现细节。需要跨章节整合的综合问题。完全不在书中的边界问题。例如问题全量投喂输入 Token技能包输入 Token节省倍数什么是自动配置3800001450262 倍如何自定义 Starter3800002100181 倍事务传播行为有哪些3800002600146 倍平均3800002050185 倍这个表格用示例数据展示方法不是某一本书的固定结论。标题中的 51 倍通常是拿整本书与全部技能包对比或者在不同场景下的平均值。真实项目里节省倍数可能从几十倍到几百倍不等取决于书的大小、技能粒度、问题命中率。4.3 验证回答质量不能只看 Token 数省 Token 只是手段回答质量必须同步验证。否则模型可能在完全错误的技能文件里找到了自信的错误答案。建议建立一份质量测试集包含 20 到 50 个业务相关问题和标准答案。至少从三个维度评估相关度回答是否围绕问题展开。准确度关键技术名词和代码示例是否和原文一致。完整性是否有明显遗漏的要点。对比全量投喂和技能包方案时要记录模型输出的差异。如果技能包方案在某个问题上明显变差通常不是模型原因而是技能包内容设计有问题比如摘要丢失了关键代码、索引没有覆盖该知识点、或多个技能文件拼接后互相矛盾。注意不要只验证程序能启动还要验证输入、输出、异常分支和日志是否符合预期。Token 统计同样如此要在真实请求层面记录而不是只算文件总字数。5. 转换过程中最常见的五个坑5.1 PDF 文本乱码或丢失标题层级现象从 PDF 抽取出来的文本里中文变成乱码章节标题和正文混杂在一起代码块缩进全丢。原因PDF 本身不包含结构化语义文字可能以图形、字体映射或多栏排版的形式存在。扫描版 PDF 甚至没有可复制文本层。检查方式抽取后先抽看前 20 页重点看目录、代码、表格、页眉页脚四类内容。处理方式优先使用具有良好文本层的 PDF。扫描版先做 OCR例如使用 PaddleOCR但需要额外增加成本。编写针对该书籍的清洗规则例如去掉重复页眉、修复断行。代码块建议从源码仓库直接读而不是依赖 PDF 里的代码排版。5.2 摘要模型自己也要消耗 Token现象构建技能包时把整本书都拿去调摘要接口离线费用比想象中高。原因离线构建阶段的 Token 消耗是“一次性投入”。如果书有 40 万 Token即使只做一次摘要也可能产生 40 万 Token 的输入费用。如果中间失败重试费用会叠加。处理方式使用便宜模型处理大批量内容不要用昂贵旗舰模型。对章节做切分后并行处理并增加失败重试和去重。构建过程加上缓存对已经处理过的章节跳过。记住这笔费用属于一次性成本分摊到后续大量问答中通常可以被接受。5.3 索引覆盖不全导致 Agent 找不到内容现象模型回答“这本书里没有相关内容”但人工翻书能查到。原因技能包的keywords和trigger_questions覆盖不足。技术书籍中同一个概念可能有多个叫法例如“控制反转”和“IoC”、“依赖注入”和“DI”经常混用。检查方式从书的目录、术语表、索引页抽取同义词与技能包的 keyword 做差集。处理方式在生成关键词时要求模型额外输出同义词和英文缩写。构建完成后对常见问答做检索覆盖率测试。为每个技能文件配置别名而不是只依赖原文术语。5.4 技能包体积膨胀后仍会超过上下文现象技能文件数量越来越多每次问答命中的文件也越来越多最终拼接后仍然超限。原因技能文件切割粒度不够细或索引命中规则太宽导致一个问题同时加载多个大文件。处理方式在技能选择器中加上严格的max_budget预算超出后不再追加技能。将大技能文件继续拆成“摘要 详细内容”默认只加载摘要。对命中多个技能的情况做优先级排序先加载相关性最高的一个。监控历史请求统计每个技能的真实加载频率和 token 消耗。5.5 忽略版本变化导致技能内容过期现象技术书使用的框架版本较老技能包生成的示例代码在当前版本已经无法运行。原因技术书出版有滞后性技能包构建后不会自动更新。处理方式在metadata.yaml中记录源书籍版本、构建日期和适用版本范围。定期根据新版本内容重建技能包。对版本敏感的知识在技能文件中显式标注“适用于 Spring Boot 3.x不适用于 2.x”。上线前用真实运行示例验证技能包中的代码片段。6. 生产环境落地技能包版本管理、质量评估与安全控制6.1 学习环境怎么跑通闭环如果你只是想验证 book-to-skill 是否适合自己可以按下面步骤快速跑通选一本自己熟悉的、结构清晰的技术书最好是 Markdown 或 HTML 版本。只提取前 3 章手工或脚本生成摘要。生成一个最简单的index.yaml。在 prompt 中手动拼接技能内容和用户问题测试回答效果。对比全量投喂和技能包方案的回答质量与 token 消耗。学习环境不需要一开始就做完整流水线重点是把“书变成技能包技能包接入 Agent”的最小闭环跑通。如果第一步就引入向量数据库、多个模型、复杂拆书规则容易陷入工具细节忽略核心流程。6.2 生产环境至少要做四件事生产环境与学习环境的差别不只是代码健壮性更在于流程、质量、安全和成本保障。关注点学习环境生产环境技能包存储本地目录对象存储或 Git 仓库构建流程手动运行脚本CI 流水线定时或触发式构建质量评估人工检查几个问题自动化测试集回归测试成本监控记录 csv 文件按模型、技能、请求维度统计安全控制忽略审查可加载文件、防提示注入、权限校验生产环境的技能包最好纳入 Git 管理因为技能文件本身就是知识资产。每次更新都要走版本变更记录变更内容、影响范围、测试结果。如果技能包数量较多还需要做内容权限控制。例如有些技术书内容不适合开放给所有提问者就要在技能选择器里增加访问级别判断。6.3 一张可复用的检查清单在把一个技能包发布到生产环境之前建议逐项检查原始书籍版本和技能包版本是否都记录在元数据中。技能的标题、关键词、触发问题是否经过实际问答验证。技能文件预估 Token 是否与真实 Token 估算一致。是否配置了单次请求最大 Token 预算。是否有多技能命中时的排序策略。是否对技能文件做了内容安全审查。是否有技能包构建失败时的重试和告警。是否有线上回答质量回看机制。这份清单不是为了形式而是为了避免“技能包能构建出来但上线后回答质量反而下降”的情况。构建成功只是起点线上表现才是最终标准。7. 从省 Token 到真正提升 Agent 能力book-to-skill 表面上解决的是 token 成本问题实际上解决的是“如何让模型在有限上下文里获得更高质量知识”的问题。省下来的 token 不只是钱更是上下文空间这部分空间可以用来承载更多工具输出、历史对话和模型推理过程。下一步可以沿着几个方向继续扩展多本书联合技能包把多本技术书统一索引构建跨领域技能库。动态技能更新结合官方文档更新技能包让 Agent 能回答新版本问题。技能文件自动编排根据任务类型自动选择多技能组合而不是只靠关键词匹配。结合代码仓库把书中的示例代码替换成项目内真实代码片段形成“书本知识 工程实践”的混合技能包。对想上手的开发者建议先拿一本自己最熟悉的技术书做实验。重点不是追求 51 倍的节省而是理解“先离线沉淀、再按需加载”这一思路。真正有价值的不是某个具体项目而是你能否把一本书变成一组可持续维护、可自动评估、可随时调用的技能资产。这会让 AI Agent 从“读过很多书”变成“在需要时准确想起书里最重要的那几页”。