qmd
光景不待人,须叟发成丝。——李白
QMD:你的本地“记忆搜索引擎”——它不问云端要答案,只在你电脑里把一切翻出来
QMD 全名 Query Markup Documents。
它更愿意被叫作:你设备上的搜索引擎。
它的使命很朴素,但执行得很“狠”:
- 把你的 Markdown 笔记、会议纪要/转录、文档、知识库统统收进来
- 让你用 关键词 或 自然语言就能找回“我明明写过但死活想不起来在哪”的那段内容
- 并且——全程本地运行:BM25、向量语义检索、LLM 重排,统统在你电脑里完成
它对自己的定位也很直白(repo description):
mini cli search engine for your docs, knowledge bases, meeting notes, whatever.
Tracking current sota approaches while being all local
它像一只非常克制的猎犬:不依赖外网、不把你的资料丢到云上,只在你本地的文件夹里闻味道、追踪线索,然后把结果叼回来。
QMD 的脾气:它不是“只会关键词”的老搜索,也不是“只会语义”的新搜索
QMD 的骨架是一个混合检索流水线,它把三种力量编成一支队伍:
- BM25 全文检索(SQLite FTS5):快速、精准、擅长命中“你写过的词”
- 向量语义检索(semantic search):擅长理解“你想表达的意思”
- LLM Re-ranking(重排):像个严苛的编辑,把“看起来相关”重新排序成“真正有用”
而且它强调:这些都在本地跑,通过 node-llama-cpp + GGUF 模型。
它的气质更像一个“守在你资料库门口的本地总管”:
- 你问得很直:它用 BM25 秒回
- 你问得很虚:它用向量去理解
- 你问得很难:它会扩展问题、融合候选、再重排,把最值得看的放前面
Quick Start:先让 QMD 认识你的世界
QMD 是 CLI 工具,开局很干脆:装上、把资料夹登记成 collection、加点 context、做 embedding、开始搜索。
1 | # 全局安装(Node 或 Bun) |
1)给你的资料建“集合”(collections)
你可以把不同类型的内容分开管理:notes / meetings / docs……
1 | qmd collection add ~/notes --name notes |
QMD 像个图书馆管理员,先给每一排书架贴上标签:
“这边是笔记”“那边是会议”“那边是文档”。
2)给它一点“语境”(context):这是 QMD 的关键气质
QMD 有一个非常关键的能力:context 是树状的,并且会跟着结果一起返回。
它不只想给你“这段文字在哪”,它还想告诉你“这段文字属于哪个语境”。
1 | qmd context add qmd://notes "Personal notes and ideas" |
它像在每个文件夹门口挂了一块牌子:
“这片区域是什么、你当初为什么把东西放这里”。
当你把搜索结果喂给 LLM/Agent 时,这块牌子会一起被带走——这就是它对 agent workflow 很友好的原因之一。
3)生成向量 embedding(语义检索的燃料)
1 | qmd embed |
从这一刻开始,QMD 不只是“会翻关键词”,它开始“会理解意思”。
4)开始搜:三种模式,各司其职
1 | qmd search "project timeline" # 关键词(快) |
它像一个三段式的搜索专家:
search:老派但可靠,速度快vsearch:语义派,擅长“换句话也能找”query:精英派,扩展问题 + 融合候选 + LLM 重排,追求“最终答案的质量”
5)把某个文档直接“叫过来”
1 | qmd get "meetings/2024-01-15.md" |
它不仅能通过路径叫人,还能用 docid 召唤——docid 会在搜索结果里出现。
6)批量带走(multi-get)
1 | qmd multi-get "journals/2025-05*.md" |
给 AI Agents 用:QMD 会“主动把自己变成结构化上下文”
QMD 很清楚它要服务的场景:agentic workflows。
所以它的输出格式从一开始就帮你准备好两种“给模型吃的口粮”:
--json:结构化结果 + snippets--files:适合让 agent 批量拉文件/引用路径
1 | # 给 LLM 结构化搜索结果 |
它像一个懂模型饮食习惯的厨师:
“你要吃 JSON?我给你切好;你要吃文件列表?我给你配好阈值;你要整篇?我给你端上来。”
MCP Server:它不只会在命令行里跑,它还能变成你的“模型工具”
QMD 除了 CLI,还提供 MCP(Model Context Protocol)服务器,用于更紧密的工具集成。
它暴露的工具包括:
query— typed sub-queries(lex/vec/hyde)+ RRF + rerankingget— 按 path 或 docid 拿文档(带 fuzzy suggestions)multi_get— 批量拿(glob / 列表 / docids)status— 索引健康与 collection 信息
Claude Desktop 配置(macOS 例子)
~/Library/Application Support/Claude/claude_desktop_config.json:
1 | { |
Claude Code:装插件(推荐)
1 | claude plugin marketplace add tobi/qmd |
或者手动在 ~/.claude/settings.json 配置 MCP:
1 | { |
HTTP Transport:让 MCP 服务器常驻,避免反复加载模型
默认是 stdio(每个 client 启一个子进程),如果你想要共享、长生命周期、避免重复加载模型,就用 HTTP:
1 | # 前台运行(Ctrl-C 结束) |
HTTP server 暴露:
POST /mcp— MCP Streamable HTTP(JSON responses,无状态)GET /health— 存活检查 + uptime
它还很“本地派”地强调了一点:
LLM 模型会常驻在 VRAM,跨请求不卸载;embedding/reranking 的上下文空闲 5 分钟会释放,下次再透明重建(约 1 秒开销),但模型仍保持加载。
SDK / Library:QMD 还愿意当你的库,不只是一把 CLI 小刀
如果你想把它塞进自己的 Node/Bun 程序里,它也给了你干净的入口:createStore()。
安装
1 | npm install @tobilu/qmd |
Quick Start(TypeScript)
1 | import { createStore } from '@tobilu/qmd' |
它的“人格”很克制:
SDK 强制要求显式 dbPath,不做任何默认假设——你把它嵌进任何应用都不会莫名其妙往你系统里写东西。
createStore() 的三种姿势:它很会配���你的工程结构
1 | import { createStore } from '@tobilu/qmd' |
搜索的“心法”:统一 search() + 可控的子通道
QMD 给了一个统一入口 search(),既能处理简单 query,也能处理你手动展开的 structured queries。
1 | // 简单 query:自动用 LLM 展开,然后 BM25 + 向量 + 重排 |
如果你想完全掌控底层,它也给你直通车:
1 | // 纯 BM25(快,不用 LLM) |
Indexing、Embedding、Chunking:QMD 很在意“把内容切得像人类写的一样”
QMD 的 embedding 不是“随便切 900 tokens”。
它会尽量在自然边界切割,让语义单元完整:章节、段落、代码块……
1 | # 默认:regex chunking |
它还有一个让代码库更舒服的选项:AST-aware chunking(tree-sitter)。
1 | # 代码文件启用 AST-aware chunking(TS/JS/Python/Go/Rust 等) |
它的态度是:
“你把代码库交给我,我就按函数、类、import 的边界来切;你别让我拿刀乱剁。”
运行环境要求:它要你升级一点点,但换来的是全本地的强能力
系统要求(README):
- Node.js >= 22
- Bun >= 1.0.0
- macOS:需要 Homebrew SQLite(为了扩展支持)
1 | brew install sqlite |
GGUF 本地模型:QMD 的三位“本地特工”
QMD 默认会自动下载并缓存三种 GGUF 模型(第一次用的时候):
embeddinggemma-300M-Q8_0:向量 embedding(默认)qwen3-reranker-0.6b-q8_0:重排qmd-query-expansion-1.7B-q4_k_m:query expansion(微调模型)
缓存目录:
~/.cache/qmd/models/
如果你需要更好的中文/日文/韩文(CJK)覆盖:换 embedding 模型
QMD 允许用环境变量覆盖 embedding model:
1 | # 换成 Qwen3-Embedding-0.6B(多语言更强) |
QMD 的个性像个严谨的实验员:
“你可以换试剂,但换了就得重新做实验,别拿旧向量糊弄我。”
CLI 使用:collections、context、search、输出格式、维护一条龙
Collection 管理
1 | # 当前目录建一个 collection |
Context 管理
1 | # 给 collection / 路径加 context |
搜索模式
1 | qmd search "authentication flow" |
常用选项与输出格式
1 | # 返回 10 条 + 分数阈值 |
输出格式选项(search / multi-get):
--files(docid, score, filepath, context)--json--csv--md--xml
它甚至会在 TTY 场景输出可点击的终端超链接(OSC 8),并且允许你配置点击打开哪个编辑器:
1 | # VS Code |
数据存储:它把“记忆索引”关在你的本地缓存里
索引位置:
~/.cache/qmd/index.sqlite
数据库里大致包含:
- collections
- path_contexts
- documents + docid
- documents_fts(FTS5)
- content_vectors + 向量索引
- llm_cache(query expansion / rerank 缓存)
它像个很懂边界的管家:
“我只在你本地的缓存里建索引,不干扰你原始文件,也不把东西搬去别处。”
���发模式:如果你想参与它的进化
1 | git clone https://github.com/tobi/qmd |
结尾:QMD 的一句话总结
QMD 像一个不睡觉的“本地记忆检索官”:
- 你把资料放哪,它就在哪建立索引
- 你用关键词问,它用 BM25 快速命中
- 你用自然语言问,它用向量理解你真正想找的东西
- 你要高质量结果,它会扩展 query、融合候选、再用本地 LLM 重排
- 你要接入 Agent,它给你 JSON、files、MCP server、HTTP 常驻、SDK 全套接口
它不是一个“搜索工具”,它更像你电脑里的一套可控、可嵌入、可扩展的“记忆召回系统”。
License
MIT
