2026-04-29 · 架构
32
架构 · 2026-04-29

QMD 实战:让 Agent 的知识检索从 grep 升级到 BM25+向量混合搜索

Agent 有个老问题:它知道怎么写代码、怎么查资料、怎么调用工具,但它不知道你自己的东西在哪里。

我说的不是联网搜索——Google 和 Bing 它已经会用了。我说的是你自己沉淀下来的那堆 Markdown:项目文档、SOP、会议纪要、故障排查记录、个人笔记。这些东西分散在十几个目录里,几百个 .md 文件,Agent 想找东西的时候,通常只能靠 rggrep 翻一遍。

问题在于,grep 只做字面匹配。"扫地机器人激光雷达偏移" 和 "SLAM 建图漂移" 说的可能是同一件事,但 grep 认为它们毫无关系。

我最近开始用 QMD 来解决这个问题。它是 Query Markup Documents 的缩写——一个专门给 Markdown 目录建检索索引的本地工具。下面是我跑通之后的完整记录。

QMD 做了什么

给一个 Markdown 目录,建一个带 BM25 全文检索 + 向量语义搜索 + 混合检索的本地索引库。

Markdown 目录 → QMD 索引库(SQLite) → Agent 或人来检索

它不替代 LLM。它只负责"找到最相关的文档",最后整理成人话答案还是 LLM 的事。

核心卖点就两个:

  1. BM25 搜索:带相关度排序的关键词检索,比 LIKE 强,比 grep 强
  2. 向量搜索:按语义找相似内容,能处理同义词、近义词和表述差异

两种模式还可以混合用(query 命令),自动做查询扩展 + BM25 + 向量 + rerank。

建索引

假设你的知识库目录是 /path/to/kb,先建一个独立的索引库(我给它起名叫 kb):

qmd --index kb collection add /path/to/kb --name kb --mask "**/*.md"

这条命令只是告诉 QMD"资料在哪里",它不会改你的 Markdown 文件。

然后刷新文本索引:

qmd --index kb update

这时候 BM25 搜索就能用了。如果你还想要语义搜索能力(推荐),再生成向量:

qmd --index kb embed

embed 会用本地 embedding 模型(默认是 embeddinggemma-300M Q8 量化版)把文档切块转成向量。它不是聊天模型,不回答问题,只是为语义检索准备数据。

查看当前状态:

qmd --index kb status

关于 --index 参数:它指定的是一个 SQLite 数据库,不是你的 Markdown 目录。QMD 的索引库里大概有这些东西:

kb.sqlite
├─ collections      注册过哪些目录
├─ documents        文件路径、标题、hash
├─ documents_fts    BM25 全文检索索引
├─ content_vectors  文档切块后的文本片段
├─ vectors_vec      向量检索索引
└─ llm_cache        查询扩展和 rerank 的缓存

如果你还有其他服务(比如 OpenClaw)也在用 QMD,建议给自己的目录单独起 index 名字,互不干扰。

三种搜索模式

QMD 提供三种搜索方式,适用场景不同。搞清楚什么时候用哪个,能省很多时间。

search:BM25 关键词检索

qmd --index kb search "扫地机器人 激光雷达偏移" -c kb

BM25 会在意关键词出现了几次、关键词是否稀有、文档长度、多词是否都命中,最后算出一个相关度分数。

白话说:grep 回答"有没有这串字",BM25 回答"哪个文档最像你要找的"。

适用场景:

明确的故障关键词
告警码 / 错误码
产品名 / 型号
SOP 标题
文档名

任何你确切知道"文档里应该有这些词"的时候,用 search 就够了。

vsearch:向量语义检索

qmd --index kb vsearch "设备建图时位置一直飘怎么排查" -c kb

即使文档里没有"位置飘"这三个字,只要语义相近(比如写的是"SLAM 建图漂移""定位偏移""地图失真"),向量搜索也能找出来。

适用场景:

自然语言描述的问题
你不确定文档里具体怎么写的
需要找"意思接近但表述不同"的内容

query:混合检索

qmd --index kb query "设备建图时位置一直飘怎么排查" -c kb

混合检索会做四件事:查询扩展 → BM25 搜索 → 向量搜索 → rerank 重新排序。

听起来最强大,但有个坑:对于很短的中文故障词,查询扩展可能把你带到沟里去。比如你搜"偏移",它可能扩展成完全无关的方向。

这种时候退回 search 反而更好。

搜索结果怎么看

默认的搜索输出可能看起来很简略:

title: SLAM 建图漂移排查 SOP
tags: [product, sop, slam, drift]

这不是 bug。QMD 默认只展示一个很短的 snippet。如果命中了文件头部的 YAML tags,就只显示文件头。

这个结果仍然有用——它告诉你:最相关的文件是哪个、相关度多少、docid 是什么、命中位置在哪。

两个方案:

方案一:先搜后读。search 找到文件,再用 get 读全文:

qmd --index kb search "激光雷达偏移" -c kb --files -n 10
qmd --index kb get "#docid"

方案二:让搜索直接吐更多内容。

qmd --index kb search "激光雷达偏移" -c kb --full --md -n 3

与 LLM 配合的正确姿势

QMD 自己不会给你整理出一段人话答案。它的定位是检索层,不是问答层。

完整的 Agent 知识检索流程应该是:

QMD search → QMD get → LLM 总结

具体操作:先用 QMD 搜索定位最相关的文档,把原文取出来,拼成 prompt 丢给 LLM:

基于下面这份文档,回答:"扫地机器人激光雷达偏移怎么处理?"
请按场景、原因、处理方式整理成简明 SOP。

[QMD 取回的文档内容]

这样做的好处是:LLM 的回答有了坚实的文档支撑,不容易编造。而且你清楚地知道答案来自哪篇文档,可以追溯验证。

判断规则速查

实际使用中,选搜索模式的决策很简单:

明确关键词 / 故障码 / 型号  →  search
自然语言问题               →  vsearch 或 query
短中文故障词(2-4字)      →  search(别用 query,扩展容易跑偏)
要最终答案                 →  QMD 找文档 + LLM 写答案
要看原文                   →  get

一个稳妥的默认命令组合:

# 找文件
qmd --index kb search "故障关键词" -c kb --files -n 10
# 读文档
qmd --index kb get "qmd://kb/docs/target-file.md"

常用命令速查

# 创建 collection
qmd --index kb collection add /path/to/kb --name kb --mask "**/*.md"

# 刷新关键词索引
qmd --index kb update

# 生成语义向量
qmd --index kb embed

# 查看状态
qmd --index kb status

# BM25 关键词搜索
qmd --index kb search "关键词" -c kb

# 向量语义搜索
qmd --index kb vsearch "自然语言问题" -c kb

# 混合检索
qmd --index kb query "自然语言问题" -c kb

# 读取文档
qmd --index kb get "#docid"
qmd --index kb get "qmd://kb/path/to/file.md"

# 搜索并输出更多内容
qmd --index kb search "关键词" -c kb --full --md -n 3

# 搜索只列文件
qmd --index kb search "关键词" -c kb --files -n 10

最后说一点

BM25 + 向量混合检索不新鲜,RAG 系统做了好几年了。QMD 的区别在于它是本地的、轻量的、专门给 Markdown 目录设计的——不需要 Elasticsearch 集群,不需要向量数据库服务,一个 SQLite 文件搞定。

对个人和小团队,够用了。

目录 最新
← 左侧翻上一屏 · 右侧翻下一屏 · 中间唤出菜单