收藏有大约 120 万册中文书目。数量一大,找书这件事就从「翻目录」变成了「大海捞针」。
原来的检索,卡在哪?
以前主要靠书名、作者、出版社这些字段做关键字匹配。逻辑简单,也稳定,但用起来总有几处别扭:
搜「汽车」,书名里没这两个字的书就进不来——比如讲智能驾驶、车联网的,明明相关,却排在结果之外。反过来,搜「跨学科」可能涌出一堆只是沾边的书,真正讲「历史学科跨学科教学」的反而沉在下面。
更麻烦的是,120 万册里混着大量小说、网文、言情武侠。做资料检索时,你明明想找教材、研究、手册,结果前面几页全是虚构作品,得手动筛半天。
这不是软件 bug,是「字面匹配」和「人真正想找什么」之间本来就有鸿沟。书名往往很短,简介又经常缺失;就算有简介,关键字匹配也理解不了「和 XX 主题相关」这种意思。
思路:让机器先「读懂」,再「找像的」
这次给 ZBooks 加语义检索,核心就一句话:用自然语言描述需求,按内容含义找书,而不是死抠书名里的字。
比如输入「历史学科的跨学科教学方法」,或者「汽车与智能驾驶技术相关的书」。系统先把这句话变成向量,再到本地向量库里找语义相近的书——书名里一个字都不撞,也有机会被捞出来。
几个原则从一开始就定死了:
- 全部在本机跑。向量化和检索都走本地 Ollama 和本地向量库,书目不往外传。
- 不动原有功能。语义检索只是多一条路;原来的筛选、收藏、阅读、导出照旧,检索结果直接进主表格,还能按相关度排序。
- 小说可以关。虚构类过滤做成选项,默认排除明确的小说,学术检索时不被网文淹没;拿不准的书保留,用户自己决定要不要看。
硬件上按 RTX 3060 12GB 这类常见配置来设计,不指望用户上云 API。
具体怎么做的
离线:先把 120 万册「翻译」成向量
语义检索不能每次查询都现算 120 万次,所以第一步是建索引,一次性、可挂机、可断点续传。
对库里所有中文书(language 为 chinese,大小写不敏感),把书名、作者、出版社、丛书、简介拼成一段文本,去掉 HTML 标签,截到合适长度,交给本地的 bge-m3 模型做向量化。每本书得到一条 1024 维向量,写入单独的 vectors.db。
建库是批量的,每批几十本,窗体上能看到进度、吞吐量和预估剩余时间。中断了下次接着跑;书的信息改了、或者换了向量模型,靠内容哈希做增量更新,不用从头再来。
120 万册完整向量大概占 6GB 量级,加上索引和日志,磁盘最好留 20GB 以上。百万级全量建库建议夜跑,具体多久看机器,不拍脑袋承诺「几小时一定完」。
在线:粗排、精排、再精排
查询时流程分三层,每层干不一样的事:
- 查询向量化——用户输入的那句话,同样用 bge-m3 变成向量。
- 粗排——在 sqlite-vec 里用二进制向量做全库扫描,先捞出大约 2000 本候选。百万级没有现成 ANN 索引,暴力扫是现实选择;二进制表示是为了在这一步省时间和磁盘。
- 精排——从库里读出这 2000 本的完整 float 向量,在 C# 内存里算余弦相似度,缩到 200 本。
- 重排序(可选)——再交给 bge-reranker-v2-m3,对「历史跨学科教学」和「别的跨学科」这种细差别做最后一轮比对。重排序服务没开也不影响检索,只是少一层精度,自动降级为纯向量排序。
虚构类过滤在粗排阶段就生效:明确标成小说的书,默认不进候选集。
小说怎么认:规则 + 小模型 + 本地大模型
书库里没有「是不是小说」字段,得自己打标。三层做法,成本从低到高:
第一层,规则。 只在高置信度词上动手——「网络小说」「玄幻」「教程」「手册」「导论」这类,几乎不会搞错的才判。像「文集」「传记」这种边界词 故意不放进规则,宁可少标,不可错标。
第二层,主力。 索引阶段每本书已经有向量了,复用即可。用本地 qwen3:8b 对分层抽样的约 5000 本书做虚构/非虚构标注,训练一个 1024 维的逻辑回归分类器,然后对全库 120 万条向量批量推断——几分钟跑完,不用每本书再过一遍大模型。
第三层,兜底。 分类器把握不够的书,标成「不确定」,检索时默认仍可见;用户也可以选「仅非虚构」,把不确定的一并排除。
《小说创作教程》这类边界情况 难免有误判,所以过滤只影响检索展示,不改书目数据,标注修正后可以重跑分类,还是分钟级。
界面与接入
Ribbon 上加了两个入口:语义索引(建库、虚构打标)和 语义检索(自然语言查询)。检索结果带「相关度」列,有序 ID 列表灌回主窗体原有的 原有查询逻辑,收藏、打开、导出不用重写一套。
打开检索前会做环境自检:Ollama 在不在、向量模型拉没拉、vec0 扩展能不能加载、库里有没有索引。缺 rerank 只提示降级,不拦着用。
用起来是什么感觉
部署上:装 Ollama,执行 ollama pull bge-m3;可选再开一个 llama-server 跑重排序模型。然后在软件里点「语义索引」,等建库完成。
之后日常就是:点「语义检索」,输入搜索意图(例如:儿童心理学相关书籍),等几秒到十几秒(首次会慢一些,模型和磁盘缓存热起来会快很多),结果按相关度排在主表里。想回到传统筛选,点「清除条件」就行。
和传统 LIKE 比,语义检索赢在「意图」——跨词、跨表述、跨学科边界,更像人找书时的联想。关键字检索仍然保留,精确查书名、作者时还是它更直接。
小结
120 万册中文书的痛点,本质是字面搜索理解不了人真正想找什么,再加上虚构与非虚构混在一起。
解法不是上云、也不是把 SQLite 换成重型搜索引擎,而是在现有 ZBooks 架构上,用本地向量化 + 向量库 + 可选重排序,把「自然语言找书」做成一条完整链路:离线建索引、在线三级检索、可开关的小说过滤、结果无缝接回主界面。
第一次建库要花时间,磁盘和显卡也要有一点余量。但建完之后,搜「智能驾驶」不必再碰运气拼关键字,搜教学参考书也不必从网文堆里往外扒——对本地超大书库来说,这一步值得。
评论