
当你的 LLM 账单飙升,你告诉自己,好吧,好吧,上下文是昂贵的,但这就是构建代理的成本。
是的。结果是......不完全是。
我在尝试解决一个非常无聊的问题时遇到了 QMD:如何让一个代理"记住"数千个 Markdown 文件,而不是把半个文件系统塞进每个提示?
会议笔记。文档。个人笔记。六个月前突然又重要的随机半成品想法。
通常的答案是嵌入 + 向量搜索 + 祈祷。或者更糟,只是把一切都塞进上下文,然后看着令牌蒸发。
QMD 做了不同的事情。老实说,更聪明。
它通过将检索从 LLM 转移到你的机器上,减少了 95%+ 的令牌使用。没有云。没有巨大的提示。只是快速的本地搜索,把模型需要的东西精确地递给它。
1、真正的问题:上下文不是记忆
让我们说清楚。
LLM 没有记忆。它们有昂贵的注意力窗口。
每次你把文档粘贴到提示词中,你都在为重新解释模型本来不应该想到的东西付费。大部分文本是无关的。模型知道这一点。但它仍然必须阅读它。
这是核心挫折。
你不希望模型知道一切。 你希望它找到正确的东西。
这是一个搜索问题。不是提示问题。
QMD 这样对待它。
2、QMD 到底是什么
QMD 是一个设备上的 Markdown 搜索引擎。
你指向文件夹。它索引你的文件。它构建:
- 一个全文索引(通过 SQLite FTS5 的 BM25)
- 一个用于语义搜索的向量索引
- 一个本地 LLM 重新排序器 来正确排序结果
然后它通过 CLI 和代理可以使用的 MCP 服务器暴露所有这些。
没有 API 调用。没有 SaaS 依赖。一切都通过 node-llama-cpp 和 GGUF 模型在本地运行。
这就是神奇之处。本地优先。令牌最后。
3、快速开始
安装它:
bun install -g https://github.com/tobi/qmd
添加你的集合:
qmd collection add ~/notes --name notes
qmd collection add ~/Documents/meetings --name meetings
qmd collection add ~/work/docs --name docs
添加一些上下文,让搜索理解这是什么:
qmd context add qmd://notes "Personal notes and ideas"
qmd context add qmd://meetings "Meeting transcripts and notes"
qmd context add qmd://docs "Work documentation"
生成嵌入:
qmd embed
现在搜索:
qmd search "project timeline"
qmd vsearch "how to deploy"
qmd query "quarterly planning process"
就是这样。你现在有一个不燃烧令牌的本地记忆系统。
4、为什么混合搜索实际上很重要
让我们谈谈检索,因为这是大多数系统崩溃的地方。
4.1 仅 BM25 不够
关键词搜索快速而精确。如果你记得确切的短语,它是无可匹敌的。
但人类不是用关键词思考的。你会输入:
"我们如何再次部署这个东西"
文档说:
"生产上线程序"
BM25 会错过这个。
4.2 仅向量搜索也不够
语义搜索很好......直到它不好。
它是模糊的。它有时会返回看起来略微相关但却错过你想要的确切答案的结果。更糟糕的是,它可以将完美的匹配埋藏在"有点相似"的下面。
QMD 不选边。
它两者都做。
4.3 混合管道
这是架构,简化后是这样的。
你输入一个查询。
QMD 使用一个小型本地 LLM 生成查询扩展。
每个查询(原始 + 变体)运行通过:
- BM25 全文搜索
- 向量语义搜索
所有结果使用倒数排名融合 (RRF) 合并。
顶级候选由本地 LLM 重新排序。
最终分数根据位置混合。
这听起来很复杂。但每个步骤都有原因。
这是来自项目的实际管道图,值得凝视:
┌─────────────────────────────────────────────────────────────────────────────┐
│ QMD Hybrid Search Pipeline │
└─────────────────────────────────────────────────────────────────────────────┘
...
关键想法:不要让任何单一方法主导。
精确匹配被保留。语义匹配被包含。重新排序器在最后清理混乱。
4.4 为什么 RRF + 位置感知混合是聪明的
大多数混合系统简单地组合分数并希望最好。
QMD 更谨慎。
- 排名第一的文档获得奖励。
- 原始查询结果比扩展的权重更大。
- 重新排序器在顶部的影响力较小 ,在后面的影响力较大 。
为什么?
因为重新排序器很强大,但它们可能会出错。特别是当一个精确的关键词匹配已经命中时。
文档中的这句话说明了一切:
纯 RRF 可以在扩展查询不匹配时稀释精确匹配。
所以 QMD 保护那些匹配。
这不是学术的。这是被检索系统烫过的人。
4.5 重新排序器在本地运行
这仍然是感觉疯狂的部分。
QMD 使用 qwen3-reranker-0.6B ,通过 node-llama-cpp 在本地运行。
没有 API。没有延迟轮盘赌。没有把你的笔记发送给第三方。
重新排序器输出一个基于编码为 log 概率的 yes/no 相关性判断的 0 到 1 之间的分数。
而且因为它只重新排序 top 30 候选,它很快。
这就是你如何在没有令牌泄漏的情况下获得质量的方法。
5、为什么令牌使用减少 95%+
想想旧的流程:
-
把文档塞进提示词
-
问问题
-
为每个无关的令牌付费
-
永远重复
现在比较这个:
-
使用 QMD 检索 5-10 个高度相关的块
-
只把那些传给 LLM
-
问同样的问题
LLM 读得更少。猜得更少。废话更少。
它回答得更快。更便宜。更好。
这不是优化。这是架构。
6、将 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"]
}
}
}
现在你的代理可以:
- 本地搜索
- 决定什么是相关的
- 只在需要时拉取完整文档
7、数据模型是无聊的
一切都在 SQLite 中:
documentsdocuments_ftscontent_vectorsllm_cache
没有神秘的 blobs。没有专有格式。
你可以检查索引。备份它。删除它并重建。
索引在这里:
~/.cache/qmd/index.sqlite
诚实地讲,这才是更多工具应该构建的方式。
8、关于模型和大小的简要说明
是的,QMD 下载模型。本地的。
- 嵌入:~300MB
- 重新排序器:~640MB
- 查询扩展:~1.1GB
这听起来很大,直到你记得你在替换什么。
在托管 LLM 上糟糕的一天,你会花费比这更多的 API 成本。
磁盘便宜。令牌不是。
9、这种方法真正有效的场景
如果你是以下情况,这个设置会很出色:
- 写很多 Markdown
- 构建需要长期记忆的代理
- 关心隐私
- 讨厌提示词膨胀
- 想要可预测的成本
如果你只是和 LLM 聊天,这可能感觉过度。
但如果你在构建系统......事后感觉显而易见。
10、结束语
QMD 不仅仅是一个搜索工具。
它提醒你 LLM 不应该是你的数据库。
它们是推理者。综合者。解释者。
让它们思考。 让其他东西记住。
一旦你分离了这些职责,一切都变得更容易。更便宜。更平静。
诚实地讲,使用这个之后,把巨大的提示词塞进去感觉像用扳手作为锤子。
它能工作。但你为什么要?
原文链接:QMD:本地MD混合搜索引擎 - 汇智网