扩展开发#
本章介绍如何扩展 book-to-skill 的功能,包括新增格式支持、修改生成行为、使用开发工具,以及理解优雅降级的设计原则。
7.1 新增格式支持#
book-to-skill 的解析器采用模块化设计,每个格式对应一个独立的解析器模块。新增格式支持遵循四步标准化流程,参考 [ARCHITECTURE.md:99-103](file:///d:/spaces/SpecWeave/external/libs/book-to-skill/docs/ARCHITECTURE.md#L99-L103)。
步骤 1:创建解析器模块#
在 book_to_skill/parsers/ 目录下创建 <fmt>.py 模块。解析器必须遵循统一的返回约定:
成功:返回
(text: str, parser_name: str)元组失败:返回
None(表示尝试下一个 fallback 解析器)或抛出异常
参考现有解析器的实现:
[parsers/pdf.py](file:///d:/spaces/SpecWeave/external/libs/book-to-skill/book_to_skill/parsers/pdf.py)
[parsers/epub.py](file:///d:/spaces/SpecWeave/external/libs/book-to-skill/book_to_skill/parsers/epub.py)
[parsers/docx.py](file:///d:/spaces/SpecWeave/external/libs/book-to-skill/book_to_skill/parsers/docx.py)
解析器设计原则:
优先使用第三方库获得最佳提取质量
必须提供 stdlib fallback 以保证零依赖可用性
提取的文本应通过
sanitize.py进行 Unicode 清理异常应向上传播或返回
None触发 fallback 链
步骤 2:注册扩展名#
在 [config.py](file:///d:/spaces/SpecWeave/external/libs/book-to-skill/book_to_skill/config.py) 中注册新格式的文件扩展名:
# 在 config.py 中添加格式集合
NEW_FORMAT_EXTENSIONS = {".ext1", ".ext2"}
# 将扩展名加入 SUPPORTED_EXTENSIONS
SUPPORTED_EXTENSIONS = {
".pdf", ".epub", ".docx", ".rtf",
*TEXT_EXTENSIONS,
*HTML_EXTENSIONS,
*CALIBRE_EBOOK_EXTENSIONS,
*NEW_FORMAT_EXTENSIONS, # 新增
}
# 如有 Python 依赖,添加到 PYTHON_DEPENDENCIES
PYTHON_DEPENDENCIES = {
# ... 现有依赖
"new_lib": "new-pip-package",
}
参考:[config.py:16-34](file:///d:/spaces/SpecWeave/external/libs/book-to-skill/book_to_skill/config.py#L16-L34)
步骤 3:添加依赖探测#
在 [dependencies.py](file:///d:/spaces/SpecWeave/external/libs/book-to-skill/book_to_skill/dependencies.py) 的 DEPENDENCY_GROUPS 列表中添加新格式的依赖探测配置:
DEPENDENCY_GROUPS = [
# ... 现有格式组
{
"label": "New Format Name",
"modules": ["new_lib"], # Python 模块名列表
"any_of_modules": True, # 是否任一模块即可
"any_tool_suffices": False, # 是否任一工具(module+system)即可
"system": [ # 系统命令依赖
("cmd-name", "Pretty Name", "install hint"),
],
"note": "falls back to a stdlib parser if missing", # 用户提示
},
]
同时需要在 prepare_dependencies() 函数中添加对应的依赖安装提示逻辑,参考 [dependencies.py:166-213](file:///d:/spaces/SpecWeave/external/libs/book-to-skill/book_to_skill/dependencies.py#L166-L213)。
步骤 4:集成到提取流程#
在 [utils.py](file:///d:/spaces/SpecWeave/external/libs/book-to-skill/book_to_skill/utils.py) 的 extract_single_file() 函数中添加新格式的分支逻辑:
在文件顶部导入解析器函数
在
extract_single_file()中添加格式判断分支按照「最佳工具优先 → fallback 链」的顺序尝试解析器
处理失败情况并给出明确的错误提示
参考现有 PDF 格式的 fallback 链实现:[utils.py:484-530](file:///d:/spaces/SpecWeave/external/libs/book-to-skill/book_to_skill/utils.py#L484-L530)
7.2 修改生成行为#
生成行为由 [SKILL.md](file:///d:/spaces/SpecWeave/external/libs/book-to-skill/SKILL.md) 定义,这是 agent 遵循的规范文档。修改生成行为需遵循以下原则:
核心原则#
保持精简(lean):SKILL.md 是每次运行都会加载的核心文档,避免不必要的膨胀
证据支持变更:根据 [CONTRIBUTING.md](file:///d:/spaces/SpecWeave/external/libs/book-to-skill/CONTRIBUTING.md),所有修改必须有可测量的证据支持
优先修改现有步骤:优先编辑现有 Step 而非新增 Step
网络新增内容:净新增内容必须有充分理由,并用 benchmark 数据证明收益
证据类型#
修改 SKILL.md 前需要提供以下类型之一的证据:
测试结果:新增或更新的测试用例证明行为正确
Benchmark 数据:使用
tools/discovery_tax.py测量的 token 成本变化Before/After 对比:在真实书籍上运行的效果对比
问题复现:清晰的 bug 复现场景和修复验证
参考:[CONTRIBUTING.md:9-14](file:///d:/spaces/SpecWeave/external/libs/book-to-skill/CONTRIBUTING.md#L9-L14)
修改流程#
确定需要修改的具体 Step 编号
在本地修改 SKILL.md
使用
tools/validate_skill.py验证格式在真实书籍上测试效果
运行完整测试套件(ruff + pytest)
提交 PR 并附上证据
7.3 工具脚本详解#
book-to-skill 提供了一系列开发和验证工具,位于 tools/ 和 scripts/ 目录下。
7.3.1 tools/discovery_tax.py — Discovery Loop Tax 测量#
功能:量化三种策略在回答定向问题时的 token 成本:
context-dump:整本书常驻上下文,每轮重复计费
discovery-loop:实时 PDF 阅读 agent 导航(读 ToC → 拉取章节 → 回溯缺失定义)
book-to-skill:小型常驻 SKILL.md 核心 + 按需加载的预编译章节
核心功能:
使用真实提取的书籍进行测量
支持 tiktoken(cl100k_base)精确计数,或
words/0.75启发式估算报告 best case(ToC + 目标章节)和 loop case(+ 前置章节查定义)
复用提取器的章节检测逻辑,保证计数一致性
用法:
python3 tools/discovery_tax.py --full-text <full_text.txt> \
[--skill-dir <skill_folder>] [--target-chapter N] [--core-tokens 4000]
参考:[tools/discovery_tax.py](file:///d:/spaces/SpecWeave/external/libs/book-to-skill/tools/discovery_tax.py)
7.3.2 tools/validate_skill.py — SKILL.md 宿主规则校验#
功能:检查生成的 SKILL.md 是否符合目标宿主(host)的规则。
支持的 lens(宿主):
claude:Claude Code 规则(默认)copilot:GitHub Copilot CLI 规则amp:Sourcegraph Amp 规则
校验内容:
YAML frontmatter 有效性
name字段:必填、≤64字符、小写字母/数字/连字符description字段:必填、≤1024字符allowed-tools:识别宿主内置工具,检测缺失的 Bash 权限未识别的 frontmatter key(警告)
正文行数 >500 行(软警告)
严重级别:
ERROR:会破坏/降低技能在该宿主上的功能(CI 失败)
WARN:宿主忽略或为软指南(不中断 CI)
用法:
python3 tools/validate_skill.py [--lens claude|copilot|amp] [path/to/SKILL.md]
参考:[tools/validate_skill.py](file:///d:/spaces/SpecWeave/external/libs/book-to-skill/tools/validate_skill.py)
7.3.3 tools/scan_generated_skill.py — 提示注入扫描(Step 9.5)#
功能:对生成的 Skill 进行提示注入和权限越权的安全扫描,这是生成流程中的 Step 9.5。
扫描范围:
SKILL.md(主文件)chapters/*.md(章节文件)glossary.md、patterns.md、cheatsheet.md(辅助文件)
检测规则:
规则 ID |
检测内容 |
|---|---|
|
不可见 Unicode 码点(零宽字符、标签块等) |
|
"ignore previous instructions" 类指令覆盖短语 |
|
"disregard the system" 类系统指令覆盖 |
|
"you are now" 角色重分配短语 |
|
伪造的 system/developer 消息前缀 |
|
|
|
模型聊天模板分隔符(`< |
|
tool-call 控制 token |
|
数据渗出形态(curl/wget/send + 敏感词) |
|
frontmatter 声明或扩大工具权限 |
|
显式启用模型调用 |
安全特性:
结果只报告规则 ID 和文件位置,永远不报告匹配的文本
扫描为建议性质(advisory),规则 intentionally broad 可能误报合法内容
不修改任何文件
用法:
python3 tools/scan_generated_skill.py <generated-skill-dir-or-SKILL.md>
参考:[tools/scan_generated_skill.py](file:///d:/spaces/SpecWeave/external/libs/book-to-skill/tools/scan_generated_skill.py)
7.3.4 scripts/extract.py — 薄入口垫片#
功能:向后兼容的入口点包装器,将调用转发到 book_to_skill.cli。
设计目的:
保持旧调用方式继续工作
处理 Windows 控制台 UTF-8 编码问题(✓/✗ 等符号)
确保项目根目录在
sys.path中,保证模块化包可靠导入
代码结构:
from book_to_skill.cli import main
if __name__ == "__main__":
main()
参考:[scripts/extract.py](file:///d:/spaces/SpecWeave/external/libs/book-to-skill/scripts/extract.py)
7.4 优雅降级设计原则#
优雅降级(Graceful degradation)是 book-to-skill 的核心设计原则之一,参考 [ARCHITECTURE.md:57-58](file:///d:/spaces/SpecWeave/external/libs/book-to-skill/docs/ARCHITECTURE.md#L57-L58)。
核心原则#
每个格式都有 stdlib fallback:
PDF:pdftotext → pypdf → pdfminer(多级 fallback)
EPUB:ebooklib + bs4 → stdlib zipfile 解析器
DOCX:python-docx → stdlib ZIP/XML 解析器
HTML:beautifulsoup4 → stdlib html.parser
RTF:striprtf → 基础正则清理 fallback
例外:MOBI/AZW/AZW3 必须依赖 Calibre(无 stdlib fallback)
一个坏源被跳过而非致命错误:
在多源提取时,单个文件失败不会导致整个流程崩溃
失败的源被记录到 warnings 列表,继续处理其他文件
只有当所有源都失败时才返回错误退出码
参考:[utils.py:642-659](file:///d:/spaces/SpecWeave/external/libs/book-to-skill/book_to_skill/utils.py#L642-L659)
降级策略示例#
以 PDF 提取为例,fallback 链的设计:
Technical 模式:优先使用 Docling(布局感知,支持表格/代码/公式)
Text 模式:
第一选择:pdftotext(poppler-utils,系统工具,质量最佳)
第二选择:pypdf(纯 Python)
第三选择:pdfminer.six(纯 Python)
所有失败:抛出
ExtractionError,给出安装提示
每一级 fallback 失败时都会打印明确的状态信息,用户可以清楚地知道使用了哪个提取器。
参考:[utils.py:484-526](file:///d:/spaces/SpecWeave/external/libs/book-to-skill/book_to_skill/utils.py#L484-L526)
依赖检查与提示#
--check 命令提供完整的依赖状态报告:
哪些可选依赖已安装(✓)
哪些缺失(✗)
每个格式的满意度状态(ready / fallback available / MISSING)
精确的安装命令
参考:[dependencies.py:216-289](file:///d:/spaces/SpecWeave/external/libs/book-to-skill/book_to_skill/dependencies.py#L216-L289)
事实来源:本章节基于以下事实编号 F-039, F-040, F-041