在个人知识管理场景中,如何高效检索散落在各处的 Markdown 笔记、会议纪要和项目文档,一直是工程师面临的实际问题。云端搜索服务虽然便捷,但数据隐私和离线可用性始终是痛点。QMD(Query Markup Documents)作为一款纯本地运行的 CLI 搜索工具,将 BM25 全文搜索、向量语义搜索和 LLM 重排序整合到同一管道中,为本地文档检索提供了接近云端质量的体验。

混合检索管道的技术拆解

QMD 的核心创新在于其混合搜索管道的精细设计。不同于简单的多路召回后直接拼接,QMD 引入了一系列精细的融合策略,确保不同检索方法的优势互补。

整个管道遵循以下流程:用户输入查询后,首先经过 LLM 进行查询扩展,生成原始查询的两个变体;随后三个查询(原始查询权重加倍)分别进入 BM25 和向量搜索两条独立路径;各路径的结果通过 Reciprocal Rank Fusion(RRF)算法融合,并对原始查询中排名靠前的文档给予额外加分;融合后的前 30 个候选文档送入 LLM 重排序;最终根据排名位置采用差异化的混合策略输出结果。

在 RRF 融合阶段,QMD 使用公式 score = Σ(1/(k+rank+1)),其中 k 参数设为 60。原始查询的权重设为 2 倍,这意味着如果用户的查询恰好匹配某文档,该文档在融合阶段会获得显著更高的分数。此外,排名第一位 的文档额外获得 0.05 加分,排名第二至三位的文档获得 0.02 加分。这一设计有效解决了查询扩展可能导致原始匹配被稀释的问题。

重排序阶段使用 qwen3-reranker-0.6b 模型,该模型以 yes/no 判定配合对数概率(logprobs)输出置信度。值得注意的是,QMD 在重排序后并非简单地采用重排序分数排序,而是引入了位置感知混合策略:排名 1 至 3 的结果以 75% 检索分数、25% 重排序分数加权;排名 4 至 10 采用 60% 对 40% 的比例;排名 11 之后则变为 40% 对 60%,更信任重排序模型的表现。这套策略既保留了精确匹配的优先性,又让语义理解能力在需要时发挥作用。

本地运行的模型配置

QMD 完全运行在本地,依赖 node-llama-cpp 加载 GGUF 格式的量化模型。默认配置下会下载三个模型:embeddinggemma-300M-Q8_0 用于生成向量嵌入(约 300MB),qwen3-reranker-0.6b-q8_0 用于重排序(约 640MB),qmd-query-expansion-1.7b-q4_k_m 用于查询扩展(约 1.1GB)。这些模型全部缓存在 ~/.cache/qmd/models/ 目录下,首次运行时会自动下载。

对于处理中文、日文或韩文文档的用户,默认的 embeddinggemma 模型在这些语言上的覆盖有限。QMD 支持通过 QMD_EMBED_MODEL 环境变量切换到 Qwen3-Embedding-0.6B,该模型支持 119 种语言包括 CJK,且在 MTEB 基准上表现优异。切换模型后需要重新执行 qmd embed -f 强制重新生成所有向量,因为不同模型生成的向量不兼容。

关于硬件要求,官方文档仅列出 Node.js >= 22 和 Bun >= 1.0.0 的软件依赖。但考虑到同时运行三个量化模型,16GB 内存是较为舒适的配置,8GB 内存下模型加载和切换会有明显延迟。M1/M2/M3 Mac 用户得益于统一内存架构,通常能获得不错的体验。

搜索命令与结果筛选

QMD 提供了三个层级的搜索命令,分别对应不同的质量与速度权衡。qmd search 仅执行 BM25 全文检索,响应速度最快,适合需要即时反馈的交互场景。qmd vsearch 仅执行向量语义搜索,能够捕捉语义相似但词汇不匹配的内容。qmd query 则是完整管道,包含查询扩展、混合检索和重排序,搜索质量最高但延迟也最大。

在实际工程实践中,建议根据场景选择合适的命令。对于快速定位一个已知关键词的文件,search 足够;若要查找概念相关但表述不同的内容,换用 vsearch;当需要最优结果且可等待数秒时,使用 query

结果筛选方面,-n 参数控制返回数量(默认 5,JSON 或 files 模式下默认 20),--min-score 设置最低分数阈值(0.0 到 1.0)。分数的解读可以参考:0.8 以上为高度相关,0.5 到 0.8 为中等相关,0.2 到 0.5 为部分相关,0.2 以下为低相关。对于需要批量处理的自动化流程,添加 --json--files 参数可以获得结构化输出。

与 AI Agent 的集成能力

QMD 从设计之初就将 AI Agent 场景纳入考量。除了 CLI 接口,它还内置了 Model Context Protocol(MCP)服务器支持。配置方式极为简洁:在 Claude Desktop 或 Claude Code 的配置文件中添加 qmd 的 MCP 服务器即可。通过 MCP 协议,Agent 可以直接调用 querygetmulti_getstatus 四个核心工具,实现对话式文档检索。

对于需要长期运行的服务场景,QMD 支持 HTTP 传输模式的 MCP 服务器。启动 qmd mcp --http --daemon 后,模型会常驻内存(默认为 5 分钟空闲后卸载),避免每次请求重新加载模型带来的延迟。HTTP 端点遵循 MCP Streamable HTTP 规范,可被任何兼容的 MCP 客户端访问。

如果需要在自有应用中深度集成,QMD 也提供了 SDK 形式的 Node.js/Bun 库。通过 createStore() 创建存储实例后,可以程序化地管理集合、执行搜索和获取文档。SDK 模式下同样支持自定义配置、分集合管理和上下文添加等高级功能。

集合管理与索引优化

QMD 以集合(collection)为单位管理文档源。一个集合对应文件系统上的一个目录,通过 glob 模式匹配目标文件类型。添加集合的典型命令如 qmd collection add ~/notes --name notes,默认会匹配目录下所有 .md 文件。也可通过 --mask 参数指定其他模式,例如 --mask "**/*.md"--mask "**/*.txt"

索引更新通过 qmd update 命令执行,该命令会扫描集合目录下的文件,与已有索引对比后增量更新。对于使用 Git 管理的内容,--pull 参数会在更新前先执行 git pull,保持本地与远程同步。

向量嵌入的生成独立于索引更新,需要单独执行 qmd embed。默认的分块策略是 regex,通过评分算法在 900 tokens 附近寻找自然断点(标题、代码块、水平分隔符等)。对于代码文件,可以启用 --chunk-strategy auto 开启 AST 感知分块,利用 tree-sitter 解析代码结构后在函数、类和导入声明边界处切分,这对搜索具体代码实现尤为有效。

工程落地的关键参数

将 QMD 集成到日常工作流时,以下参数值得特别关注。首先是环境变量 QMD_EMBED_MODEL,中文用户建议设置为 hf:Qwen/Qwen3-Embedding-0.6B-GGUF/Qwen3-Embedding-0.6B-Q8_0.gguf 并重新嵌入。其次是 QMD_EDITOR_URI,配置编辑器 URI 模板后,搜索结果中的文件路径可直接点击跳转,支持 VS Code、Cursor、Zed 和 Sublime Text 等主流编辑器。

在搜索命令层面,批量导出场景推荐组合使用 --json --all --min-score 0.3 -n 50 获取足量结果后再程序化筛选。对于 MCP 集成场景,启动 HTTP 模式时可通过 --port 指定端口,通过 --daemon 实现后台常驻。

整体而言,QMD 作为一个纯本地的 CLI 搜索工具,在保持数据隐私和离线可用性的前提下,通过精细的混合检索管道实现了接近云端搜索质量的结果。对于需要管理大量 Markdown 笔记、会议纪要和项目文档的工程师,或希望为 AI Agent 提供私有知识库检索能力的团队,QMD 提供了一个无需依赖外部服务的高质量解决方案。

资料来源:https://github.com/tobi/qmd