Back to skills
extension
Category: OtherNo API key required

Dochub

专业文档知识库管理技能。将 .docx/.xlsx 原始文档编译为结构化 Markdown 知识库,基于 Andrej Karpathy 三层架构方法论(raw -> wiki -> schema)。支持初始化、增量更新、渐进式检索问答和知识健康检查四大操作。触发场景:用户初始化文档知识库、消化新文档、搜索文档内...

personAuthor: longjf25hubclawhub

dochub — 文档知识库管理技能

基于 Andrej Karpathy LLM Wiki 方法论,将原始办公文档编译为结构化、可检索、可生长的 Markdown 知识库。

核心架构

采用 Karpathy 三层架构(详细原理见 references/karpathy-methodology.md):

KNOWLEDGE_BASE_ROOT/               # 知识库根目录(由用户指定,如 C:\Users\xx\Documents\工作文档)
├── raw/                           # Layer 1: 不可变原始文档
│   └── {category}/{subdir}/*.docx, *.xlsx
├── wiki/                          # Layer 2: LLM 生成与维护的知识层
│   ├── _index.md                  #   主编排索引(渐进式披露 L1)
│   ├── _log.md                    #   仅追加操作日志
│   ├── _overview.md               #   知识库概况与统计
│   ├── sources/                   #   源文档摘要(markitdown 转换产物)
│   │   └── {category}/{subdir}/*.md
│   ├── concepts/                  #   概念页(LLM 生成)
│   ├── entities/                  #   实体页(LLM 生成)
│   └── comparisons/               #   对比分析页(LLM 生成)
├── update/                        # 增量更新投放区
├── _schema.md                     # Layer 3: dochub 治理规则
└── _dochub_knowledge_base.md      # 友好概览(向后兼容旧版)

三层架构要点

| 层 | 目录 | 角色 | 可变性 | |----|------|------|--------| | 原始层 | raw/ | 源文档仓库,所有知识的真相来源 | 不可变 — LLM 只读不写 | | 知识层 | wiki/ | LLM 生成的结构化 Markdown | 完全由 LLM 维护 | | Schema 层 | _schema.md | 治理规则、模板、工作流定义 | 人与 LLM 共同迭代 |

文档格式支持

| 格式 | 状态 | 说明 | |------|------|------| | .docx | 支持 | Word 现代格式,使用 python-docx 转换 | | .xlsx | 支持 | Excel 现代格式,使用 openpyxl 转换 | | .doc / .xls / .pdf / .pptx / 其他 | 不支持 | 跳过转换,但建立索引(可定位 raw/ 原文) |

四大核心操作

操作 1: 初始化 (init)

将工作目录中原有的原始文档转化为完整知识库。

触发方式: 用户在 KNOWLEDGE_BASE_ROOT 下运行初始化,或明确说「初始化知识库」「dochub init」。

完整流程:

[1/7] 安全确认 → [2/7] 移动原始文档到 raw/ → [3/7] 文件名规范化 → [4/7] 检测不支持格式 → [5/7] MD转换 → [6/7] 生成知识层 → [7/7] 创建Schema

[1/7] 安全确认

  • 询问用户:「是否已确认所有文档不含敏感个人信息、机密数据?(y/n)」
  • 必须获得明确确认后才能继续。 未经确认不允许进入下一步。
  • 如果用户是首次使用,先确认 KNOWLEDGE_BASE_ROOT 目录路径。如果用户未指定,询问用户目标目录。

[2/7] 移动原始文档到 raw/

  • 将 KNOWLEDGE_BASE_ROOT 下所有文件(除已有 raw/、wiki/、update/ 和 _schema.md 外)移动到 raw/ 目录
  • 保持原始目录结构,按现有分类子目录组织
  • 同时排除 .fnsync_temp_dir 等临时目录
  • 非 .docx/.xlsx 文件一并移动(将在步骤 4 处理)

[3/7] 文件名规范化

raw/ 下所有文件执行文件名规范化:

  • 保留:中文、英文、数字、中横线 -
  • 替换:其他字符替换为 -
  • 合并连续多个 - 为单个 -
  • 去除首尾 -

[4/7] 检测不支持格式

  • 扫描 raw/ 下所有文件
  • 识别非 .docx / .xlsx 文件(如 .pptx.pdf.doc.xls.txt.jpg
  • 以表格形式列出跳过的文件清单
  • 输出:「共发现 N 个不支持格式文件,将被跳过(不删除,仅不转换)。是否继续?(y/n)」

[5/7] MD 文档转换

raw/ 下所有 .docx 和 .xlsx 转换为 Markdown,输出到 wiki/sources/,保持相同目录结构。

转换工具选择:

由于 markitdown 的 extra dependencies 在部分环境下解析不稳定,优先使用原生库

| 格式 | 工具 | 方法 | |------|------|------| | .docx | python-docx | 提取段落(Heading 样式 -> # 标题)+ 提取表格(-> Markdown 表格) | | .xlsx | openpyxl | 遍历 Sheet,每 Sheet 一个 ## 标题 + Markdown 表格 |

如原生方案失败,可回退尝试 markitdown[all]

Python 路径: 始终使用 C:/Users/skya2/.workbuddy/binaries/python/envs/default/Scripts/python.exe 如需安装依赖:pip install python-docx openpyxl

写脚本执行: 中文文件名在 here-doc 中可能编码异常,将转换脚本写入临时 .py 文件后执行,完成后删除临时脚本。

转换规则:

  • 输入:raw/{category}/{subdir}/file.docx
  • 输出:wiki/sources/{category}/{subdir}/file.md
  • 转换前检查目标文件是否已存在
    • 首次存在时:询问「跳过 / 覆盖 / 全部跳过 / 全部覆盖」
    • 记录用户选择,后续同批处理自动应用
  • 转换结束后输出统计:「成功 X 个,失败 Y 个,跳过 Z 个」
  • 对于超过 50MB 的 xlsx 文件,使用 read_only=True, data_only=True 参数避免内存溢出

[6/7] 生成知识层

生成 wiki/ 下的核心文件:

6a. 生成 wiki/sources/ 下的源文档摘要页

对每个转换后的 MD 文件,在文件头部添加 YAML frontmatter:

---
title: {文档标题,从原始文件名推导}
type: source-summary
sources:
  - raw/{category}/{subdir}/{filename}.docx
domain: {从目录结构推导领域}
tags: [{从内容提取 3-5 个关键词}]
created: {转换日期}
updated: {转换日期}
confidence: high
---

6b. 生成 wiki/_overview.md(知识库概览)

---
title: 知识库概览
type: overview
updated: {日期}
---

## 文档统计
- 总文档数: N
- 总大小: X MB
- 分类数: N
- 最后更新: {日期}

## 分类目录树
(可视化 ASCII 树状结构)

## 高频关键词标签云
(按频率排列的关键词列表)

## 文档索引
(按分类组织的完整文件清单,每项包含文件名、一句话摘要、标签)

6c. 生成 wiki/_index.md(主编排索引 — Karpathy 核心)

这是 LLM 检索的入口点,采用两级索引结构:

---
title: 知识库索引
type: index
updated: {日期}
---

# 知识库索引

> **检索优先级:** 先查 MD 文档(可全文检索),无结果时再查原始文档(仅索引)。

## 分类导航

### {分类1}

#### MD 文档(可全文检索)
- [[{path}.md]]  {文档名}
...

#### 原始文档(仅索引,不可搜索内容)
- [{格式}] `raw/{path}`  {文档名}
...

### {分类2}
...

## 文档统计
- 原始文档: N 个 (X MB)
- MD 可检索: N 个
- 原始仅索引: N 个
- 分类: N 个
- 初始化: YYYY-MM-DD | 更新: YYYY-MM-DD

索引规则:

  • 每个分类下分两层,MD 文档在上(优先),原始文档在下(备用)
  • 不支持格式文件不跳过——全部纳入原始文档索引层
  • 原始文档以 [格式] 标签标注(如 [PPTX], [PDF], [TXT], [JPG], [DOC], [XLS]
  • 顶部添加检索优先级提示语

6d. 初始化 wiki/_log.md

---
title: 操作日志
type: log
created: {日期}
---

## [{日期}] init | 知识库初始化
- 操作: 初始化知识库
- 文档总数: N
- 成功转换: X
- 跳过: Z (不支持格式)

[7/7] 创建 _schema.md

在 KNOWLEDGE_BASE_ROOT 下创建治理规则文件。

参考 references/entity-types.md 中的模板定义,生成适用于当前文档领域的 schema 文件。内容包括:

  • 项目结构定义
  • 页面类型与命名约定
  • YAML frontmatter 规范
  • 四大操作工作流
  • 领域标签体系

操作 2: 增量更新 (update)

将新文档放入 update/ 目录后运行。

触发方式: 用户说「dochub update」「增量更新」「有新文档」或明确指向 update/ 目录。

完整流程:

[1/6] 安全确认 → [2/6] 扫描update/ → [3/6] 检测不支持格式 → [4/6] MD转换 → [5/6] 更新知识层 → [6/6] 追加日志

[1/6] 安全确认

同 init 操作。确认新文档已脱敏。

[2/6] 扫描 update/ 目录

  • 列出 update/ 下所有文件
  • 检测与 raw/wiki/sources/ 中已有文件的对应关系
  • 输出变更摘要:「新增 M 个,更新 N 个,无变化 L 个」

文件对应判定:

  • 同名文件(不含扩展名)= 同一文档的不同格式版本 → 视为更新
  • 新文件名 → 新增文档

[3/6] 检测不支持格式

同 init 操作,列出非 .docx/.xlsx 文件。

[4/6] MD 转换

仅转换新增或已修改的文件:

  • 新增 .docx/.xlsx → 转换
  • 已修改(与 raw/ 中已有文件同名但内容不同)→ 转换(覆盖 wiki/sources/ 中对应 MD)
  • 已有且未修改 → 跳过

转换方法同 init 操作 [5/7],使用 python-docx + openpyxl 原生方案。

文档归类(重要): 新文档不直接以其 update/ 中的目录结构存放,而应根据文档名/内容分析归入已有分类。规则:

  • 文档名含「进港货站」「新货站」「发货」「分拣」「AGV」「ETV」「EMS」等关键词 → 归入「新进港货站」
  • 文档名含「设施」「设备」「维修」「漏水」等关键词 → 归入「设施设备」
  • 如果无法匹配现有分类,创建新分类目录(以文档名中提取的关键词命名)
  • 仓库路径:wiki/sources/{分类}/{YYYY-MM-DD-子主题}/文件.md

[5/6] 更新知识层

级联更新受影响的 wiki 页面:

必须更新的文件:

  • wiki/_index.md — 添加新条目
  • wiki/_overview.md — 更新统计
  • wiki/sources/ — 新文档的摘要页

建议更新的文件(LLM 自行判断):

  • 相关概念页 — 如果新文档引入了新信息
  • 相关实体页 — 如果新文档涉及已有实体
  • 对比页 — 如果新文档与已有文档有互补/矛盾信息

新类型页面的创建条件:

  • concept:多个源文档涉及同一主题,且主题足够独立 → 创建概念页
  • entity:多个源文档提及同一实体 → 创建实体页
  • comparison:两个或多个文档/概念存在对比价值 → 创建对比页

更新完成后,逐个更新页面的 YAML frontmatter 中的 updated 字段。

索引结构规范:

_index.md 中每个分类下分两层,严格执行:

### {分类名}

#### MD 文档(可全文检索)
- [[xxx.md]]  文档名
...

#### 原始文档(仅索引,不可搜索内容)
- [格式] `raw/xxx`  文档名
...

关键规则:

  • MD 文档在上(优先),原始文档在下(备用)
  • 不支持格式文件也要索引,以 [格式] 标签标注
  • 新文档按内容归类到已有分类中,不应自建顶级分类
  • 检索时先查 MD 全文,无结果才查原始文档索引定位 raw/ 原文

[6/6] 追加操作日志

## [{日期}] update | {源文件名}
- 变更类型: 新增/更新
- 归类: {分类名}
- 影响页面: [{受影响 wiki 页面列表}]
- 摘要: {一句话描述}

重要: 更新完成后,将 update/ 中的原始文件移动到 raw/ 对应分类目录。不支持格式文件也一并移动并加入索引。


操作 3: 检索与问答 (search)

触发方式: 用户提问涉及文档内容,说「查一下」「搜索」「dochub search」等。

检索策略(Karpathy 渐进式披露):

L0 → L1 → L2 → L3

| 级别 | 内容 | Token 预算 | 何时加载 | |------|------|-----------|---------| | L0 | 工作上下文(用户 profile) | ~200 | 每次会话 | | L1 | wiki/_index.md | 1-2K | 每次检索开始 | | L2 | 匹配页面内容(grep 定位) | 2-5K | 索引命中后 | | L3 | 完整源文档(wiki/sources/) | 5-20K | 需要原始细节时 |

检索流程:

  1. 读索引:先读取 wiki/_index.md,确定相关页面
  2. 关键词搜索:在 wiki/ 目录下使用 grep 搜索用户问题的关键词
  3. 读匹配页:读取匹配的 wiki 页面(优先 L2 级别)
  4. 溯源验证:如需要,追溯 wiki/sources/ 中对应源文档验证细节
  5. 综合回答

回答格式遵循 Karpathy 双输出原则:

## 回答
{基于文档内容的综合回答}

## 来源
- [[wiki/sources/{path}/file]] — {一句话说明}
- [[wiki/concepts/{concept}]] — {一句话说明}

## 置信度
{high / medium / low} — {简要说明}

特别规则:

  • 如果回答具有长期价值,主动提议将其保存为新的概念页/对比页/实体页
  • 必须引用来源,使用 [[wikilinks]] 格式
  • 不编造信息——如果文档中没有相关内容,明确告知
  • 如果发现文档间矛盾,标注并记录

操作 4: 健康检查 (lint)

定期对知识库进行全面体检。

触发方式: 用户说「dochub lint」「知识库检查」「健康检查」。

检查维度(Karpathy Lint 操作):

| 检查项 | 说明 | 输出 | |--------|------|------| | 矛盾检测 | 扫描 wiki 页面间的冲突声明 | 矛盾清单(页面A vs 页面B,具体冲突点) | | 孤立页面 | 无 [[wikilinks]] 入链的 wiki 页面 | 孤立页面清单 | | 缺失概念 | 被引用但尚未创建页面的主题 | 缺失概念清单及引用来源 | | 过期声明 | updated 超过 90 天的页面 | 过期页面清单 | | 置信度异常 | confidence: low 且被广泛引用的页面 | 需复核页面清单 | | 格式一致性 | YAML frontmatter 完整性、命名规范、交叉引用有效性 | 格式问题清单 | | 知识缺口 | 建议深入研究或补充的领域 | 研究建议清单 |

输出格式: 生成 wiki/_lint-{YYYY-MM-DD}.md 文件,包含所有检查结果。

同时追加到 wiki/_log.md

## [{日期}] lint | 知识库健康检查
- 矛盾: N 处
- 孤立页面: N 个
- 缺失概念: N 个
- 过期页面: N 个
- 格式问题: N 处
- 建议: {摘要}

关键设计决策

为什么是三层架构而不是简单文件夹?

| 问题 | 简单文件夹方案 | dochub 三层架构 | |------|---------------|----------------| | 知识积累 | 每次搜索需要重新扫文档 | wiki 层持续生长,知识复利 | | 交叉引用 | 无结构化关系 | [[wikilinks]] 预建关联 | | 可追溯性 | 无法验证信息来源 | 每个声明可追溯到 raw/ | | 维护成本 | 人工手动组织 | LLM 自动维护索引和交叉引用 | | 置信度 | 无法判断可靠性 | 每页标注 confidence | | 知识衰减 | 无法发现过时信息 | lint 操作定期体检 |

与 RAG 的区别

dochub 不依赖向量数据库或嵌入管道。它的策略是编译,而非检索——LLM 提前将知识组织好,而非每次查询时临时拼接。

渐进式披露

_index.md 是解决上下文窗口退化的核心机制。LLM 始终先读索引(1-2K token),而非加载整个知识库。索引质量随知识库增长自动提升——因为它是 LLM 自己维护的。

安装依赖

必需依赖(原生方案,推荐):

pip install python-docx openpyxl

可选依赖(markitdown 回退方案):

pip install "markitdown[all]"

Python 路径: C:/Users/skya2/.workbuddy/binaries/python/envs/default/Scripts/python.exe

工作目录配置

  • KNOWLEDGE_BASE_ROOT 由用户在首次 init 时指定,或从当前工作目录推断
  • 如果用户未明确指定路径,询问:「请指定需要管理的文档目录路径(如 C:\Users\xx\Documents\工作文档)」
  • 所有 dochub 操作默认在 KNOWLEDGE_BASE_ROOT 下执行

与用户的交互约定

  1. 安全确认不可跳过:init 和 update 操作必须先确认文档已脱敏
  2. 进度可视化:每个操作步骤以 [X/N] 格式显示进度
  3. 批量确认:覆盖/跳过等决策首次询问后自动应用
  4. 主动提议:检索中发现的长期价值内容,主动提议保存
  5. 诚实告知:文档中无相关内容的,明确告知而非编造
  6. 增量输出:阶段明显断开时,分批输出结果

实战经验

转换脚本模板

由于中文文件名在 bash heredoc 中可能编码出错,转换脚本应写入临时 .py 文件后执行:

# docx 转换
import docx
doc = docx.Document(path)
for para in doc.paragraphs:
    if para.style.name.startswith('Heading'):
        level = para.style.name.split()[-1]
        lines.append('#' * level + ' ' + para.text)
    else:
        lines.append(para.text)
for table in doc.tables:
    # 转为 Markdown 表格

# xlsx 转换
import openpyxl
wb = openpyxl.load_workbook(path, read_only=True, data_only=True)
for ws_name in wb.sheetnames:
    lines.append(f'## {ws_name}\n')
    for row in ws.iter_rows(values_only=True):
        # 首行作表头,后续行作数据

大文件处理

  • 超过 50MB 的 xlsx:load_workbook(path, read_only=True, data_only=True)
  • 99MB 漏水点清单实测可用,但转换耗时较长

已知坑点

  • markitdown 基础安装不含 docx/xlsx 支持,需 markitdown[all]
  • 即使安装 markitdown[all],部分环境仍报 MissingDependencyException
  • 推荐直接用 python-docx + openpyxl 原生方案,确定性更高
  • Windows 下移动文件到 Documents 目录可能触发沙箱拦截,需要 dangerouslyDisableSandbox