Ch27: 自适应分块源码——四级策略、降级链与表格保护
Part 8 · 前置:Ch26 PMI 图谱 · 后续:Ch28 docreader 案例:case-1725(HTML 表被切断)
结论先行:分块是 检索上限——再强的 RRF/Rerank 也救不回被撕碎的表格或拦腰斩断的代码块。WeKnora 用 四级自适应 + 降级链 在 ingest 时选粒度;大师改 chunk 必做 表格/代码/FAQ 三类回归,并理解 chunker 与 docparser 的格式契约。
一、日常类比
把一本教材拆成检索卡片。按固定字数切:函数定义拦腰断,上下半页都「半相关」;按页切:FAQ 的问题和答案分到不同卡片,用户问原题只召回问题。WeKnora 的做法像 先看目录结构再决定怎么切——有章节用章节,没有再用段落,最后才语义/固定长度。
二、四级策略与降级链
| 级 | 粒度 | 触发条件(概念) | 适用 |
|---|---|---|---|
| L1 文档 | 整篇 | 极短 FAQ / 单页说明 | 一问一答 doc |
| L2 章节 | # 标题下 |
Markdown/Word 有清晰 heading | 手册、API doc |
| L3 段落 | \n\n + max tokens |
默认路径 | 长文叙述 |
| L4 语义 | embedding 跳变切 | L3 仍过大 | 无标题长文 |
降级链(语义失败时):L4 → L3 → 固定长度 + overlap。读代码时找 Chunk() / AdaptiveChunker 内 if-else 选级 与 ChunkSize、Overlap 常量。
cd WeKnora # pin: 见 case-index main 122408b2 或当前 main
rg -n "ChunkSize|Overlap|Adaptive|protectedPattern" --glob '*.go' internal/ pkg/
三、表格保护:case-1725 为什么发生在 chunker
现象:PaddleOCR-VL 输出 HTML <table>,超过 ChunkSize 后从 <td> 中间切断。
根因链(不是单点 bug):
docreader(HTML table) → docparser(未归一化) → chunker(只保护 | pipe 表|)
chunker 的 protectedPatterns 识别 Markdown 管道表,不识别 HTML table。修复可在 docparser 转 MD(PR #1755)或 chunker 增加 <table> 边界(二选一或双做)。
| 表格表示 | chunker 是否应整段保留 |
|---|---|
Markdown \| col \| col \| |
✅ 已有保护 |
HTML <table>...</table> |
❌ 1725 前无保护 |
| 展平纯文本「23.5 18.7」 | ❌ 表头已丢,语义残缺 |
四、其他失败模式
| 场景 | 分块后果 | 检测方法 |
|---|---|---|
| 50 行函数拦腰切 | 无签名或无实现 | 上传 .go 样例,看 top chunk |
| FAQ Q/A 分离 | 召回问题无答案 | QA 对应用 L1 或 Q+A 同 chunk |
| 长距离指代「它」 | 指代丢失 | contextual chunk 或更大 overlap |
| 大表按行切 | 数字无表头 | 强制整表 chunk |
五、动手实验(45 分钟)
- 上传 同一 PDF 两种配置(默认 vs 更小 ChunkSize)
- 问表格单元格精确值(见 lab/queries-smoke-20.jsonl D 组)
- 对比 top-3 chunk 是否 含表头+数据同行
- 改 chunk 参数后跑 benchmark/smoke-10.jsonl 中
zh-005
六、竞赛贡献方向
doc_type上传枚举 → 绑定 chunk 策略(法规/代码/FAQ)- HTML/Markdown 双表保护统一测试套件
- 分块质量工具:内聚性/完整性分数(见 Ch40)
章末自检
- 画出 docreader → docparser → chunker → embed 四段
- 解释 case-1725 为何主要改 docparser 而非只调 ChunkSize
- 说出四级降级顺序及 L1 适用场景
- 在仓库定位
protectedPattern或等价逻辑文件名