☰
book-to-skill:将技术书转化为AI技能包,降低Token消耗
2026/10/21 2:59:00 网站建设 项目流程

处理 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 万 Token
400 页实战书籍25 万到 35 万字30 万到 50 万 Token
600 页大部头参考书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、poppler
tiktokenToken 估算用于统计当前模型的分词结果
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 页面级摘要与关键词抽取

原始全文不适合直接进入技能包,因为即使是单章,也可能超过模型上下文预算。因此先做页面级别或小节级别的清洗与切割,再让离线模型生成摘要。

一个合理的处理顺序:

  1. 按章节标题拆分全文。
  2. 对超过阈值的章节做二次切分。
  3. 对每个切分块调用摘要模型,输出结构化 JSON。
  4. 汇总 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", encoding="utf-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(encoding="utf-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", encoding="utf-8") as f: raw_text = f.read() with open("skills/index.yaml", "r", encoding="utf-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 是否适合自己,可以按下面步骤快速跑通:

  1. 选一本自己熟悉的、结构清晰的技术书,最好是 Markdown 或 HTML 版本。
  2. 只提取前 3 章,手工或脚本生成摘要。
  3. 生成一个最简单的index.yaml。
  4. 在 prompt 中手动拼接技能内容和用户问题,测试回答效果。
  5. 对比全量投喂和技能包方案的回答质量与 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 从“读过很多书”变成“在需要时准确想起书里最重要的那几页”。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询