# 文档处理核心流程：A–F 抽取操作细节

> 🔴 两阶段法**契约**（文档处理优先级 / Phase1 禁止关联 / 关联仅一次 / B0 抽取模式 / 并行完成门控）见 `kb/kb.md`。本文件仅含 A–F 操作步骤，供菜单 0/1/2/3/4 执行时按需读取。

### A. 提取内容 + 自动归档

```bash
python {skill_dir}/kb/scripts/ahkb.py extract <相对路径> [--category <分类名>]
```

**此命令同时完成三件事：**
1. **提取内容** — 输出 JSON 包含 `chunks` 和 `resources_flat`
2. **自动归档** — 将原文件移入 `原始文件/` 目录
3. **分块落盘** — 已将每个原始文件按标题 / 段落切成 chunk，连同正文与关键词存入 `chunks/<文件>.json`。**C 步一律以该 chunk JSON 为唯一输入，不再为生成知识元而重读整篇原文。**

> 🔴 **抽取结果 ok 闸门（2026-08-11 加固）**：`extract` 返回的 JSON 现含 `ok` 与 `chunks_path` 字段。
> - `ok:true` 且 `chunks_path` 非空 → 抽取与分块落盘成功，进入 C 步（以 `chunks_path` 指向的 JSON 为唯一输入）。
> - `ok:false`（含 `chunks_error` / `extract_error`）→ 抽取或分块落盘失败，**立即停止并上报主代理，严禁把失败当成功继续**（旧版在 chunks 保存失败时会静默返回、子代理误以为成功）。

> 💡 进入 C 前可先运行 `preview-chunks` 查看极简分块目录：
> ```bash
> python {skill_dir}/kb/scripts/ahkb.py preview-chunks "<原始文件/相对路径>"
> ```
> 它只输出每个 chunk 的 `id / 标题 / 字数 / 前200字 / 关键词`，agent 据此决定切分；真正写某知识元时才去读那一个 chunk 的全文。

### C. 分析并生成知识元（★ 决定知识库质量的核心环节）

**⚡ 轻量化生成法（本地预切 + LLM 三步，★ 提速核心）：**
- **输入即本地 chunk**：C 步一律读取 `chunks/<文件>.json`（A 步已本地切好，含正文 + 关键词），**严禁为生成知识元而重读整篇原始文档**。
- **逐 chunk 轻量三步**（LLM 对每个 chunk / chunk 组只做）：
  1. **起名** —— 据 chunk 标题 + 关键词定知识元名（遵守命名规则、原子性规则）。
     - **🔴 命名前强制消噪**：chunk 标题常带原始文档的章节编号、括号、方括号。起名时必须先剥离：
       - `(1)xxx`、`[1] xxx`、`（一）xxx`、`2、xxx` → 只取 `xxx`
       - `[参考文献]`、`(工具)` → 去掉括号，取内部文字
       - `(28)`、`[40]`、`（68）` 等纯数字/页码 → **不得作为知识元名**；若对应正文无独立概念，应合入上级或弃置
       - 消噪后名称若超过 12 字，再压缩到核心词
  2. **摘原文** —— 直接引用 `chunk.text` 中对应片段（已有原文依据，不重写、不编造）。
  3. **写 summary** —— 一句话摘要（遵循 `cTextAmount` 展开深度）。
- **上下文最小化**：先用 `preview-chunks` 看极简目录决定切分；真正写某知识元时，只加载那一个 chunk 的全文，而非整篇。
- **逐段完整分析仍强制**：每个 chunk 都必须过一遍上述三步，该拆的知识元一个不能少（"严禁简化处理"铁律不变）。

**🎯 cGranularity 三档模式：**

| 值 | 模式 | 拆分策略 | 字数底线 |
|:--:|------|----------|:--------:|
| 0 | **精细模式** | 概念有独立性即拆分 | ≥50字 |
| 0.5 | **均衡模式**（默认） | 有明确概念边界才独立 | ≥60字 |
| 1 | **粗粒模式** | 只按大主题拆分 | ≥120字 |

> 🔴🔴 **概念独立性原则（★ 最高优先级，唯一标准）**：上表所有"拆分策略 / 字数底线"都只是**倾向与提示**，绝不是强制数量指标。是否成元的**唯一判据**是"概念是否独立"——脱离上下文含义仍完整才独立成元；不独立的组成部分合入父级或弃置，**绝不凑数、绝不硬拆**。并行抽取（模式 2）下尤其要克制：每个子代理独立处理单文件，更不能为"达标"而把概念切得过碎（详见 `kb.md` 核心设计原则之首条）。

**🎯 cTextAmount 三档模式：**

| 值 | 模式 | 每个知识元的展开深度 |
|:--:|------|-------------------|
| 0 | **摘要模式** | 只写定义加 2~3 个核心要点 |
| 0.5 | **适中模式**（默认） | 一个完整段落 |
| 1 | **详细模式** | 充分展开，含定义、说明、论证 |

**🔴🔴 严肃抽取铁律（★ 最高优先级）**
- **严禁因文档篇幅大而偷懒。** 文档越大越要逐段分析，该拆的知识元一个不能少。
- **严禁将整篇文档不经认真分析就当做一个知识元标记为已处理。** 每个段落、每个概念都必须独立判断是否成元。
- **严格按照 `cGranularity` 和 `cTextAmount` 参数执行：** 该细就细（精细模式概念有独立性即拆）、该粗就粗（粗粒模式只按大主题拆）、该详就详（详细模式充分展开）、该略就略（摘要模式只写要点）。
- **每批完成后必须自查（不凑数原则）**：检查本次产出的知识元——若数量异常偏多，先查是否把"非独立组成部分"（子步骤、举例、补充、过渡）误拆成了独立单元；若数量偏少，先查是否确有独立概念被遗漏。**但绝不为凑数而强行拆分或新建**；概念独立性是唯一标准，数量本身不是目标。
- **🔴🔴 禁止跳过任何原始文档（★ 铁律）。** 只要被判定为原始文档，**每一篇都必须完整解析抽取，即使存在相似或同名的文件也绝不能跳过**。处理清单上列出的所有 N 个文件，必须逐个处理完毕，少一个也不行。绝对禁止以"这个文件看起来和之前处理过的类似"为理由跳过。
  - **🔴 自动审查机制已启用（双重保险）：**
  1. **D.5 产出自检** — 覆盖率/数量/字数自检已合并进 C/D 生成指令，产出时当场自查；`verify-units` 仍作为 mark-processed 前最后一次轻量脚本确认
  2. **F `mark-processed` 硬关卡** — 零匹配的知识元时直接拒绝标记
  - **不要试图绕过这些检查，它们是为了帮你拦截错误。** 如果脚本拒绝了标记，说明你确实跳过了 C/D 步骤，回去补做即可。
- **🔴 所有文档必须重新从头处理，禁止使用对话历史中上一轮的产出作为参考。** 重建的目的是得到不同的知识库，上一轮的结果作废。

**⚠️ 护城河原则（任何时候不违反）：**
- **所有内容必须有原文依据**，禁止编造、推测
- **🔴 正文不得为空**
- **🔴 字数底线（仅作"是否真独立"的提示）**：候选正文不足该档位最低字数时，**先判断它脱离父级后含义是否仍完整**——完整则保留（哪怕短，如一条精确的定义或定理）；不完整才合入上级。绝不为了凑满字数而编造内容或把非独立片段硬拆成元。
- **🔴 连续短节合并**
- **🔴 低温模式**：事实准确性为最高标准
- **🔴🔴 用户抽取要求优先（★ 2026-08-14 新增）**：用户在「抽取要求确认」环节（菜单 0/1/2/3/4 均在开始抽取 chunk 前询问）输入的额外要求，写入 `系统设置/project_settings.json` 的 `extraction_requirements` 字段，由 `extract` 注入 `guidance.instruction`（顺序模式主代理遵守）与子代理提示词模板 `<抽取要求>` 占位符（并行模式）。**用户要求优先级高于 cGranularity/cTextAmount 默认参数；与默认参数冲突时以用户要求为准。**

**🔴 子代理 / 并行抽取（★ 2026-08-13 起为"均衡分组"模式）：** 是否使用由用户在 **B0 抽取模式选择** 决定。选 2（并行）时：主代理先批量 `extract`（确定性）→ `phase1-group --from-scan --max-groups 4` 按工作量**均衡分组（≤4 组）**→ 每组派发**一个**子代理**顺序处理组内全部文件**（大文件独占一组、小文件打包）；每个子代理写知识元前必须执行「🔴 写前查盘合并（★ 强制）」规则；选 1（顺序）时不使用子代理。

> 🔴🔴 **子代理契约的唯一权威来源 = `kb/kb.md` 中的「🔴 子代理提示词模板（分组版）」。** 主代理**必须将该模板原样注入**每个子代理提示词，不得只口头传达要点——子代理是独立进程，看不到主代理的上下文，任何"主代理知道但没写进提示词"的规则都等于没告诉它。模板已内联以下关键铁律（缺任一即违约）：
> 1. 🔴🔴 **Phase 1 禁止写入任何 `[[链接]]`**（关联由第二阶段 maintain 统一添加）；
> 2. 概念独立性原则（唯一成元标准，绝不凑数/硬拆）；
> 3. 🔴 **命名规则（文件名=H1，一字不差；禁编号/括号/纯数字/装饰符；起名前强制消噪）**——写前查盘合并依赖此约定；
> 4. 知识元 frontmatter 固定格式与字段顺序 + **Phase 1 禁止写入 resources/关联字段**；
> 5. 🔴🔴 **写前查盘合并**的具体做法（已存在同名→合并而非覆盖/跳过/新建）；
> 6. `extract` 的 **ok 闸门**（ok:false 立即停止上报，严禁当成功；主代理已预抽取时直接复用 chunks 跳过）；
> 7. `verify-units` 与 `validate-units --quarantine` 两道收尾闸门（**每个文件** mark-processed 前必跑）；
> 8. `update-concept-index` 命令；
> 9. 🔴🔴 **临时文件铁律**（见下）；
> 10. 当前 `<cGranularity模式>` / `<cTextAmount模式>`（从 `系统设置/project_settings.json` 取值后填入，子代理无默认值可猜）；
> 11. 🔴 **组内多文件逐个处理**：按文件列表顺序，每个文件独立跑完 A→F + 心跳（按当前文件）+ 收尾（mark-processed ok:true）后才开始下一个。

> 🔴🔴 **子代理临时文件铁律（★ 强制）**：子代理产生的任何临时脚本、调试日志、中间文件（`_xxx.py`、`_xxx.log`、`_xxx.txt`、`extract_*.txt`、`mark_*.log` 等）**一律写入 `<工作空间>/临时工作文件/`，严禁直接落在工作空间根目录**。流程结束前须清理自己产生的无用中间文件；若已有文件误落根目录，必须移入 `临时工作文件/` 或上报主代理。
>
> 🔴🔴 **删除自动执行铁律（★ 强制，禁止任何删除确认）**：清理临时文件/中间产物一律用统一删除命令 `python <skill_dir>/kb/scripts/ahkb_trash.py <路径> --workspace <工作空间>`（`os.rename` 移入工作空间「回收站/」，失败静默直删，全程不向用户确认）。**严禁 Bash `rm`/`rmdir`（会触发 WorkBuddy 权限弹窗打断全自动流程），严禁 os.remove / Path.unlink / shutil.rmtree（沙箱 safe-delete 会拦截导致静默失败残留）**。

**🔴 批次一致性自查（强制）：**
每批完成后检查本批产出的总数——如果与预期数量偏差超过 2 倍，暂停检查原因。

#### 跨文档统一处理规则

分析文档前先加载已有知识元/资源/处理清单。**完全重建时跳过**。

#### 🔴 写前查盘合并（★ 强制）

> 这是跨文档 / 并行抽取去重的**唯一机制**。每个知识元在落盘前必须执行查盘，从根本上避免同名覆盖与重复建元。

准备写入知识元 `<概念名>.md` 前，**先检查 `知识元/` 目录是否已存在同名文件**：

- **不存在** → 正常新建。
- **已存在** → **合并，严禁覆盖、严禁跳过、严禁新建同名文件**：
  1. 正文：保留元原有正文原样不动，在其后追加新来源对该概念的内容，加一个子标题区分来源，如 `## <来源文档短标识>视角`（例：`## 大系统观PPT视角`）；
  2. `source` 字段：把新来源文件路径追加合并进保留元的 `source`（多来源用 `, ` 分隔的引号列表，如 `"a.md", "b.pptx"`）；
  3. frontmatter：只保留**一份**；`updated` 改为当天；类型标签取其一（优先"概念"）；`tags`/`unit_id`/`created`/`summary` 沿用保留元（summary 可微调）；
  4. **严禁**产生重复 `# <概念名>` 标题、重复 frontmatter 字段、或把旧内容整段丢弃。

#### ⚡ 原子性拆分规则

**核心原则：** 一个知识元 = 一个独立概念/观点/定义/事实/人物/原理/方法。

> 🔴🔴 **唯一成元标准 = 概念独立**：下方"人物/定义强制独立""是否包含超过一个独立概念→拆"等规则，全部从属于这一条。判断时**只问一句**：脱离上下文，这个概念含义还完整吗？完整→成元；不完整→合入。不要问"够不够长""够不够多"——那些只是辅助提示，不是标准。

**🔴 强制独立（任何参数下不得合并）：**
- **人物** — 任何人物名必须独立成元
- **定义** — 任何概念定义必须独立成元

**原子性检查清单（创建每个知识元前自查）：**
```
□ 候选名称与已有知识元高度相似？ → 🔴 不新建，追加关联
□ 是否脱离父级后含义仍完整？ → 不独立，合入父级
□ 是否包含超过一个独立概念？ → 拆
□ 是否含有人物名？ → 人物必须独立
□ 正文是否满足该档位数底线？
□ 正文是否为空？ → 🔴 不得为空！
□ 详细程度是否符合 guidance 指令？
□ 原文回溯：这一句原文中有对应文字吗？
□ 同一层级是否有连续短节可以合并？
```

#### 🧩 知识元关联规则

**第一阶段 AI 禁止写入任何 `[[链接]]`。**

#### 🏷️ 标签规则

**顺序约定：** `[领域标签, 概念标签, ..., 类型标签]`
- **最后一个标签必须是类型标签**（如 `概念`、`方法论`、`人物`、`定义`、`原理`）
- **知识元名称本身不得作为标签**

#### 📛 知识元命名规则

**🔴 知识元名称必须是合理、规范的概念或术语，严禁出现以下形式：**

- ❌ 章节编号：`1.1 概述`、`第3章 方法论`、`§2.3`、`2、主打产品与服务`
- ❌ 符号式字符：`→→→`、`★核心★`、`【要点】`、`===分割线===`
- ❌ 字符画/装饰：`╔══╗`、`~~~~`、`●●●`
- ❌ 编号前缀：`KD-001-xxx`、`A-耦合度`、`(1)工具`、`（3）霍尔`、`[1] 引言`
- ❌ 括号/方括号整体包裹：`[参考文献]`、`(工具)`、`【系统哲学】`
- ❌ 纯数字及带括号的纯数字：`123`、`2024`、`(28)`、`[40]`、`（68）`
- ❌ 过长的句子：超过 12 个字

- ✅ 正确示例：`耦合度定理`、`系统边界`、`熵增原理`、`全息有机系统论`、`卢春阳`

**文件名（不含 `.md`）必须等于 H1 标题，一字不差。**
- 简短（1-12字），尽量短
- 若原始标题含编号/括号/方括号，必须在写入前**强制剥离**，仅保留真实概念名。例如 `(1)工具` → `工具`，`[参考文献]` → `参考文献`，`2、主打产品与服务` → `主打产品与服务`。
- `(28)`、`[40]`、`（68）` 等纯数字/页码片段**不是概念名**，不得建元；若正文无独立概念，应合入上级 chunk 或弃置。

### D. 写入知识元文件

**AI 在 Phase 1 写入的内容：**

```markdown
---
tags: [系统论, 耦合, 概念]
source: "原始文件/管理哲学/源文件.pptx"
unit_id: KD-YYYYMMDD-NNN
created: YYYY-MM-DD
updated: YYYY-MM-DD
summary: 耦合度是指系统要素之间的相互依存程度
related_files:
  - file: "原始文件/管理哲学/源文件.pptx"
    score: 1.0
---

# 耦合度定义

正文内容...
```

**强制规范：**
1. **Phase 1 字段顺序**：tags → source → unit_id → created → updated → summary
2. **Phase 1 禁止写入** resources、关联知识元、关联资源、关联原始文件
3. 🔴🔴 **source 字段格式（★ 2026-08-13 实战教训：格式错误 = 收尾卡死）**：
   - 单来源：`source: "原始文件/xxx.pdf"`（带引号）；
   - 多来源（写前查盘合并后）：`source: "a.md", "b.pptx"`（**逗号分隔的引号列表**，引号完整保留）；
   - 🔴 **严禁 YAML 数组格式**（`source: ["a.md", "b.pptx"]`）。`verify-units` / `mark-processed` 按 source 匹配知识元，数组格式会令匹配失败、计数为 0，导致"零匹配拒绝标记"——子代理/主代理都永远无法收尾（2026-08-13 东油-第2讲 66 个单元因此卡死）。多来源合并时逐来源追加引号项，切勿改写成数组。

### D.5 🔴 产出自检（已合并进生成，无需单独复盘轮次）

> 🤖 **全自动执行**：无需用户确认。

覆盖率 / 数量 / 字数自检**已写入 C/D 的生成指令**：每批知识元产出时，agent 当场按当前 `cGranularity` 档位自查（最少知识元数、chunk/知识元比、每知识元最少字数，阈值见表），不达标立即在本批内补做，**不再另起一轮"生成后再复盘"的推理**。

mark-processed 前，**仍须执行一次 `verify-units` 作为轻量脚本终检**（硬关卡不撤）：

```bash
python {skill_dir}/kb/scripts/ahkb.py verify-units "<原始文件/相对路径>"
```

AI 根据返回的 `status` 字段自动决策：

| 返回 status | 含义 | AI 行动 |
|:----------:|------|---------|
| `"pass"` | ✅ 产出合理，符合当前 cGranularity 档位 | 继续下一步 |
| `"warning"` | ⚠️ 覆盖率偏低，但未完全跳过 | 检查 `warnings` 列表，补做遗漏 chunk 对应的知识元 |
| `"fail"` | ❌ 知识元数为 0 或严重不足 | 必须回到 [C] 重新逐段分析，不得进入下一步 |

> 🔴 **`ok` 与 `status` 已对齐（2026-08-11 加固）**：命令现保证 `ok:true` **当且仅当** `status=pass`；`warning` / `fail` 一律返回 `ok:false`。AI 应以 `ok` 为通过闸门，不应仅凭 `status` 字符串判断（旧版 `verify-units` 恒返回 `ok:true`，会把 `fail` 误判为成功）。

> 🔴🔴 **`unit_count=0` 排查（★ 2026-08-13 实战教训）**：若某文件明明写入了知识元、`verify-units` 却报 `unit_count=0`，**第一嫌疑是 frontmatter 的 `source` 字段格式错误**（YAML 数组 `source: ["..."]`，或多来源合并时引号/逗号书写错误），导致按 source 匹配失败。处置：先抽查该文件知识元的 source 形态（单来源/多来源引号列表/数组），把数组格式改为引号列表后再重新 `verify-units`；若大量单元格式错误，回到 [C] 统一修复。新版 `verify-units`/`mark-processed` 已对数组格式容错匹配并输出格式告警，但告警 ≠ 放任——发现后仍须修复。

> 🔴 检查阈值**自动随 `project_settings.json` 中 `cGranularity` 调整**：

| 检查项 | 精细模式 | 均衡模式 | 粗粒模式 |
|--------|:--------:|:--------:|:--------:|
| cGranularity 值 | ≤ 0.25 | 0.26~0.74 | ≥ 0.75 |
| 每文档最少知识元 | ≥ 3 | ≥ 2 | ≥ 1 |
| chunk/知识元建议比 | ≤ 3:1 | ≤ 5:1 | ≤ 8:1 |
| 每知识元最少字数 | ≥ 50 | ≥ 60 | ≥ 120 |
| 全库单元数/文档数 | ≥ 5 | ≥ 3 | ≥ 1.5 |

### E. 处理资源 .ctx 文件

提取器已自动生成初始 `.ctx`。**你的任务：** 填写 `belongs_to` 指向所属知识元。

### E.5 更新概念索引

```bash
python {skill_dir}/kb/scripts/ahkb.py update-concept-index
```

### F. 🔴 标记已处理（自动硬关卡检查）

> 🔴 **命名质量硬关卡（新增）**：在调用 `mark-processed` 前，**必须先运行 `validate-units --quarantine`**，把 bad_name（名称含编号/括号/纯数字等）和 empty_body 单元移入 `知识元/_quarantine/`。若 quarantine 后发现大量名称违规，必须回到 [C] 重新起名并修复。
> ```bash
> python {skill_dir}/kb/scripts/ahkb.py validate-units --quarantine
> ```

> 🔴 **自动硬关卡**：`mark-processed` 会自动检查 `知识元/` 中是否存在 source 匹配该文件的知识元。
> **零匹配且无 `--force` → 拒绝标记**，AI 检测到 error 后自动回头执行 [C] 分析。
> `--force` 仅用于极少数特殊情况（如文档确实无法产生知识元），不得常规使用。

```bash
python {skill_dir}/kb/scripts/ahkb.py mark-processed "<原始文件/文件名>"
```

AI 读取返回的 JSON，按以下逻辑处理：

```
收到 mark-processed 的 JSON →
  ├─ "ok": true → ✅ 标记成功，继续处理下一个文件
  └─ "ok": false 且 "warning": true, type:"no_knowledge_units" →
       ❌ 知识元完整性检查未通过（旧版仅返回 warning:true 不带回 ok:false，现已补上）
       → 回到 [C] 重新分析该文档的 chunks 并创建知识元
       → 再次执行 mark-processed（直到 ok:true 才返回）
```

| 返回特征 | 含义 | AI 行动 |
|:--------:|------|---------|
| `"ok": true` | ✅ 完整性检查通过，已标记 | 继续处理下一个文件 |
| `"ok": false, "warning": true, type:"no_knowledge_units"` | ❌ 在知识元中未找到该文件的产出（ok 现为 false） | 回到 [C] 重新分析 chunks 并创建知识元，然后再次执行 mark-processed |

> 🔴 **执行 `mark-processed` 前必须已执行过 D.5 `verify-units` 且状态为 `pass` 或已处理警告。**

### F.5 全库去重（已移除）

> 本步骤（原"并行模式全库去重合并"）已按计划移除。跨文档重复由抽取阶段的防重复提示（见上方规则与 `ahkb.py` 中的抽取指令）在创建时天然拦下，不再设置事后全库合并环节。选 1（顺序）与选 2（并行）均不执行任何事后全库去重。

### G. 质量审核

```bash
python {skill_dir}/kb/scripts/ahkb.py audit
```

---

