How tobi/qmd Works
QMD定位为一个专业的、面向开发者和高级用户的本地知识管理搜索引擎。与依赖云服务的笔记应用(如Notion、Evernote)相比,QMD的核心优势是完全的隐私保障和零运营成本。与简单的本地文件搜索工具(如grep或系统自带搜索)相比,QMD提供了结合关键词(BM25)、语义向量和LLM重排的复杂混合搜索技术,实现了远超传统工具的搜索质量和相关性。它本质上是将企业级搜索技术“下放”到个人设备,并为AI智能体(Agent)的本地化运行提供了关键的“外部知识库”能力。
Overview
QMD定位为一个专业的、面向开发者和高级用户的本地知识管理搜索引擎。与依赖云服务的笔记应用(如Notion、Evernote)相比,QMD的核心优势是完全的隐私保障和零运营成本。与简单的本地文件搜索工具(如grep或系统自带搜索)相比,QMD提供了结合关键词(BM25)、语义向量和LLM重排的复杂混合搜索技术,实现了远超传统工具的搜索质量和相关性。它本质上是将企业级搜索技术“下放”到个人设备,并为AI智能体(Agent)的本地化运行提供了关键的“外部知识库”能力。
为个人和AI智能体提供一个完全在本地设备上运行的、无需联网的混合搜索引擎,用于索引和查询私人的Markdown笔记、文档和知识库,确保数据隐私和即时访问。
How It Works: End-to-End Flows
用户执行一次高质量的本地混合搜索
此流程描述了用户使用QMD核心的混合搜索功能的全过程,这是产品的核心价值所在。用户输入一个自然语言查询,期望系统能理解其意图并返回最相关的文档。系统在后台启动一个复杂的AI增强流程:首先通过本地LLM扩展用户的查询以覆盖更多相关表达;然后并行执行关键词和语义两种召回策略,从不同维度捕捉相关文档;接着通过一个精巧的融合算法合并结果,并突出高置信度的匹配;最后,再由另一个LLM对前30个结果进行精排,并根据结果在初始列表中的位置动态调整权重,最终呈现给用户一个经过多重AI技术优化的高质量排序列表。整个过程完全在本地完成,保障了隐私和速度。
- 用户在终端输入混合搜索命令
- 系统使用本地LLM对查询进行扩展
- 系统并行执行关键词搜索和向量搜索
- 系统对多路搜索结果进行融合、加权和奖励
- 系统筛选出Top 30候选结果,并交由本地LLM进行重排序
- 系统根据位置感知策略,混合初始分数和重排分数,生成最终排序
- 系统在终端以友好格式展示最终结果
AI智能体通过MCP协议查询并使用知识库
该流程展示了QMD作为AI智能体(如Claude)的“外部大脑”如何工作。当AI需要本地知识时,它通过模型上下文协议(MCP)向QMD发起工具调用。例如,AI可以调用 `qmd_query` 工具并提供一个问题。QMD执行其复杂的本地混合搜索,并将结果以结构化的JSON格式返回给AI。AI解析JSON,可能会选择最相关的结果,并通过其文档ID(如 `#abc123`)或 `qmd://` URI调用 `qmd_get` 工具来获取该文档的全文。这个闭环使得AI能够自主地在用户的私有知识库中进行研究和检索,而所有数据和计算都保留在本地,为构建强大的个性化AI助手奠定了基础。
- AI智能体启动并连接到QMD的MCP服务器
- AI智能体调用 `qmd_query` 工具并传入自然语言查询
- QMD返回结构化的JSON搜索结果给AI
- AI解析结果,并决定获取某个特定文档的全文
- AI调用 `qmd_get` 工具,并传入从上一步获得的文档ID或路径
- QMD返回完整的文档内容,AI将其用于后续任务
用户首次配置并索引一个新的知识库
此流程描绘了新用户从零开始使用QMD的完整引导过程。首先,用户通过 `collection add` 命令,将一个包含其Markdown文件的本地目录注册为一个新的“集合”。接着,用户运行 `update` 命令,QMD会遍历该目录,解析所有文档,基于内容哈希进行去重存储,并自动构建全文检索索引。为了启用更强大的语义搜索,用户最后需要运行 `embed` 命令。此时,QMD会自动下载所需的嵌入模型(如果本地没有),然后将所有文档内容分块、向量化,并创建向量索引。完成这三步后,用户的本地知识库就完全准备就绪,可以体验QMD提供的所有搜索功能了。
- 用户使用`collection add`命令添加一个本地笔记目录
- 用户运行`update`命令,系统扫描文件并构建关键词索引
- 用户运行`embed`命令以开启语义搜索功能
- 系统自动下载并缓存所需的本地嵌入模型
- 系统将所有文档内容进行分块和向量化,并构建向量索引
Key Features
知识库管理与索引
此模块负责将用户本地的Markdown文件转化为一个可被高效搜索的结构化索引。设计核心是“内容寻址存储”与“自动化索引同步”。首先,它通过对文件内容计算哈希值来识别和存储唯一的文档,避免了重复内容造成的空间浪费。其次,利用数据库触发器,任何文件的增、删、改都会自动更新全文搜索引擎的索引,无需用户手动干预,保证了搜索的时效性。用户还可以为不同的文件集合(Collection)或路径添加描述性上下文,帮助搜索引擎更好地理解内容。
- 多源文件集合管理 — 【设计策略】允许用户将散落在不同目录下的文件聚合为逻辑上的“集合”,并进行统一管理和索引。 【业务逻辑】 1. 用户通过命令行指定一个本地目录路径,并为其命名,从而创建一个“集合”。 2. 可以为每个集合指定特定的文件匹配规则(Glob模式),例如只包含`.md`后缀的文件。 3. 系统将这些集合的元数据(名称、路径、匹配规则)记录在中心配置文件中。 4. 后续的索引、搜索等操作都可以通过集合名称来限定范围。
- 内容寻址与增量索引 — 【设计策略】采用基于内容哈希的存储机制,实现内容去重和高效的增量更新,同时通过数据库触发器自动化维护全文检索索引。 【业务逻辑】 1. **内容哈希**:当索引一个文件时,系统首先计算文件内容的哈希值。 2. **去重存储**:该哈希值作为内容的唯一标识符。如果哈希已存在于数据库中,则不再重复存储内容;仅在文件映射表中创建一个新的指向该内容的记录。 3. **文件映射**:`documents`表记录了文件路径、所属集合、标题等元数据,并通过外键关联到`content`表中的哈希值。 4. **自动同步FTS索引**:在`documents`表上设置了数据库触发器。当有新文件被插入、更新或删除时,对应的全文检索(FTS)索引表会自动进行同步,无需应用层面执行额外的索引命令。
- 上下文元数据标注 — 【设计策略】允许用户为集合或特定路径添加自然语言描述作为“上下文”,为后续的语义搜索和LLM重排提供更丰富的背景信息。 【业务逻辑】 1. 用户可以为一个集合(如 `qmd://notes`)或集合内的具体路径(如 `qmd://docs/api`)添加一段描述性文本。 2. 这些上下文信息被存储起来,并在搜索结果展示时附带显示,帮助用户或AI理解文档的背景。 3. 虽然当前版本主要用于展示,但这个设计为未来利用上下文信息优化查询或重排分数提供了基础。
本地混合搜索引擎
这是产品的核心,提供三种不同层次的搜索能力。从快速的关键词匹配,到理解语义的向量搜索,再到融合两者并由大语言模型精炼的最高质量混合搜索。整个复杂的搜索流程,包括查询扩展、多路召回、结果融合和重排,完全在用户本地设备上完成。其设计精髓在于通过一个精巧的多阶段流水线,在保证结果质量的同时,兼顾了本地运行的性能和资源限制。
- 关键词搜索 (BM25) — 【设计策略】提供基于BM25算法的快速、精准的全文检索功能,适用于用户明确知道关键词的场景。 【业务逻辑】 1. **查询处理**:将用户输入的查询语句按空格分割,对每个词进行清理(只保留字母、数字、撇号)并转为小写。 2. **查询构建**:将清理后的词条构造成一个FTS5的MATCH查询。单个词条变为 `"term"*`(前缀匹配),多个词条用 `AND` 连接。 3. **执行与评分**:在全文检索表 `documents_fts` 中执行查询,使用 `bm25(documents_fts, 10.0, 1.0)` 函数计算相关性分数。 4. **分数归一化**:将原始的BM25分数(通常为负数,绝对值越小越相关)通过公式 `Score = 1 / (1 + abs(bm25_score))` 转换为0到1之间的统一分数,越高越好。
- 语义搜索 (向量) — 【设计策略】利用文档和查询的向量嵌入,实现基于语义相似度的搜索,能够找到概念相近但用词不同的内容。 【业务逻辑】 1. **前置检查**:检查向量索引表(`vectors_vec`)是否存在,若不存在则直接报错,提示用户需要先生成嵌入。 2. **查询向量化**:将用户查询文本格式化为 `task: search result | query: {query}` 的形式,然后调用本地嵌入模型生成查询向量。 3. **向量检索**:在 `vectors_vec` 表中执行向量匹配查询,召回 K * 3 个最相似的候选结果(K为用户请求数量)。 4. **元数据获取与去重**:由于向量索引和文档元数据分离,需要根据召回结果的ID,再去查询文档的详细信息。然后按文档路径进行去重,每个文档只保留其最匹配的文本块(相似度最高)。 5. **分数转换**:将向量的余弦距离转换为0到1的相似度分数 `Score = 1 - distance`。
- 旗舰混合搜索 (Hybrid Query) — 【用户价值】为用户提供最高质量的搜索结果,结合了关键词的精确性和语义的模糊性,并通过LLM进行最终排序,最有可能找到用户真正想要的内容。 【设计策略】采用一个复杂的多阶段流水线,融合了查询扩展、并行检索、结果融合、LLM重排和位置感知加权,以实现最佳的搜索效果。 【业务逻辑】 1. **Step 1: 查询扩展**:将用户的原始查询发送给本地的查询扩展模型,生成2个语义上相关但表达方式不同的新查询。 2. **Step 2: 并行检索 (多路召回)**:将原始查询和2个扩展查询,分别同时提交给“关键词搜索”和“语义搜索”。此步骤会产生 3 x 2 = 6 个独立的、按相关性排序的文档列表。 3. **Step 3: 结果融合 (RRF)**:使用“倒数排名融合”(Reciprocal Rank Fusion)算法将这6个列表合并成一个。为了突出原始意图,原始查询产生的两个列表(关键词和语义)的权重被设为2倍。同时,为在任何列表中排名第一的文档提供 `+0.05` 的分数奖励,排名2-3的获得 `+0.02` 奖励,以保护高置信度的匹配结果。 4. **Step 4: 候选集筛选**:从融合后的列表中选取分数最高的30个文档作为最终候选集。 5. **Step 5: LLM重排**:将这30个候选文档及其内容摘要,交给一个本地的“重排”语言模型。该模型会对每个文档与原始查询的匹配度进行打分(是/否的判断加置信度)。 6. **Step 6: 位置感知分数融合**:最终的文档分数,是“RRF融合分数”和“LLM重排分数”的加权平均。这个权重是动态的: - 对于排名 1-3 的文档:`最终分 = 75% RRF分 + 25% LLM分` (更信任初始检索结果) - 对于排名 4-10 的文档:`最终分 = 60% RRF分 + 40% LLM分` - 对于排名 11+ 的文档:`最终分 = 40% RRF分 + 60% LLM分` (更信任LLM的判断) 7. **Step 7: 返回结果**:根据最终分数排序后,将结果呈现给用户。
本地AI能力引擎
该模块是QMD实现高质量语义搜索和混合搜索的“大脑”。它负责管理在本地运行的多个小型语言模型,包括自动下载、缓存和资源回收。这些模型分别承担文档向量化(Embedding)、查询意图扩展(Query Expansion)和搜索结果精排(Re-ranking)等关键任务,将AI能力无缝集成到本地搜索流程中。
- 文档向量化生成 — 【设计策略】将长文档分割成带有重叠的、固定大小的文本块,并以特定格式输入给本地嵌入模型,生成用于语义搜索的向量。 【业务逻辑】 1. **识别任务**:系统扫描数据库,找出所有尚未生成向量的文档。 2. **文本分块 (Chunking)**:将每个文档的全文内容切割成最多800个Token的文本块,且块与块之间有15%的内容重叠,以确保上下文信息的连续性。 3. **格式化输入**:每个文本块都按照 `title: {文档标题} | text: {文本块内容}` 的格式进行组织,以符合嵌入模型的最佳实践。 4. **生成与存储**:调用本地嵌入模型(如 `embeddinggemma`)为每个格式化后的文本块生成向量,并将向量及其元数据(如所属文档哈希、在原文中的位置)存入数据库。
- 自动化本地模型管理 — 【设计策略】实现一个全自动的本地模型生命周期管理器,处理从下载、缓存、更新到闲置资源释放的全过程,让用户无需关心模型文件的具体操作。 【业务逻辑】 1. **按需下载**:当首次使用需要某个AI功能(如嵌入、重排)时,系统会根据预设的HuggingFace地址自动下载对应的GGUF格式模型文件。 2. **本地缓存**:下载的模型被存储在用户主目录下的 `.cache/qmd/models` 文件夹中。 3. **缓存更新**:在下载前,系统会通过HTTP HEAD请求检查HuggingFace上模型文件的ETag(版本标识)。如果远程ETag与本地缓存记录不符,则自动删除旧缓存并重新下载,确保模型保持最新。 4. **并发安全**:通过内部的Promise锁机制,防止在多个并发请求下重复下载或加载同一个模型,避免资源浪费和冲突。 5. **闲置回收**:系统设有一个5分钟的闲置计时器。如果在5分钟内没有任何AI操作,系统会自动卸载已加载到内存中的模型上下文(Context),释放内存资源。但默认情况下,模型文件本身仍保留在内存中以加快下次响应。该行为是可配置的。
- 查询扩展模型微调管道 — 【设计策略】提供一套完整的模型微调(Fine-tuning)流程,允许高级用户基于自定义数据训练查询扩展模型,以适应特定领域的术语和表达习惯。 【业务逻辑】 这是一个两阶段的训练过程: 1. **第一阶段:监督微调 (SFT)**:使用一批“查询-扩展”样本,通过监督学习的方式,先让基础模型(如Qwen3-1.7B)学会输出指定的结构化格式(如`lex:`、`vec:`、`hyde:`)。 2. **第二阶段:策略优化 (GRPO)**:在SFT的基础上,通过强化学习进一步提升扩展的质量。系统会为每个查询生成多个候选扩展,然后使用一个基于规则的奖励函数(评估格式、多样性、术语保留等)对它们打分,并根据分数对模型进行优化。 3. **模型导出**:训练完成后,生成的模型适配器(Adapter)会被合并到基础模型中,并导出为标准的GGUF格式,可以直接被QMD的查询引擎使用。
AI智能体集成与开发者工具
此模块旨在将QMD从一个个人命令行工具,转变为一个可供AI智能体(如Claude)编程调用的“本地知识插件”。通过实现模型上下文协议(MCP),QMD暴露了一系列结构化的工具接口。同时,它提供了多种输出格式和灵活的文档检索方式,极大地便利了自动化工作流和脚本集成。
- 模型上下文协议 (MCP) 服务器 — 【设计策略】通过标准输入输出(stdio)实现一个MCP服务器,将QMD的核心功能封装成AI智能体可以理解和调用的工具。 【业务逻辑】 1. 当以`mcp`模式启动时,QMD会注册一系列工具供AI调用,包括:`qmd_search` (关键词搜索), `qmd_vsearch` (向量搜索), `qmd_query` (混合搜索), `qmd_get` (获取单文档), `qmd_multi_get` (批量获取), 和 `qmd_status` (索引状态)。 2. 每次工具调用,QMD都会返回一个双重响应:一份是为人类用户准备的易读文本摘要,另一份是为AI准备的、包含详细信息的结构化JSON对象 (`structuredContent`)。 3. 同时,它还注册了 `qmd://` 协议,允许AI通过URI直接引用和读取知识库中的任何文档。
- 多格式结果输出 — 【设计策略】为搜索和获取命令提供多种可切换的输出格式,以适应不同的使用场景,无论是人类阅读还是机器处理。 【业务逻辑】 用户可以通过命令行标志(如 `--json`, `--files`, `--csv`, `--md`, `--xml`)来指定输出格式。 - **默认格式**:为命令行优化的彩色高亮文本,适合人类快速浏览。 - **JSON格式**:输出结构化的JSON对象,包含完整的搜索结果细节(如分数、摘要、路径等),便于脚本或程序解析。 - **Files格式**:输出一种简化的 `docid,score,filepath,context` 格式,专为需要文件列表的Agent工作流设计。 - **Markdown/XML格式**:将结果格式化为标准Markdown或XML,便于集成到其他文档或系统中。
- 灵活的文档获取机制 — 【设计策略】提供多种方式来精确或模糊地定位和获取文档内容,提升在命令行和Agent交互中的使用便利性。 【业务逻辑】 1. **按路径/ID获取**:用户可以使用 `qmd get` 命令,通过文件的相对路径或搜索结果中显示的6位短哈希ID(如`#abc123`)来获取文档内容。 2. **模糊路径匹配**:如果提供的路径不完全准确,系统会自动计算与库中所有文件路径的“编辑距离”,并推荐最相似的几个文件,以帮助用户纠正输入错误。 3. **按模式批量获取**:`qmd multi-get` 命令支持使用glob模式(如 `journals/2025-*.md`)或逗号分隔的列表,一次性获取多个文档的内容。此功能还支持按文件大小(默认不超过10KB)进行过滤,避免一次性加载过多内容。
Core Technical Capabilities
完全在本地设备运行的AI混合搜索流水线
Problem: 如何在不依赖任何云服务、保证100%数据隐私的前提下,实现媲美现代搜索引擎的(关键词+语义+AI重排)高质量搜索体验?传统本地搜索要么只支持关键词,要么配置复杂,无法开箱即用地提供AI增强能力。
Solution: 该能力通过一个精巧的多阶段流水线实现: Step 1: **查询扩展**:使用一个本地微调过的小型LLM,将用户的单一查询扩展为多个不同表述,拓宽召回范围。 Step 2: **并行召回**:将所有查询变体同时发往BM25关键词索引和向量索引,实现“词法”和“语义”的双重检索。 Step 3: **RRF融合**:使用倒数排名融合算法(RRF)智能地合并来自不同渠道的结果,并对原始查询的结果给予额外权重和排名奖励,确保精确匹配不被稀释。 Step 4: **LLM精排**:将融合后的前30个结果交由一个本地的跨编码器(Cross-encoder)LLM进行重新打分。 Step 5: **位置感知融合**:最后,将初始的融合分数和LLM的重排分数进行动态加权混合。对于排名靠前的结果,更信任初始检索;对于排名靠后的,则更信任LLM的深度判断。这个设计巧妙地平衡了检索的广度、精度和LLM的理解能力。
Technologies: Hybrid Search, Reciprocal Rank Fusion (RRF), LLM Reranking, GGUF, node-llama-cpp
Boundaries & Risks: 该方案对本地硬件有一定要求,需要足够的内存和CPU资源来运行多个LLM模型。首次运行时,需要从网络下载数百MB到数GB的模型文件。如果模型加载或推理失败,混合搜索会完全失败,而不是优雅降级为简单搜索。整个流程计算密集,查询延迟会高于单纯的关键词搜索。
自动化生命周期管理的本地LLM引擎
Problem: 如何让一个需要同时使用嵌入、生成、重排等多个不同LLM的应用,对用户来说易于管理?如果让用户手动下载、配置和启停模型,会极大增加使用门槛,同时持续运行模型也会造成不必要的资源浪费。
Solution: 通过一个集成的LLM服务来解决此问题: Step 1: **自动获取与缓存**:模型通过HuggingFace URI定义。系统在首次需要时自动下载,并使用文件的ETag进行版本比对,实现缓存的自动更新。 Step 2: **并发安全加载**:使用在途的Promise作为锁,确保即使有多个并发请求,同一个模型也只会被加载一次,避免了VRAM的重复分配和竞争条件。 Step 3: **会话管理**:所有LLM操作都在一个“会话”内进行,确保在系列操作(如查询扩展+重排)期间,模型不会被意外卸载。 Step 4: **智能闲置回收**:系统内置一个5分钟的非活动计时器。一旦超时且没有任何活动会话,它会自动卸载已加载的模型上下文(Context)以释放内存。这个计时器不会阻止程序退出,设计得非常轻量。
Technologies: Hugging Face, ETag Caching, Promise Concurrency Guards, setTimeout/unref
Boundaries & Risks: 模型的自动下载和更新依赖于到HuggingFace的稳定网络连接。缓存清理机制基于文件名包含匹配,在命名冲突的极端情况下可能误删。默认配置下,模型主体会常驻内存以优化性能,对内存资源有持续占用。
基于内容寻址与数据库触发器的自动化索引
Problem: 如何高效地索引一个可能包含大量重复或相似文件的大型知识库,并保证关键词索引始终与文件系统保持同步,而无需用户频繁手动执行“重建索引”?
Solution: 该能力结合了两种数据库技术: Step 1: **内容寻址存储**:在索引文件时,不以文件路径为核心,而是计算文件内容的哈希值。该哈希作为内容的唯一ID。`content`表存储哈希和唯一的文档内容,而`documents`表则存储文件元数据(如路径)并引用该哈希。这天然地实现了对内容的去重。 Step 2: **触发器自动同步**:在`documents`表上预设了`INSERT`, `UPDATE`, `DELETE`三种数据库触发器。任何对文件记录的操作(如添加新文件、删除旧文件)都会被数据库捕获,并自动地、原子地在全文检索(FTS5)索引中执行相应的同步操作。这使得FTS索引始终保持最新,完全对用户透明。
Technologies: Content-Addressable Storage, SQLite Triggers, SQLite FTS5
Boundaries & Risks: 数据库触发器的逻辑与表结构紧密耦合,未来对表结构的修改需要同步更新触发器,否则可能导致索引不一致。文档的短ID(6位哈希前缀)在极大规模的知识库中理论上存在碰撞风险,可能导致`qmd get #id`命令定位到错误文档。
面向AI智能体的标准化工具协议封装
Problem: 如何让一个强大的命令行工具,能够被AI智能体(如Claude)发现、理解和调用,从而将其能力融入到更复杂的自动化工作流中?AI需要的是结构化数据和标准的交互协议,而非人类可读的命令行输出。
Solution: 通过实现模型上下文协议(MCP)来桥接这一差距: Step 1: **启动MCP服务器**:程序提供一个`mcp`模式,通过标准输入/输出(stdio)与AI Agent的宿主环境(如Claude桌面应用)通信。 Step 2: **注册工具集**:将核心功能(如搜索、获取文档等)注册为符合MCP规范的工具,每个工具都有明确的输入参数(通过Zod schema定义)和功能描述。 Step 3: **双格式响应**:所有工具的返回结果都包含两部分:`content`部分是人类可读的文本摘要,`structuredContent`部分是包含完整细节的JSON对象,专供AI进行程序化处理。 Step 4: **资源URI化**:定义了`qmd://`协议,知识库中的每个文档都可以通过一个唯一的URI(如 `qmd://notes/meeting-2024.md`)被引用和访问,符合AI的资源操作习惯。
Technologies: Model Context Protocol (MCP), Stdio Transport, JSON, Resource URI
Boundaries & Risks: 该MCP服务器没有内置任何认证或授权机制,任何能够连接到该进程的本地应用都可以无限制地访问所有索引数据,因此仅适用于受信任的单用户环境。性能受限于单个数据库连接和本地机器资源,不适合高并发场景。