中医知识库检索质量改造 · 进度与成果总结

日期:2026-10-02 性质:本机实测报告(可直接给外部评审) 环境:DSH 桌面端 0.2.0-rc.2 + dsh-knowledge 插件 0.4.1,仅监听 127.0.0.1:19387 嵌入/重排:Qwen/Qwen3-Embedding-4B(2560 维) / Qwen/Qwen3-Reranker-8B(硅基流动 API) 总原则:原文完整、出处可追溯 > 分块与检索效果;未确认前不动原始 EPUB、不动现有库、不改插件


0. 一句话结论

《经络腧穴学》的"碎块"问题已定位并解决:不改插件,用"结构优先文本"通道重建,676 块(原 6535 块),入库逐字无损,36 道测试题全部第 1 位精确命中(原库 14/36)。新库已建成(经络腧穴学·结构优先),但检索开关仍指向原库,等人工确认后切换。


1. 问题与根因(已确认,可复现)

1.1 现象

「中医新」库(《经络腧穴学》沈雪勇 4 版 EPUB)共 6535 块 / 283093 字符,平均 41 字符/块,1341 块不足 50 字符。问"中府 定位",Top1 返回的是一句 36 字符、没有穴名的 【定位】横平第1肋间隙…。

1.2 根因(源码 + 复刻双重确认)

1.3 顺带查实的两个源数据事实


2. 三条候选路线与实测对比

测试集:第一、二、三、九、十六章 + 附录,共 1812 个原始段落;同一套嵌入/重排/检索参数。

指标A 现状C 结构优先(采用)D 语义合并R 原库(整本)
块数18122241552—
块长 中位 / 均值 / 最长24 / 42.2 / 509266 / 377 / 182123 / 49.4 / 881—
碎块(<50 字符)134191090—
孤立标题块98048—
穴名与【定位】同块0/116116/1162/116—
入库逐字无损通过通过通过—
检索:单块精确命中(21 题 TopK=4)11211411
检索:仅靠 Top4 拼装才命中7015
检索:完全落空3065

结论:C 路(结构优先文本)全面胜出;D 路(插件配置项 semanticChunk=true,按嵌入相似度自动合并碎块)只能把 1812 块降到 1552 块,穴位条目同块率仍只有 2%,解决不了问题,予以排除。


3. 关键技术发现:「Markdown 聚合不可行」需要限定条件

早期结论认为"在 Markdown 层面预先聚合无效"。实测表明该结论只在"单元内部保留空行"时成立:

  1. 单元内部段落用单换行连接(normalizeText 只压缩 3 个以上连续换行,单换行保留)→ splitBlocks 不再切。
  2. 单元之间用空行分隔 → 每个单元恰好成为一个块。
  3. #/## 开头的行会被 splitBlocks 吃掉并转成该块的 heading 元数据,入库时拼成 context = 书名 > 章 > 节(:9401)。此前一次失败的 A/B 测试,是因为前缀行与正文之间留了空行,才被切成独立小片。
  4. 本方案改用片首内联出处行(不依赖上述机制),因此逐字无损。

即:仅靠文本导入通道就能实现结构优先分块,无需修改插件。


4. 最终采用的分块规则

全书离线核验(29 页 / 6535 段 → 676 片)

核验项结果
片数 / 最长片 / 超预算片676 / 1817 / 0
无损性去标记与注入上下文后,去空白逐字 == 库内 rawText
标题253 个,一个不少
图片占位 / 脚注锚点 / 【定位】217 / 1922 / 401,与现状完全一致
出处标记可回解676 / 676 全部可定位到原 XHTML 页 + 元素序号 / 锚点 id
穴位条目纯度每片最多 1 个【定位】,0 粘连
标记与上下文开销19810 字符,占原文 7.1%
目录页处理EPUB 目录页 541 小片 → 18 片;NCX 导航页 3.3 万字符单块 → 20 片

5. 已建成的新库(检索开关尚未切换)

项值
库名经络腧穴学·结构优先
库 id8bf27782-5f61-49c8-8d9a-af2b89158239
结构29 篇文档(按原 XHTML 页切分,标题取原书章名/前言/附录等)
块数676
字符 / token297000 / 128197
逐篇核验块数与送入片数一致 29/29;入库逐字无损 29/29
检索开关仍指向原「中医新」库(enabledBaseIds 未改)

建设过程中修正了两个我方脚本的缺陷(与插件无关):① 未按每篇文档自身预算收口,导致 5 篇中各有片超限;② 按篇补切时片首标记行后多出空行,入库被切成"标记 + 正文"两块(首版库 686 块 ≠ 676 片)。修正后删库重建,逐篇完全对齐。


6. 检索验证:36 题三版对照(重点,含一处结论更正)

36 题覆盖《经络腧穴学》的第一、二、三、五、六、七、八、九、十、十一、十二、十三、十四、十五、十六、十七章及附录——其中 12 章未参与任何规则调参,用于防止过拟合。全部问题限定到"本书"这一个文档,TopK=4。

版本块数一块多大单块精确命中仅拼装命中完全落空
中医新(EPUB 直导)653541 字符14 / 361111
中医 旧库(md 版)175~1200 字符36 / 3600
新库 结构优先676一条一块36 / 3600

必须更正的一点:不能声称"前两个库都远不如新库"。实测表明旧「中医」库里那一版(md,1200 字一块)同样是 36/36,与新库打平。真正的差异不在"能否检索到",而在下面四项:

维度中医 旧库新库 结构优先
一块里含几个穴位多个(1200 字一大段,需自行在其中定位)一个(穴名+定位+主治+操作,可整块引用)
正文结构标记401【定位】/401【主治】/401【解剖】(与 EPUB 完全一致)同左
图片占位0(全丢)217(全在)
脚注锚点0(全丢,无法跳转)1922(全在)
每块出处无有(原 XHTML 页 + 锚点)

即:新库相对旧库的增量是「一条一块、可整块引用、图片与脚注未丢、出处可回解」,而不是"能查到 vs 查不到"。若只要求"能检索到",其余那批 1200 字一块的资料不需要改造。


7. 其余 46 份资料的体检结果(决定后续工作量)

47 份资料的原始格式全部为 EPUB,原始文件位置: DSH云端备份\4-原始底本\epubtest\00-原始EPUB\(10 个 EPUB,含 2 个合集) 已转换的 md:…\epubtest\03-入库\(10 个)、…\epubtest\04-合集拆分\(38 个,由两个合集拆出)

按"块是否碎"分类(以库内块数 ≈ md 段落数、块长 ≈ 段落长为等价关系):

类别本数特征建议
A 已较粗34 本一段约 1200 字,不碎(等同旧库那版)不用重切
B 偏碎1 本《脈經校注》,一段约 590 字顺手做
C 真碎11 本一段 200–370 字,近一半段落不足 50 字优先做,受益最大

C 类 11 本(合计约 400 万字符):证治准绳(五)幼科、千金翼方校释、重订医学衷中参西录(上/下)、中药学、证治准绳(四)疡医、黄帝内经素问语译、针灸大成、刺法灸法学、单玉堂针灸配穴通俗讲话、黄帝内经素问(典藏版)。

工作量估计(若把 C+B 类做完)

步骤时间
4 套"单元规则"(医经校注类 / 方书类 / 教材讲稿类 / 针灸专著类)4–8 小时
C 类 11 本 + B 类 1 本:跑通+逐本无损与出处核验+导入+抽测5–7 小时
全库检索验证2–3 小时
合计约 11–18 小时 ≈ 2–3 个工作日
A 类 34 本若也要按章细化追加 8–12 小时(收益小,建议暂不做)

复用性:EPUB 元素级抽取、结构优先切分、无损自检、出处回解、入库与检索对比脚本均已具备,对全部书目通用;每本真正需要人工介入的是"什么算一个单元"的规则确认。

注意:《中药学》那份文件名标注为 中药学 .pdf_by_PaddleOCR-VL-1.6.md,是扫描 PDF 经 OCR 得到的,文字质量需单独核对,不宜与其他书批量处理。


8. 知识库设置审计(全局 vs 库级)

关键机制:库级配置优先于全局配置(曾因此踩坑:重排模型短名写在库级,全局正常但库级报 HTTP 400)。

项全局「中医新」库级(实际生效)
嵌入模型Qwen3-Embedding-4B继承(一致)
重排模型Qwen3-Reranker-8B同(已修好)
topK46
similarityThreshold00.15
siblingChunks1继承 1
semanticChunkfalsefalse(显式)
文档处理器builtinmineru(带 key)
图片识别offopenai / Qwen2.5-VL-72B(带 key)
chunkSize / overlap / smartChunk800 / 100 / true继承

不要改动:

  1. 嵌入模型(一改,三库 1460 万字符全部需重新向量化,且新旧库向量互不兼容);
  2. 重排模型(当前是正确的全名,改动会重演 HTTP 400);
  3. smartChunk=true 与空行分隔(本方案生效的前提)。

建议调整(均在「中医新」库级,属可选):

  1. siblingChunks 1 → 0:现在会把命中块的前后邻居一并塞进结果。对碎块库是补救(邻居里可能有穴名),对"一条一块"的新库则是噪声(邻居是别的穴位)。旧「中医」库本身即设为 0。
  2. topK 6 → 4(可选):一条一块时 4 条足够。

MinerU:只对 PDF 生效。现有三库内容全部是 EPUB/md(唯一 PDF 衍生的《中药学》已在外部用 PaddleOCR 转好),MinerU 当前完全用不上、也不会被触发,无需改动。注意它设在「中医新」库级,新库继承全局 builtin;将来若向新库导入扫描 PDF,才需要另行配置。

图片识别:「中医新」库级其实已开启(openai / Qwen2.5-VL-72B-Instruct;全局是 off,被库级覆盖),但这本书一张图注都没生成——库内 217 个图片占位全部为空。说明内置 EPUB 解析路径不会把图片交给视觉模型,该设置对本库是空转。图片提字应作为独立工作线,且机器输出必须标注「机器识别/待核」。

关于嵌入模型 4B vs 8B:同家族 MTEB 多语言成绩 0.6B ≈64.3 / 4B ≈69.5 / 8B = 70.58,即 4B → 8B 仅约 +1.1 分(相对约 1.6%),真正的大台阶是 0.6B → 4B。而本次仅改变分块方式(同一 4B 嵌入)就把命中率从 14/36 提到 36/36。因此暂不更换嵌入模型;若将来要试 8B,最省的做法是只在新库上试(676 块,分钟级、成本极低),不动旧库与全局。


9. 对早期外部建议的逐条核对

#早期建议核对结果
1碎块源于源 XHTML 短段落 + 插件按空行切,重建索引无效成立,已复现
2本 EPUB 顺序/图片未丢;插件从不读 spine 是潜在缺陷成立,源码复核确认
3Markdown 预聚合不可行,须改插件或用"单元内无空行"的文本需限定:前半句只对"保留空行的 Markdown"成立;后半句已验证可行,因此不必改插件
4按章→节→穴位单元组织,超 1824 再拆,保留章节/XHTML/元素序号/锚点成立,已实现并量化
5暂不改全书,先扩到 3–5 章测试再定已执行,并已按此结论建成全量新库(未切换)
6图片单独处理、模型输出只作待核同意,尚未开始
7接口明文返回 key,须轮换同意,尚未执行(见 §10)
—该清单遗漏:插件配置项 semanticChunk(自动合并碎块)已补测,解决不了问题,排除
—需更正:不宜声称"旧库远不如新库"旧库 md 版 36/36 与新库打平,真正差异见 §6

10. 未决事项

  1. 是否把检索启用范围切到新库(knowledge-toggle 的 enabledBaseIds,目前仅 中医新)。一步可回退。
  2. 图片提字:217 张图仍只有占位,alt 全空;字形图/正文图/注释图需分别提取并人工核对,机器输出标注「机器识别/待核」。经络示意图的模型描述建议另存。
  3. 插件 spine 缺陷:建议向上游提 issue(通用缺陷,与本机数据无关),尚未提交。
  4. 凭据安全:GET /knowledge/config 与 GET /knowledge/bases 会明文返回嵌入/重排/图注/MinerU 的 key,而本机接口无鉴权;历史上会话记录中亦曾出现明文 key。建议轮换密钥并给这两个 GET 加鉴权(后者属改动插件本体,未执行)。本报告与全部脚本均不含任何密钥。
  5. 临时库清理:本轮为对比共建了 5 个 _tmp- 临时库,尚未删除(见 §12)。
  6. C 类 11 本是否开工(§7)。

11. 复现方式

全部脚本位于 工作区\_tmp\,可用随附 Python 运行;关键产物:

文件用途
gen_struct.py结构优先文本生成器(内置无损自检 + 按每篇预算收口)
extract_v2.jsEPUB 元素级抽取器(按 OPF spine + body 顶层块元素,输出 page/elemIndex/id/images)
import_full.py / reset_full.py全量建库 / 删库重建
verify_c_full.py / check_pieces.py出处回解、单元纯度、片内空行与预算复核
retrieval_full.py / retrieval_old.py / deep_compare.py36 题检索对比 / 旧库补测 / 三维度深挖
five\C-pieces-all.json全书 676 片(含 pre/core 与元素 ids),全量建库之源
five\full_base.json新库 id 与 29 篇文档 id 台账
five\retrieval_full.json / retrieval_3way.json检索结果原始数据
five\md_inventory.json / worklist.json47 份资料的结构体检与分类

主要 API 端点:POST /knowledge/bases、POST /knowledge/bases/{id}/documents、GET /knowledge/documents/{id}?includeChunks=true、POST /knowledge/search。


12. 现状快照:什么被改了,什么没动

未改动:

新增:

本报告全部数字均可在本机用 §11 脚本复现。


安全声明:本报告未包含任何 API key、token 或其他凭据;配置审计中密钥一律以掩码形式呈现。