HonoSumi

ebook-knowledge-extractor

从电子书中提取结构化知识的完整工作流。 支持 PDF / EPUB / MOBI / TXT / MD 等多种电子书格式。 特点:(1) 分块处理避免上下文爆炸,绝不直接读取全书; (2) 每块串行通过 subagent 提取名词,结合互联网检索给出解释; (3) 最终汇总到 SQLite 数据库。 当用户需要"提取电子书知识"、"做读书笔记"、"整理书中人物/事件"、 "归档书中概念"、"结构化电子书内容"时务必使用此 skill。 也适用于用户想从书中提取具有民族特色或地方特色的文化元素时。

HonoSumi 1 Updated 1mo ago

Resources

3
GitHub

Install

npx skillscat add honosumi/i-desire-more-knowledge-skill

Install via the SkillsCat registry.

SKILL.md

电子书知识提取工作流

核心原则

  1. 断点续传 — 每次启动必须先检测断点(扫描 {book_name}_*.json 文件),有已完成块则从断点继续,无断点才全新开始。严禁不检查直接从头处理。
  2. 禁止直接读取整本电子书 — 对电子书的访问仅限于读取文件名、目录列表和分块后的文本块
  3. 分块处理 — 每个文本块约 5000 字符,块间 100 字符重叠,保证上下文连贯但不溢出
  4. 串行处理 — 每个文本块依次处理,禁止并行启动 subagent,确保质量
  5. 知识型条目优先 — 提取的是"知识点"而非"名词"。判断标准:一个不了解背景的读者是否需要查资料才能理解?如果是,才提取。主角名字、普通日常物品、通用概念一律不收录
  6. 纯词汇输出 — 关键词文件只允许包含纯词汇(每行一个),禁止写入类别名、分组标题、分隔线等任何非词汇内容
  7. 互联网辅助 — 对每个条目检索互联网,结合书中内容进行解释,不做纯虚构
  8. YAML 四字段约束 — 每个知识条目严格 4 字段:名词解释书中原文网络来源。禁止出现任何额外字段。
  9. subagent 静默模式 — subagent 只产出文件,禁止在最终消息中输出任何总结、表格、分类、类别名或分析。最多一句话确认完成。

前置条件

  • Python 3.7+
  • 四个固化脚本在 scripts/ 目录下:
    • chunk_ebook.py — 电子书分段
    • yaml_to_json.py — 将 subagent 输出的 YAML 转为标准 JSON(避免引号问题)
    • manage_keywords.py — 管理 already_searched.txt 关键词去重列表(读取/追加)
    • merge_to_sqlite.py — 合并 JSON 到 SQLite

详细工作步骤

步骤 0:创建/检查工作目录

检查 {书名}_tmp/ 目录是否存在。若不存在则创建:

mkdir -p "{书名}_tmp"

步骤 1:检测断点(先于分片)

这是首要步骤。 每次启动必须先检测断点,根据已有数据决定后续走向。

1a. 检查是否已有分片文本

检查 {书名}_tmp/ 目录下是否已有 .txt 分片文件:

ls "{书名}_tmp/"*_001.txt 2>/dev/null && echo "分片已存在" || echo "需要分片"

1b. 检查是否已有分片计划

检查 {书名}_tmp/_plan.json 是否存在。

1c. 检测已完成处理结果

若分片存在,扫描 {tmp_dir}/ 下以 {book_name}_ 开头、.json 结尾的文件:

ls "{tmp_dir}"/{book_name}_*.json 2>/dev/null | sed 's/.*_//' | sed 's/\.json//' | sort -n

1d. 根据检测结果决定走向

情况 分片 txt 文件 _plan.json JSON 结果 处理方式
全新处理 不存在 不存在 不存在 → 去步骤 2(分片),完成后继续步骤 4
部分完成 存在 存在 部分存在 → 去步骤 4,从断点继续
全部完成 存在 存在 全部存在 → 直接跳到步骤 5(合并)

例如:

  • 全新:检测到无已有分片,将进行分片 → 共 202 个文本块待处理
  • 断点:检测到已有 15/42 块完成,将从第 16 块继续
  • 全部完成:检测到所有 42 块已完成,跳过提取直接合并

步骤 2:分段电子书(仅在无分片时执行)

若步骤 1 检测到无已有分片,使用固化脚本 scripts/chunk_ebook.py 将电子书分割为多个重叠的小文本块。

python scripts/chunk_ebook.py <电子书路径> --chunk-size 5000

脚本会自动:

  1. 检测文件格式并提取全文
  2. 自动安装所需 Python 依赖
  3. 分割为约 5000 字符的文本块(块间重叠约 100 字符)
  4. 将文本块保存到 {书名}_tmp/{书名}_001.txt{书名}_002.txt… 中
  5. 生成 _plan.json 处理计划文件

务必使用此脚本执行分段,不要手动分段。

如果脚本执行成功,会输出类似:

[4/4] 写入处理计划: _plan.json
============================================================
完成! 所有文本块已保存到: 百年孤独_tmp
计划列表: 共 42 个文本块待处理
============================================================

步骤 3(可选):初始化关键词去重列表

如果 {书名}_tmp/already_searched.txt 不存在,新建空文件:

touch "{书名}_tmp/already_searched.txt"

文件由 manage_keywords.py filter 命令自动维护,无需手动编辑。

步骤 4:串行提取每个文本块的知识(subagent 隔离处理)

这是核心步骤。心态上要放慢:无论有 5 个块还是 500 个块,都一个接一个地处理,不急不躁。
我们最不缺的就是时间,最不需要的就是效率。提取质量远比速度重要。

设计思路

每个文本块的全部处理委托给一个独立的 subagent,主流程只负责串行调度和进度汇报。subagent 内部完成:

  1. 读取文本块 → 提取关键词(无 WebSearch)
  2. 运行 manage_keywords.py filter 去重
  3. 对新关键词做 WebSearch + 撰写 YAML
  4. 运行 yaml_to_json.py 转换

整个 pipeline 在 subagent 上下文中完成,主流程不接触每块的关键词文件、YAML、JSON 等中间产物细节,极大节省主上下文窗口。

处理流程

_plan.json 中的每个文本块(按 seq 升序),串行执行:

  1. 跳过已完成 — 若 {tmp_dir}/{book_name}_{seq}.json 已存在,跳过不处理

  2. 告知用户[003/042] 正在处理 百年孤独_003.txt……

  3. 启动 subagent 处理该块 — 使用 Agent 工具(prompt 见下方),等待其完成后再启动下一个

  4. 汇报进度(精简模式) — subagent 返回后,只报告一行:

    • [003/042] 百年孤独_003.txt → 5 个关键词,累计 23 个
    • 不要复述 subagent 输出的任何表格、分类、总结
    • subagent 如果输出了多余内容,忽略即可,不转发给用户
  5. 若失败 — 重试该块,连续 3 次失败则跳过并在最终报告注明

subagent prompt

你是一个电子书知识提取助手。请完整处理一个文本块的知识提取 pipeline。

参数(替换实际值):
- 书名: {book_name}
- 文本块序号: {seq}/{total}
- 文本块文件: {chunk_filepath}
- 工作目录: {tmp_dir}
- 去重列表: {tmp_dir}/already_searched.txt
- 关键词输出文件: {tmp_dir}/keywords_{seq}.txt
- YAML 输出文件: {tmp_dir}/{book_name}_{seq}.yaml

=== 步骤 1:提取关键词 ===

使用 Read 工具阅读文本块文件,提取其中的**知识型条目**,将关键词列表写入 {tmp_dir}/keywords_{seq}.txt(使用 Write 工具)。

判断标准:**"一个不了解背景的读者,看到这个词会需要查资料才能理解吗?"**
- 需要 → 知识点,提取(如"扎染"、"傩戏"、"土楼")
- 不需要,仅作为叙事要素 → 不提取(如主角名"翠翠")

筛选类别(仅用于辅助判断,**禁止写入输出文件**):
- 物件·工艺 — 有民族/地方特色的物品、手工艺品、食物等(排除普通日用品)
- 习俗·仪式 — 有文化背景的风俗、节日、祭祀、禁忌
- 概念·观念 — 特有的思想、信仰、民间说法
- 事件·典故 — 有文化意义的历史事件、传说
- 人物 — 仅限真实历史人物或文化符号人物(排除书中叙事角色)
- 地点 — 仅限有历史文化意义的地点(排除虚构场景名)

关键约束 — 输出文件必须**纯词汇,不含任何类别标题**:
✅ 正确格式(只有词汇,一行一个):
  扎染
  傩戏
  土楼

❌ 错误格式(禁止包含任何类别名、冒号、分隔线):
  物件·工艺
  扎染           ← 类别名不应出现

重要要求:
- 输出文件中**禁止出现任何类别名**,只能有纯词汇
- 无需分类、无需分组、无需标题、无需序号、无需分隔线
- 不要使用 WebSearch,不要写解释
- 按实提取,不设上下限

=== 步骤 2:去重过滤 ===

运行 Bash 命令对关键词去重:

```bash
python scripts/manage_keywords.py filter "{tmp_dir}/already_searched.txt" --from-file "{tmp_dir}/keywords_{seq}.txt" --output "{tmp_dir}/filtered_{seq}.txt"

将输出(新关键词列表)保存到变量 NEW_KEYWORDS。

如果过滤后无新关键词(输出为空),必须将空 JSON 数组 [] 写入 {book_name}_{seq}.json 作为完成标记再结束,否则系统扫描不到该文件会认为该块未处理而重复执行:

echo '[]' > "{tmp_dir}/{book_name}_{seq}.json"

写完后立即结束任务(跳过步骤 3 和 4),不要做任何多余操作。

=== 步骤 3:检索并撰写 YAML ===

对 NEW_KEYWORDS 中的每个关键词,使用 WebSearch 进行互联网检索,结合书中原文撰写综合解释。

  • 用 Read 工具再次阅读文本块,找到每个关键词对应的原文句子
  • 使用 WebSearch 检索每个关键词
  • 输出 YAML 到 {tmp_dir}/{book_name}_{seq}.yaml

YAML 格式:

- 名词: White Walkers
  解释: |
    《冰与火之歌》中的神秘生物,又称异鬼,是长城以北的传说中存在。他们是一种寒冷而邪恶的人形生物,拥有将死者复活为尸鬼的能力。
  书中原文: |
    He had seen the white walkers in the woods beyond the Wall.
  网络来源: |
    https://iceandfire.fandom.com/wiki/White_Walkers

YAML 书写规则:

  • 每条记录以 - 名词: 开头
  • 字段缩进 2 空格
  • 多行文本用 : | 换行,内容缩进 4 空格
  • 不需要引号

重要 — 语言要求:

  • 名词 字段:保留原文语言(原文是英文就保持英文,原文是日文就保持日文,以此类推)
  • 解释 字段:始终使用中文撰写
  • 书中原文 字段:保留书中原始文本,不做翻译
  • 网络来源 字段:保留原始 URL

其他重要要求:

  • 只处理 NEW_KEYWORDS 中的关键词
  • "书中原文"必须是书中出现的完整可读的句子
  • 检索不到则注明"未检索到网络资料"
  • 禁止编造信息

=== 步骤 4:强制 YAML→JSON 转换 ===

python scripts/yaml_to_json.py "{tmp_dir}/{book_name}_{seq}.yaml"

验证输出的 JSON 文件存在。若失败则重试步骤 3 和 4。

=== 【验收】步骤 5:字段合规检查 ===

用 Read 工具读取生成的 JSON 文件,逐条检查:

# 在 subagent 中用 Read 检查后,心理验证:
# 每个 dict 的 keys 必须严格等于 {"名词", "解释", "书中原文", "网络来源"}
# 不允许有第 5 个字段,不允许字段名错误,不允许空值

如果任何条目存在以下问题,必须回到步骤 3 重新生成 YAML

  • 出现第 5 个额外字段
  • 字段名错误(如"词条"代替"名词")
  • 核心字段为空
  • 格式不是有效的 YAML/JSON

验收通过后,只输出一句确认(例:"块 42/329 完成,3 个关键词"),禁止输出任何总结、表格、分类统计、类别名、markdown 表格、分隔线。拒绝输出表格式的任何内容。


#### 串行约束

- **必须串行,禁止并行** — 每次只启动一个 subagent,阻塞等待其完成后才启动下一个
- **慢就是快** — 每块可能需要数分钟,这是正常的
- subagent 是独立上下文,其内部细节不会污染主流程上下文窗口
- 若某块 subagent 连续失败 3 次,跳过该块,在最终报告中注明

### 步骤 5:合并到 SQLite

所有文本块处理完毕后,使用固化脚本 `scripts/merge_to_sqlite.py` 合并所有 JSON 到 SQLite 数据库。

```bash
python scripts/merge_to_sqlite.py <json_dir>
# 例如: python scripts/merge_to_sqlite.py 百年孤独_tmp

其中 <json_dir> 就是步骤 0/2 中创建/使用的 {书名}_tmp/ 目录。

脚本会自动:

  1. 扫描目录下的所有 *.json 文件(排除 _ 开头的)
  2. 按名词去重(不区分大小写),合并解释、原文和来源
  3. 写入 SQLite 数据库,文件名为 {书名}.db
  4. 输出统计信息

脚本执行完成后,向用户汇报最终统计:

📊 处理完成统计
────────────────────────────────
总文本块数:    42
总原始条目:    587
去重后条目:    423
数据库文件:    百年孤独.db
────────────────────────────────

输出说明

SQLite 数据库结构

库文件 {书名}.db 包含两个表:

nouns 表 — 知识条目:

列名 说明
noun 名词(主键,不区分大小写去重)
explanation 综合解释
original_text 书中原文片段
source_urls 网络来源 URL
created_at 创建时间
updated_at 更新时间

metadata 表 — 处理元信息:

列名 说明
key 元信息键名
value 元信息值

查询示例:

SELECT noun, length(explanation) as expl_len FROM nouns ORDER BY expl_len DESC LIMIT 10;
SELECT noun, source_urls FROM nouns WHERE source_urls != '' LIMIT 10;

错误处理

subagent 处理失败

如果某个文本块的 subagent 处理失败(超时、格式错误等),重试该块而不是跳到下一个。如果连续 3 次失败,跳过该块并在最终报告中注明。重试时 already_searched.txt 中的关键词不会被重复搜索,不会浪费 token。

分段脚本失败

如果 chunk_ebook.py 失败,先检查文件格式是否支持。对于不支持的格式(如 MOBI 且没有 calibre),提示用户转换格式。

合并脚本失败

如果 merge_to_sqlite.py 失败,检查 JSON 文件是否完整。可以手动修复损坏的 JSON 后重试。


使用范例

用户说:"帮我提取《百年孤独》这本书的知识点"

你会回答好的,然后执行:

  1. 检查 百年孤独_tmp/ 目录是否存在,检测断点 → 判断是否为全新处理
  2. 若为全新,运行 python scripts/chunk_ebook.py 百年孤独.epub 分片
  3. 确保 百年孤独_tmp/already_searched.txt 存在
  4. 读取 _plan.json 列出文本块数,告知用户预计时间
  5. 串行启动 subagent(从断点处开始),每个处理一个文本块的完整 pipeline
  6. 每块完成后简短汇报一次进度
  7. 全部完成后运行 python scripts/merge_to_sqlite.py 百年孤独_tmp
  8. 展示最终统计