书籍转技能转换器
通过提取结构——而非生成摘要——将书面知识转化为可操作的智能体技能。
理念
书籍中蕴含着结晶化的专业知识:框架、原则和技术,这些可能需要数年时间才能形成。本技能将这些知识提取为一种格式,使 GitHub Copilot CLI、Amp、Claude Code、Hermes Agent 或其他兼容的智能体能够反复利用。
提取结构,而非摘要。 技能不是读书报告。它是一个工具包,包含:
- 具名框架(具有明确应用场景的心智模型)
- 可操作的原则(指导决策的规则)
- 技术(逐步执行的方法)
- 反模式(应避免的内容及其原因)
- 语态校准(作者的思考与沟通方式)
保留作者的精确性。 框架通常有特定的命名原因。“5个为什么”不能与“多问几次为什么”互换。请捕获确切的表述。
适当分层。 简单的书籍 → 简单的技能。包含 10 个以上框架的复杂书籍 → 附带参考文件和按需加载章节的技能。
操作模式
提供四种路径。根据用户的请求选择:
1. 完整转换(默认)
触发条件: 用户提供一个或多个文档/目录/通配符路径,且没有特殊指令 操作: 执行以下所有步骤(步骤 0–9) 输出: 完整的技能,包含 SKILL.md、chapters/、术语表、模式库、速查表
2. 仅分析
触发条件: 用户说“分析”、“仅提取”或“我想在生成前预览” 操作: 执行步骤 0–3,然后生成结构化提取报告(发现的框架、原则、技术)。停止——不要生成技能文件。 输出: 供用户审查的分析报告
3. 基于先前分析生成
触发条件: 用户有现有的分析笔记或之前运行过仅分析模式 操作: 跳过步骤 0–3,使用提供的分析作为输入,执行步骤 4–9 输出: 根据提供的分析生成的技能文件
4. 更新/合并(现有技能)
触发条件: 用户提供一个或多个新的源路径,并指示要更新现有技能(通过指向现有技能文件夹,提供 SKILLS_HOME 中已存在的技能短横线名称,或明确请求更新)
操作: 执行步骤 0(范围外检查)、步骤 1(验证输入)、步骤 1.5(识别书籍类型)和步骤 2(提取新文件)。然后跳至步骤 5(识别/检测现有技能路径)并运行 更新/合并工作流,将新内容合并到现有的技能文件中。
输出: 更新后的现有技能,包含新的/修订的章节摘要以及合并后的索引/术语表。
技能位置
此转换器可以从多个技能系统运行。在查找此转换器的辅助脚本或写入生成的书籍技能时,优先采用以下顺序的位置:
- GitHub Copilot CLI 个人技能:
~/.copilot/skills/ - 跨智能体个人技能(Copilot, Amp, Codex):
~/.agents/skills/ - Claude Code 个人技能:
~/.claude/skills/ - 项目本地 Copilot 技能:
.github/skills/ - 项目本地 Claude 技能:
.claude/skills/ - 项目本地 Amp / Copilot 技能:
.agents/skills/ - Amp 全局技能:
~/.config/agents/skills/ - Amp 遗留全局技能:
~/.config/amp/skills/ - Hermes Agent 个人技能:
$HERMES_HOME/skills/(默认~/.hermes/skills/) - Hermes Agent 项目技能:
.hermes/skills/或.agents/skills/
对于生成的书籍技能,优先使用用户级别的跨智能体根目录 ~/.agents/skills/——一个物理副本即可服务于所有受支持的宿主。Copilot CLI 和 Amp 原生支持它;Claude Code 需要从 ~/.claude/skills/<技能名称> 创建一个符号链接(在步骤 10 中创建,有关规则请参见步骤 5)。仅当用户要求时,才选择宿主私有或项目本地根目录。
步骤 0 — 范围外检查
如果没有提供任何参数,则停止并响应:
"book-to-skill 需要一个受支持的文档路径、文件夹或通配符模式。用法:
book-to-skill <文档路径或目录或通配符>... [技能名称-短横线]"
在整个工作流程中:
- 识别输入路径和可选的技能短横线名称。
- 如果最后一个参数不是文件、文件夹或存在或匹配任何文件的通配符,并且看起来像是一个技能短横线名称(例如小写字母、连字符、字母数字),则将其视为
SKILL_NAME。 - 将所有其他参数视为
INPUT_PATHS列表。 - 如果任何输入路径是现有的技能目录(包含
SKILL.md和chapters/子文件夹),或者SKILL_NAME与SKILLS_HOME中现有的技能短横线名称匹配,则将此运行标记为 更新/合并 操作(模式 4)。
步骤 1 — 验证输入
验证 INPUT_PATHS 中是否至少有一个受支持的文件、目录或通配符模式。
对于目录和通配符,展开它们以查找匹配的受支持文件(.pdf, .epub, .docx, .txt, .md, .markdown, .rst, .adoc, .html, .htm, .rtf, .mobi, .azw, .azw3)。
如果未找到受支持的文件,则停止并显示清晰的错误消息。
步骤 1.5 — 识别内容类型
在提取之前,询问用户:
"这些源内容是什么类型?这有助于我选择最佳的提取方法。
- 技术类 — 包含代码块、表格、公式、图表(例如编程书籍、学术论文、架构指南)
- 文本类 — 主要是散文,很少有或没有表格/代码(例如管理、生产力、叙事性非虚构类)
- 不确定 — 我将使用快速方法,如果质量看起来有限,我会警告你"
将答案存储为 BOOK_TYPE:
- 选项 1 →
BOOK_TYPE=technical - 选项 2 →
BOOK_TYPE=text - 选项 3 →
BOOK_TYPE=text
如果 BOOK_TYPE=technical,在继续之前告知用户:
"📐 技术模式已选择——使用 Docling 进行结构化感知提取(表格、代码块、公式保留为 markdown)。每页大约需要 1.5 秒,因此对于较长的源内容,预计需要几分钟。现在开始..."
如果 BOOK_TYPE=text,告知:
"📄 文本模式已选择——对每种文件类型使用最快的合适提取器。纯文本/Markdown/HTML 通常在几秒钟内准备好;PDF 在可用时使用 pdftotext。"
步骤 2 — 从源文档中提取文本
运行提取脚本,传递输入路径:
SCRIPT_PATH=""
HERMES_HOME_RESOLVED="${HERMES_HOME:-$HOME/.hermes}"
PROJECT_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || true)"
HERMES_PROJECT_TRUSTED=false
if [ -n "$PROJECT_ROOT" ] && [ "${HERMES_AGENT:-}" = true ] && \
command -v hermes >/dev/null 2>&1 && \
command -v python3 >/dev/null 2>&1 && \
hermes config get skills.trusted_project_dirs --json 2>/dev/null | PROJECT_ROOT="$PROJECT_ROOT" python3 -c 'import json, os, pathlib, sys; root=pathlib.Path(os.environ["PROJECT_ROOT"]).resolve(); sys.exit(not any(pathlib.Path(p).expanduser().resolve() == root for p in json.load(sys.stdin)))' 2>/dev/null
then
HERMES_PROJECT_TRUSTED=true
fi
CANDIDATES=(
"$HOME/.copilot/skills/book-to-skill/scripts/extract.py"
"$HOME/.agents/skills/book-to-skill/scripts/extract.py"
"$HOME/.claude/skills/book-to-skill/scripts/extract.py"
"$HERMES_HOME_RESOLVED/skills/book-to-skill/scripts/extract.py"
"$HERMES_HOME_RESOLVED"/skills/*/book-to-skill/scripts/extract.py
)
if [ "${HERMES_AGENT:-}" != true ]; then
CANDIDATES+=(
".github/skills/book-to-skill/scripts/extract.py"
".claude/skills/book-to-skill/scripts/extract.py"
".agents/skills/book-to-skill/scripts/extract.py"
)
fi
CANDIDATES+=(
"$HOME/.config/agents/skills/book-to-skill/scripts/extract.py"
"$HOME/.config/amp/skills/book-to-skill/scripts/extract.py"
)
if [ "$HERMES_PROJECT_TRUSTED" = true ]; then
CANDIDATES=(
"$PROJECT_ROOT/.hermes/skills/book-to-skill/scripts/extract.py"
"$PROJECT_ROOT/.hermes/skills"/*/book-to-skill/scripts/extract.py
"$PROJECT_ROOT/.agents/skills/book-to-skill/scripts/extract.py"
"$PROJECT_ROOT/.agents/skills"/*/book-to-skill/scripts/extract.py
"${CANDIDATES[@]}"
)
fi
for candidate in "${CANDIDATES[@]}"
do
if [ -f "$candidate" ]; then
SCRIPT_PATH="$candidate"
break
fi
done
if [ -z "$SCRIPT_PATH" ]; then
echo "找不到 book-to-skill 的 scripts/extract.py" >&2
exit 1
fi
PYTHON_BIN="${PYTHON_BIN:-python3}"
if ! command -v "$PYTHON_BIN" >/dev/null 2>&1; then
PYTHON_BIN="python"
fi
"$PYTHON_BIN" "$SCRIPT_PATH" $INPUT_PATHS --mode <BOOK_TYPE> --install-missing ask
在提取之前,脚本会检查检测到的格式所需的可选 Python 包。如果更好的提取器缺失,它会提示用户可用的降级方案。非交互式会话默认使用降级方案,除非安装模式明确设为 yes。
提示——预处理环境: 运行 "$PYTHON_BIN" "$SCRIPT_PATH" --check 会打印一份按格式划分的报告,说明安装了哪些提取器以及安装缺失项的具体命令,无需处理任何文件。这在用户报告设置或质量问题时很有用。
这会创建一个每次运行的工作目录——默认是 <tempdir>/book_skill_work-<pid>/,或者直接使用您在 BOOK_SKILL_WORKDIR 中设置的路径——包含:
full_text.txt— 所有源的合并提取文本,并带有清晰的视觉分隔边界。metadata.json— 总体合并大小、字数、页数、词元数、丢弃的 EPUB 图片数量、解析后的workdir,以及一个包含各个已处理sources的详细列表。
运行完成后会打印所有三个路径(Workdir ->, Text ->, Meta ->)。从该输出中获取路径(或从 metadata.json 自身的 workdir 字段获取),而不是假设一个固定位置——目录名称因运行而异,这样一台机器上的并发提取不会互相覆盖结果。
读取该次运行的 metadata.json 以检查结果。
在生成任何内容之前,务必确认提取的是您要求的文档:检查 metadata.json 中的 filename / source_file,或 full_text.txt 第一行的 SOURCE: 头。如果您正在等待后台运行,请等待其特定的工作目录——轮询共享路径可能会获取到不同运行的结果。
步骤 2.5 — 前置成本估算
读取本次运行的 metadata.json(提取输出中的 Meta -> 路径),并在进行任何生成之前向用户呈现估算:
📖 检测到的源:<total_sources> 个源
<从 sources 元数据列表中列出每个源文件名和格式>
<如果 images_dropped > 5:警告有 N 个源图片未被读取>
📄 合并页数/章节数:~<N> | 字数:~<N> | 总词元数:~<N>K
💰 预估词元成本(完整转换 / 更新):
输入(读取 + 提示):~<N>K 词元
输出(生成/更新的技能文件):~<N>K 词元
总计: ~<N>K 词元
成本:将以上词元数乘以您模型当前的输入/输出每百万词元费率(价格和模型名称变化频繁——
请勿硬编码;引用今天的费率并将其标注为估算值)。
⏱ 预计时间:~<N> 分钟
📁 待生成/更新的文件:
SKILL.md + 章节文件 + 术语表 + 模式库 + 速查表
➡ 继续完整转换 / 更新?(或输入 "analyze only" 以先预览)
如何估算:
- 输入词元 ≈ 元数据中的
estimated_tokens× 1.3(每章节通过的提示开销) - 输出词元 ≈ 章节数 × 每章节预算 + 4,000(SKILL.md) + 4,500(术语表 + 模式库 + 速查表)
- 根据
BOOK_TYPE确定的每章节预算中点(深度在步骤 4 中决定,可以增加):text≈ 1,000,technical≈ 1,800。如果用户已经指示了“仅参考”或“深度研究”,请使用步骤 7 矩阵中相应的行。
- 根据
- 成本:报告词元数并乘以用户当前的每百万词元输入/输出费率。不要硬编码美元数字——模型名称和价格会变化;如果您显示一个,请将其标记为估算值并注明日期。
等待用户确认后再继续。如果他们说 "analyze only",则切换到模式 2。
步骤 2.6 — 针对大型书籍(> 50k 词元)的 REPL 式访问
灵感来源于递归语言模型(RLM)范式:将 full_text.txt 视为可查询的语料库,而不是一次性读取。将整个文件加载到上下文中会消耗您稍后生成所需的预算。
对于超过约 50k 词元的书籍,优先使用程序化探测而非无界的 Read(full_text.txt):
# 在任何 Read 之前进行大小检查
wc -w "$FULL_TEXT_PATH"
# 在不加载整个文件的情况下查找章节偏移量
grep -n -E "^\s*(Chapter|CHAPTER)\s+[0-9]+" "$FULL_TEXT_PATH" | head -40
# 仅提取您需要的章节(包含起始行和结束行)
sed -n '<start>,<end>p' "$FULL_TEXT_PATH"
# 在声称 SKILL.md 中包含某个框架之前,先验证它是否真的被提及
grep -c -i "westrum\|dora" "$FULL_TEXT_PATH"
# 带偏移量/限制的目标读取避免了转储整个文件
# Read(file_path=full_text.txt, offset=<line>, limit=<lines>)
将这种方法用于步骤 3(结构分析)、步骤 7(逐章节摘要)和步骤 8(术语表/模式提取)。对于小于 50k 词元的书籍,单次 Read 就足够了。
为什么这很重要:一本 200 页的书大约有 75k 词元。每章重新读取一次(28 次传递)会...