QMD:本地 文档 混合搜索引擎 ——95% token节省的智能解决方案

当你的 LLM 账单一路飙升,你或许会自我安慰:“没办法,上下文就是这么昂贵,这就是构建代理的必要成本。”
但事实真的如此吗?其实不尽然。
我在解决一个相当棘手的问题时发现了 QMD:如何让代理 “记住” 数千个 Markdown 文件,而不必把半个文件系统都塞进每次的提示词里?
会议纪要、项目文档、个人笔记,还有那些六个月前随手记下、如今突然变得至关重要的半成品想法 —— 这些信息的管理一直是个难题。
常规解决方案要么是 “嵌入 + 向量搜索 + 碰运气”,要么更糟:直接把所有内容一股脑塞进上下文,眼睁睁看着token像流水一样消耗。
而 QMD 采用了截然不同的思路 —— 说实话,是更聪明的思路。它将检索工作从 LLM 转移到本地设备,直接减少 95% 以上的token使用。无需依赖云服务,不用构建冗长的提示词,只需通过快速的本地搜索,就能精准地把模型需要的信息递交给它。
一、核心认知:上下文≠记忆
我们必须明确一点:LLM 并没有真正的 “记忆”,它们只有昂贵的注意力窗口。
每次你把文档粘贴到提示词中,都是在为模型重新解读 “本不该它操心” 的内容付费。这些文本中大部分信息都是无关紧要的 —— 模型其实也清楚这一点,但它仍需逐字逐句阅读。
这就是问题的核心症结:你不需要模型 “知晓一切”,你只需要它 “找到正确的信息”。
这本质上是一个搜索问题,而非提示词优化问题。而 QMD 正是基于这个认知设计的。
二、QMD 究竟是什么?
QMD 是一款本地部署的 Markdown 搜索引擎,核心特点是 “设备端运行、无云依赖”。
你只需指定目标文件夹,它就会自动索引文件并构建三大核心组件:
-
全文索引(基于 SQLite FTS5 的 BM25 算法)
-
语义搜索向量索引
-
本地 LLM 重排器(用于结果精准排序)
随后通过命令行界面(CLI)和 MCP 服务器对外提供服务,支持代理工具调用。全程无需 API 调用,不依赖任何 SaaS 服务,通过 node-llama-cpp 和 GGUF 模型实现纯本地运行 —— 这正是它的神奇之处:本地优先,token最小化。
三、快速上手指南
1. 安装 QMD
bun install -g https://github.com/tobi/qmd
2. 添加文件集合
# 个人笔记集合qmd collection add ~/notes --name notes# 会议文档集合qmd collection add ~/Documents/meetings --name meetings# 工作文档集合qmd collection add ~/work/docs --name docs
3. 添加上下文描述(帮助搜索理解场景)
qmd context add qmd://notes "个人笔记与创意想法"qmd context add qmd://meetings "会议记录与转录文本"qmd context add qmd://docs "工作相关技术文档"
4. 生成嵌入向量
qmd embed
5. 开始搜索
# 全文搜索(关键词匹配)qmd search "项目时间线"# 向量搜索(语义匹配)qmd vsearch "部署流程"# 混合查询(智能融合搜索)qmd query "季度规划流程"
就是这么简单!现在你拥有了一套不浪费token的本地 “记忆系统”。
四、混合搜索的核心价值
检索是大多数同类系统的薄弱环节,而 QMD 的混合搜索架构正是其核心优势所在。
4.1 仅用 BM25 远远不够
关键词搜索的优势是快速精准,如果你能记住确切短语,它的表现无可挑剔。但人类的思考方式并非基于关键词 —— 比如你会搜索 “我们如何再次部署这个东西”,而文档中对应的表述可能是 “生产上线程序”,这时 BM25 关键词搜索就会完全失效。
4.2 仅用向量搜索也存在局限
语义搜索固然强大,但也有明显短板:结果模糊性强,有时会返回 “略有相关性” 却偏离核心答案的内容,甚至会把完美匹配的结果淹没在 “有点相似” 的条目里。
QMD 没有选择 “二选一”,而是实现了两者的完美融合。
4.3 混合搜索流水线
以下是简化后的核心架构:
当你输入一个查询后,QMD 会通过小型本地 LLM 生成查询变体(扩展查询),然后将原始查询与变体查询同时传入两条并行通道:
-
BM25 全文搜索(精准关键词匹配)
-
向量语义搜索(模糊语义匹配)
所有搜索结果通过倒数排名融合(RRF) 算法合并,筛选出 Top 候选后,再由本地 LLM 进行重排序,最终根据结果位置进行分数加权。
这个流程看似复杂,但每个步骤都有其设计逻辑:
-
保留精准匹配结果,避免关键词搜索的遗漏
-
纳入语义匹配结果,覆盖 “意近词不同” 的场景
-
重排器负责最终筛选,修正前序步骤的偏差
QMD 的实际流程架构图如下(核心逻辑值得深入研究):
┌─────────────────────────────────────────────────────────────────────────────┐
│ QMD Hybrid Search Pipeline │
└─────────────────────────────────────────────────────────────────────────────┘
…
核心设计理念:不依赖单一搜索方法,让每种技术各司其职、优势互补。
4.4 RRF + 位置感知混合的精妙之处
大多数混合搜索系统只是简单合并分数,而 QMD 的设计更为严谨:
-
排名第一的文档会获得额外权重奖励
-
原始查询的搜索结果权重高于扩展查询
-
重排器对排名靠前的结果影响较小,对后排结果影响更大
这样设计的原因很实际:重排器虽然强大,但也可能出错 —— 尤其是当已经存在精准关键词匹配结果时,过度重排反而会适得其反。正如项目文档中所强调的:“纯 RRF 算法可能在扩展查询不匹配时,稀释精准匹配的权重”。
QMD 的设计正是为了保护这些精准匹配结果,这是有过检索系统踩坑经历后的经验总结,而非单纯的学术设计。
4.5 重排器全程本地运行
这一点至今仍让人感到惊叹:QMD 采用 qwen3-reranker-0.6B 模型,通过 node-llama-cpp 在本地运行重排逻辑。
无需 API 调用,没有网络延迟,更不会将你的私密笔记发送给第三方。重排器会输出 0-1 之间的相关性分数(基于 log 概率编码的二分类判断),且仅对 Top30 候选结果进行重排,速度极快 —— 这正是 “无token消耗却能保证搜索质量” 的关键所在。
五、为何能减少 95%+ 的token使用?
对比传统流程与 QMD 流程:
-
传统流程:将大量文档塞进提示词 → 提问 → 为无关内容支付token费用 → 重复该过程
-
QMD 流程:通过 QMD 检索 5-10 个高度相关的信息块 → 仅将这些核心内容传给 LLM → 提问
LLM 读取的内容更少,猜测的空间更小,生成的冗余信息更少 —— 回答速度更快、成本更低、质量更高。
这不是简单的优化,而是架构层面的革新。
六、QMD 与代理的集成使用
QMD 不仅是一款 CLI 工具,还提供了 MCP 服务器,允许代理将其作为工具调用。
支持的核心工具包括:
-
qmd_search(全文搜索)
-
qmd_vsearch(向量搜索)
-
qmd_query(混合查询)
-
qmd_get(获取单篇文档)
-
qmd_multi_get(批量获取文档)
-
qmd_status(查询服务状态)
接入 Claude Desktop 或 Claude Code 的配置示例:
{"mcpServers": {"qmd": {"command": "qmd","args": ["mcp"]}}}
集成后,你的代理可以实现:本地搜索 → 自主判断相关性 → 仅在需要时拉取完整文档,全程无需依赖外部服务。
七、简洁可靠的数据模型
QMD 的所有数据都存储在 SQLite 数据库中,核心表结构包括:
-
documents(文档元数据)
-
documents_fts(全文搜索索引)
-
content_vectors(向量索引)
-
llm_cache(LLM 缓存)
没有神秘的二进制大对象(blobs),没有专有格式 —— 你可以直接查看索引、备份数据、删除重建,完全可控。
索引文件路径:~/.cache/qmd/index.sqlite
坦白说,这才是工具应有的构建方式:透明、可靠、易于维护。
八、模型大小与资源占用说明
QMD 需要本地下载以下模型,资源占用情况如下:
-
嵌入模型:约 300MB
-
重排器模型:约 640MB
-
查询扩展模型:约 1.1GB
乍看之下体积不小,但对比其替代的成本(托管 LLM 一天的 API 费用可能远超这些存储成本),这些资源消耗完全值得。
毕竟,磁盘空间很便宜,而 LLM token却很昂贵。
九、QMD 的最佳适用场景
如果你的工作场景符合以下特点,QMD 会成为你的得力工具:
-
经常撰写 Markdown 文档
-
正在构建需要长期记忆的代理系统
-
重视数据隐私与安全
-
厌烦冗长的提示词膨胀问题
-
希望获得可预测的使用成本
如果你只是偶尔和 LLM 聊天,QMD 可能显得有些 “大材小用”;但如果你正在构建复杂的 AI 系统,使用后你会发现 —— 这才是最合理的架构设计。
十、总结
QMD 不仅仅是一款搜索工具,它更在传递一个核心理念:LLM 不应该成为你的数据库。
LLM 的核心价值是推理、整合与解释 —— 让它们专注于思考,把 “记忆” 的任务交给更擅长的工具。
一旦明确了这种职责划分,一切都会变得更简单、更便宜、更高效。
说实话,使用 QMD 之后,再回头把海量文档塞进提示词的做法,就像用扳手当锤子 —— 虽然偶尔能奏效,但何必如此呢?
夜雨聆风
