obsidian:~/vault$ search --hybrid obsidian

Obsidian MCP + 混合检索:2026参考指南

# 通过MCP将Obsidian接入Claude及其他代理:涵盖服务器设置、BM25+向量混合检索,以及为包含16,894个文件的知识库建立索引,并提供可用配置。

author: words: 3712 read_time: 63m updated: 2026-08-16 11:28
$ retriever search --hybrid obsidian

Obsidian不是笔记应用。它是一个本地优先、纯文本、图结构化的Markdown语料库;加入检索基础设施后,它会成为AI上下文储备池。16,894个文件。49,746个分块。23ms查询。0次API调用。1个83 MB的SQLite文件。本指南涵盖完整系统:从知识库架构到hybrid检索,再到MCP集成与运营工作流。


关键要点

这关乎上下文工程,而非记笔记。Obsidian知识库对AI的价值不在于笔记本身,而在于让笔记可被查询的检索层。没有检索能力的16,000个文件知识库,不过是一个只写不读的数据库。拥有hybrid搜索和MCP集成的200个文件知识库,才是AI知识库。检索基础设施才是产品,笔记则是原材料。

hybrid检索优于纯关键词或纯语义搜索。BM25擅长捕捉精确标识符和函数名称。向量搜索能够跨越不同术语捕捉同义词和概念匹配。Reciprocal Rank Fusion(RRF)无需进行分数校准即可合并两者。任何单一方法都无法同时覆盖这两类失效模式。关于MS MARCO段落排序的研究证实了这一规律:hybrid检索的表现始终优于单独使用任一方法。3hybrid retriever深度解析》涵盖RRF数学原理、包含真实数值的示例、失效模式分析,以及交互式融合计算器。

MCP让AI工具直接访问知识库。Model Context Protocol(MCP)服务器将检索器作为工具公开,供Claude Code、Codex CLI、Cursor及其他AI工具直接调用。代理会查询知识库,获得带来源归属的排序结果,并在无需加载完整文件的情况下使用上下文。MCP服务器只是检索引擎的一层轻量封装。

本地优先意味着零API成本和完整隐私保护。整套技术栈在一台机器上运行:SQLite负责存储,Model2Vec负责embeddings,FTS5负责关键词搜索,sqlite-vec负责向量KNN。无需云服务、无需API调用,也不依赖网络。个人笔记永远不会离开本机。以OpenAI API价格计算,完整重新嵌入49,746个文本块的成本约为$0.30;但真正的成本在于延迟、隐私暴露,以及一个本应离线运行的系统对网络的依赖。4

增量索引让系统在10秒内保持最新。通过比较文件修改时间来检测变更。只有已修改的文件会被重新chunking和重新嵌入。在Apple M系列硬件上,完整重新索引约需4分钟。典型一天的编辑所触发的增量更新可在10秒内完成。系统无需人工干预即可保持最新状态。

该架构可从200条笔记扩展至20,000+条。相同的三层设计(采集、检索、集成)适用于任何规模的知识库。对于小型知识库,可从仅使用BM25搜索开始。当关键词冲突成为问题时,再添加向量搜索。当您同时需要精确匹配和语义匹配时,加入RRF融合。每一层都可独立发挥价值,也可独立移除。


如何使用本指南

本指南涵盖完整系统。您的起点取决于当前所处阶段:

您是…… 从这里开始 然后探索
刚接触Obsidian+AI 为何选择Obsidian作为AI基础设施Obsidian MCP设置 知识库架构MCP服务器架构
已有知识库,希望获得AI访问能力 MCP服务器架构Claude Code集成 嵌入模型全文搜索
正在构建检索系统 完整检索管道Reciprocal Rank Fusion 性能调优故障排除
团队或企业环境 决策框架知识图谱模式 开发者工作流方案迁移指南

标记为Contract的章节包含实现细节、配置块和失效模式。标记为Narrative的章节侧重概念、架构决策及其设计考量。标记为Recipe的章节提供分步工作流。


为何选择Obsidian作为AI基础设施

本指南的核心观点是:Obsidian知识库是个人AI知识库的最佳基础,因为它本地优先、采用纯文本、具备图谱结构,并且用户可控制技术栈的每一层。

Obsidian为AI提供了哪些替代方案所没有的能力

纯文本markdown文件。每条笔记都是文件系统中的.md文件。没有专有格式,无需导出数据库,也无需API即可读取内容。任何能够读取文件的工具都可以读取您的知识库。grepripgrep、Python的pathlib、SQLite FTS5——它们都能直接处理源文件。构建检索系统时,您索引的是文件,而不是API响应。由于源头就是文件系统,索引始终与源内容保持一致。

本地优先架构。知识库存放在您的机器上。没有服务器、没有云同步依赖、没有API速率限制,也没有约束您如何处理自有内容的服务条款。无需任何外部服务,即可对笔记进行嵌入、索引、chunking和搜索。对于AI基础设施而言,这一点很重要:检索管道的运行速度取决于磁盘速度,而非API端点的响应速度。隐私同样如此:包含凭据、健康数据、财务信息和私人感想的个人笔记永远不会离开您的机器。

通过wiki-links构建的图谱结构。Obsidian的[[wiki-link]]语法会在笔记之间创建有向图。一条关于OAuth实现的笔记,可以链接到令牌轮换、会话管理和API安全相关笔记。图谱结构编码了作者在思考主题时人工整理的概念关系。向量embeddings能够捕捉语义相似性,但wiki-links捕捉的是作者有意建立的连接。这种信号是embeddings无法复制的。

插件生态系统。Obsidian拥有2,500+个社区插件(截至2026年3月,数量已突破2,500个,高于2025年年中时的1,800+个)。Dataview可像查询数据库一样查询您的知识库。Templater可通过JavaScript逻辑根据模板生成笔记。Git集成可将知识库同步到代码仓库。Linter可强制保持格式一致。Bases核心插件(在v1.9.10中引入)使用frontmatter属性作为字段,在知识库文件之上提供类似数据库的视图——表格、画廊、日历和看板,并保存为.base文件。15这些插件在不改变底层纯文本格式的前提下,为知识库增添结构。检索系统索引的是这些插件的输出,而非插件本身。

500万+用户。Obsidian拥有庞大且活跃的社区,持续产出模板、工作流、插件和文档。当您遇到知识库组织或插件配置问题时,很可能已经有人记录了解决方案。社区还开发了Obsidian周边工具:MCP服务器、索引脚本、发布管道和API封装器。

仅有文件系统无法提供什么

markdown文件目录具有纯文本优势,但缺少Obsidian带来的三项能力:

  1. 双向链接。Obsidian会自动跟踪backlinks。当您从笔记A链接到笔记B时,笔记B会显示笔记A引用了它。图谱面板会将连接集群可视化。这种双向感知是原始文件系统无法提供的元数据。

  2. 带插件渲染的实时预览。Dataview查询、Mermaid图表和callout块会实时渲染。在存储格式仍为纯文本的同时,写作体验比文本编辑器更丰富。您在丰富的环境中撰写和组织内容;检索系统则索引原始markdown。

  3. 社区基础设施。包括插件发现、主题市场、同步服务(可选)、发布服务(可选)和文档生态系统。您可以使用独立工具复刻任何单项功能,但Obsidian将它们整合为连贯的工作流。

Obsidian不提供什么(以及您需要构建什么)

Obsidian不包含检索基础设施。它具备基础搜索能力(全文、文件名、标签),但没有嵌入管道、向量搜索、融合排序、MCP服务器、凭据过滤、chunking策略,也没有面向外部AI工具的集成钩子。本指南介绍如何在Obsidian之上构建这些基础设施。知识库是基础。检索管道、MCP服务器和集成钩子才是基础设施。

本文所述架构是markdown优先,而非Obsidian专属。如果您使用Logseq、Foam、Dendron,或一个普通的markdown文件目录,检索管道的工作方式完全相同。chunker读取.md文件。embedder处理文本字符串。indexer写入SQLite。这些组件均不依赖Obsidian特有功能。Obsidian的贡献在于提供写作和组织环境,产出供检索器索引的markdown文件。

Obsidian MCP 设置

Model Context Protocol(MCP)是标准接口,可让Claude Code、Codex CLI、Cursor及其他 AI 工具直接访问 Obsidian vault。本节将在 5 分钟内将 vault 连接到 AI 工具。您将安装 Obsidian、创建 vault、安装 MCP 服务器,并运行首次查询。快速入门使用社区 MCP 服务器,以便立即获得结果。后续章节将介绍如何构建适用于生产环境的自定义检索管道。

前提条件

  • macOS、Linux 或 Windows
  • Node.js 18+(用于 MCP 服务器)
  • Obsidian 1.12+(用于 CLI 集成;1.13.7 是当前公开发布的桌面版——稳定版与 beta 版已合并,1.13 系列于 2026年7月30日离开 Catalyst;更早版本也可用于仅 MCP 的设置)
  • 已安装 Claude Code、Codex CLI 或 Cursor

第 1 步:创建 vault

obsidian.md 下载 Obsidian,并创建一个新的 vault。选择您容易记住的位置——MCP 服务器需要绝对路径。

# Example vault location
~/Documents/knowledge-base/

添加几篇笔记,让检索器有内容可供处理。即使只有 10–20 篇笔记,也足以看到结果。每篇笔记都应是一个 .md 文件,包含有意义的标题和至少一个段落的内容。

第 2 步:安装 MCP 服务器

多个社区 MCP 服务器可立即提供 vault 访问能力。该生态系统在 2025–2026 年间显著发展。其中值得关注的是 MCPVault(npm @bitbonsai/mcpvault,仓库 bitbonsai/mcpvault),现已达到 v0.15.0(已于 2026年8月14日根据 npm 验证)——它与下文的 MarkusPfundstein/mcp-obsidian 是独立项目,并非其改名版本。其 v0.11.0(2026年3月)新增了 list_all_tags,可扫描 frontmatter 和 hashtag 并统计数量,同时改进了点号文件夹处理以及对 .base/.canvas 的支持。值得采用 2026年7月23日当天发布的 3 个补丁:v0.12.3 新增 wiki_link 工具,可解析 [[Document Name]][[Name|Display]]、表格转义的 [[Name\|Display]]#fragment 形式,返回笔记内容、解析后的路径及所有存在歧义的替代项——这是让 agent 沿着 vault 自身链接图谱继续探索、而非重新搜索的检索原语——并通过默认路径过滤器将 .trash/ 排除在所有工具之外;v0.12.4 将 wiki_link 扩展到如 [[folder/Note]] 的带路径链接;v0.12.2 防止 patch_note 损坏包含 $ 替换模式的插入内容,并规范化意外携带 vault 前缀的路径。其路径过滤器的受限目录拒绝列表曾披露 2 个中等严重性公告(GHSA-9c83-rr99-vfwj 和 GHSA-j99q-93c9-h869);两者均早在 0.12 系列之前的 0.11.4 和 0.11.5 中修复,因此所有 0.12.x 版本均不受影响。13

2026年4月的转变——将 Obsidian CLI 作为首选桥接方式:Obsidian 1.12.0 引入了一等支持的 CLI,而公开发布的 1.12.7 安装程序(2026年3月23日)捆绑了独立二进制文件、TUI 和 socket 文件改进,使终端工作流更易于安装和运行。16 1.13 系列于 2026年7月30日以 1.13.4 进入公开渠道——这是一个设置、图像和 URI 安全更新,除 1.12.x 的 CLI 功能外,没有新增 AI 或自动化能力(具体改动请参阅变更日志条目)。2526 社区工具正积极从 Local REST API 插件(mcp-obsidian 基于此构建)迁移至基于 CLI 的集成,因为后者速度更快、稳定性更高。MarkusPfundstein/mcp-obsidian 仓库仍在维护——截至 2026年5月的提交新增了 search_by_tagget_frontmatter 等工具——但未发布带标签的版本(请从固定的提交安装)。它仍基于 Local-REST-API;对于新设置,CLI 桥接通常更快、更稳定,因此应优先选择它或下文列出的较新社区替代方案。20 有关推荐设置,请参阅本指南后文的“面向 AI 工作流的 Obsidian CLI”章节。

服务器 作者 传输方式 需要插件 核心功能
obsidian-mcp(npm obsidian-mcp StevenStavrakis STDIO 轻量级、基于文件
mcp-obsidian MarkusPfundstein STDIO Local REST API 通过 REST 完整 CRUD vault,另提供 search_by_tag/get_frontmatter——仍在积极维护(提交截至 2026年5月);无带标签版本,请固定提交20
obsidian-mcp-tools jacksteamdev STDIO 是(插件) 语义搜索 + Templater
obsidian-claude-code-mcp iansinnott WebSocket 是(插件) 为 Claude Code 自动发现
obsidian-mcp-server(npm obsidian-mcp-server cyanheads STDIO Local REST API 标签、frontmatter 管理——通过 OBSIDIAN_API_KEY/OBSIDIAN_BASE_URL 配置,而非 CLI 标志
Hybrid Search MCP community STDIO BM25 + 语义搜索 MCP 服务器 + CLI。由社区维护;采用前请验证近期提交。

对于快速入门,最简单的选择是直接读取 .md 文件的基于文件的服务器。请留意 npm 名称冲突:基于文件的服务器在 npm 中是 obsidian-mcp(StevenStavrakis);npm obsidian-mcp-server 则是 cyanheads 基于 REST-API 的服务器,需要 Local REST API 插件和 API 密钥——这是常见混淆,会导致读者安装了无法启动的服务器:

npm install -g obsidian-mcp

第 3 步:配置您的 AI 工具

Claude Code——使用 claude mcp add 注册服务器(Claude Code 将用户范围的 MCP 服务器存储在 ~/.claude.json 中,或存储在项目的 .mcp.json 中——而不是 ~/.claude/settings.json,后者会静默忽略 mcpServers 块):

# User scope (all your projects)
claude mcp add obsidian -s user -- npx -y obsidian-mcp@2 serve --vault notes=/absolute/path/to/your/vault

# Or project scope, shared with the repo (writes .mcp.json)
claude mcp add obsidian -s project -- npx -y obsidian-mcp@2 serve --vault notes=/absolute/path/to/your/vault

Codex CLI——添加至 ~/.codex/config.toml

[mcp_servers.obsidian]
command = "npx"
args = ["-y", "obsidian-mcp@2", "serve", "--vault", "notes=/absolute/path/to/your/vault"]

Cursor——添加至 .cursor/mcp.json

{
  "mcpServers": {
    "obsidian": {
      "command": "npx",
      "args": ["-y", "obsidian-mcp@2", "serve", "--vault", "notes=/absolute/path/to/your/vault"]
    }
  }
}

第 4 步:运行首次查询

打开您的 AI 工具,并提出 vault 笔记能够回答的问题:

Search my Obsidian vault for notes about [topic you wrote about]

AI 工具会调用 MCP 服务器,后者搜索您的 vault 并返回匹配内容。您应能看到包含文件路径和相关摘录的结果。

连接后 Claude 可以做什么

不同服务器的确切工具名称有所不同,但各实现的核心能力范围是一致的:

能力 常见工具 agent 如何使用
搜索 vault obsidian_search / search 查找与查询匹配的笔记,并返回按相关度排序的摘录、文件路径和来源归属
读取完整笔记 obsidian_read_note / read_note 当搜索摘录不足以满足需要时,获取完整笔记内容
列出和浏览 obsidian_list_notes / list_notes 没有特定查询时,按文件夹、标签或日期范围探索笔记
获取格式化上下文 obsidian_get_context 返回围绕主题组织、大小符合 token 预算的上下文块,可直接注入对话

在实践中:Claude 可基于您的笔记回答问题并标注来源,将既有决策和参考资料带入编程会话,并在无需将整个文件加载到上下文的情况下探索 vault 结构。部分社区服务器还提供写入操作(创建、追加、标签和 frontmatter 管理);本指南后文构建的自定义服务器则有意设计为只读,笔记创建改由 hooks 处理。

深入阅读:MCP 服务器架构了解工具与权限设计;Claude Code 集成了解 hooks 与桥接模式;Codex CLI 集成Cursor 及其他工具了解其他 agent。

您刚刚构建了什么

您通过标准协议将本地知识库连接到了 AI 工具。MCP 服务器读取 vault 文件,执行基础搜索并返回结果。这是最小可行版本。

此快速入门不提供以下能力: - Hybrid 检索(BM25 + 向量搜索 + RRF 融合) - 基于 embedding 的语义搜索 - 凭据过滤 - 增量索引 - 基于 hook 的自动上下文注入

本指南其余部分将介绍如何构建上述每项能力。快速入门验证了这一概念;完整管道则提供生产级检索能力。


用于 AI 工作流的 Obsidian CLI

Obsidian 1.12(2026年2月)引入了内置命令行接口,为 AI 工作流开辟了新的集成面;该接口在 1.13.7 中仍保持最新状态(1.13 系列于2026年7月30日进入公开渠道,此后未新增 CLI 功能)。162526 CLI 可充当 Obsidian GUI 的遥控器——Obsidian 必须处于运行状态(或会在首次执行命令时自动启动)。请在“设置”>“通用”>“命令行接口”中启用它。

CLI 对 AI 基础设施的重要性

CLI 为此前必须通过 GUI 或插件APIs才能完成的 Obsidian 原生操作提供了编程访问能力。对于 AI 工作流,主要能力包括:

  • 从脚本和 hook 中搜索。 obsidian search "query"obsidian search:context "query" 可从任意 shell 脚本、hook 或自动化流水线中搜索 vault。search:context 变体会返回匹配行及其周边上下文,适合将结果输入 AI 提示词。
  • 每日笔记自动化。 obsidian daily 会打开或创建当天的每日笔记。结合 shell 脚本,可实现自动化每日简报工作流——hook 可以将 AI 生成的摘要追加到每日笔记中。
  • 基于模板创建笔记。 obsidian template listobsidian template create 可根据 Templater 或核心模板生成笔记,使 AI agent 无需直接写入 markdown 文件即可创建结构化的 vault 条目。
  • 属性管理。 obsidian property setobsidian property get 可读取和写入 frontmatter 属性,使脚本无需解析 YAML 即可更新元数据。
  • 插件控制。 obsidian plugin enable/disable/list 可通过编程方式管理插件,适合在批处理期间切换索引插件。
  • 任务管理。 obsidian task list/add/complete 提供结构化任务访问,适合由 AI agent 管理 vault 中的工作项。

面向 AI 访问的 CLI 与 MCP

CLI 和 MCP 服务器承担不同角色,彼此互补而非竞争:

方面 Obsidian CLI MCP Server
调用方 Shell 脚本、hook、cron 任务 AI agent(Claude Code、Codex、Cursor)
协议 POSIX 进程(stdin/stdout/stderr) MCP(通过 STDIO 或 HTTP 的 JSON-RPC)
优势 Obsidian 原生操作(模板、插件、属性) 自定义检索(embeddings、BM25、RRF 融合)
局限 不支持向量搜索和 embedding 流水线 无法访问 Obsidian 内部操作
最适合 自动化脚本、接入流水线、hook 操作 会话期间的实时 AI agent 查询

建议:使用 CLI 处理接入自动化(创建笔记、管理属性、运行 Obsidian 原生搜索),使用 MCP 进行检索(结合 embeddings 的 hybrid 搜索)。UserPromptSubmit hook 可以在更耗资源的 hybrid 检索运行前调用 obsidian search:context 进行快速预检(限定工具范围的 hook 事件无法注入——其 stdout 永远不会传递给模型)。

示例:由 CLI 驱动的接入 hook

#!/bin/bash
# Hook: append today's signals to daily note via CLI
DATE=$(date +%Y-%m-%d)
SUMMARY="$1"
obsidian daily  # ensure daily note exists
obsidian file append "Daily Notes/${DATE}.md" "## AI Summary\n${SUMMARY}"

Obsidian Agent 插件

日益壮大的 Obsidian 插件类别正在将 AI 编程 agent 直接嵌入 vault UI,为外部 MCP server 配置提供了替代方案。这些插件让 AI agent 在 Obsidian 的侧边栏中运行,而非从外部工具连接。

Claudian

Claudian 将 Claude Code 作为 AI 协作者嵌入 vault。vault 目录会成为 Claude 的工作目录,使其具备完整的 agent 能力:文件读写、搜索、bash 命令以及多步骤工作流。17

面向 AI 基础设施的主要功能: - 上下文感知提示词。 自动附加当前聚焦的笔记,支持使用 @notename 提及文件、基于标签排除内容,并将编辑器选区作为上下文。 - 视觉支持。 通过拖放、粘贴或文件路径分析图像——适合处理 vault 中保存的截图和图表。 - 斜杠命令。 创建由 /command 触发的可复用提示词模板,从而实现标准化的 vault 操作。 - 权限模式。 提供 YOLO(自动批准)、Safe(逐项批准)和 Plan(仅规划)模式,并配有安全阻止列表和 vault 范围限制。

Agent Client

Agent Client 通过 Agent Client Protocol(ACP)将 Claude Code、Codex CLI 和 Gemini CLI 集成到统一的 Obsidian 侧边栏中。18

主要功能: - 多 agent 切换。 可在同一面板中与 Claude Code、Codex 或 Gemini CLI 对话,并按需切换 agent。 - 笔记提及。 使用 @notename 将笔记内容纳入提示词,类似 Claudian,但不依赖特定 agent。 - Shell 执行。 可直接在聊天中执行终端命令——构建脚本、git 命令或任何终端操作,无需离开对话。 - 操作批准。 对文件读取、编辑和命令执行提供细粒度控制。

何时使用 agent 插件,何时使用外部 MCP

场景 Agent 插件 外部 MCP
借助 AI 编写和编辑 vault 笔记 更好——agent 能感知编辑器上下文 可用,但不具备编辑器感知能力
跨多个 repo 进行代码开发 有限——仅限 vault 范围 更好——以项目为范围并可访问完整文件系统
从大型已索引语料库中检索 仅提供基础搜索 提供完整 hybrid 检索流水线
记笔记期间快速进行 vault 问答 理想——无需切换上下文 需要切换到终端

建议:将 agent 插件用于以 vault 为中心的工作流(编写、整理、总结笔记)。对于 AI agent 需要完整检索流水线且需要访问 vault 外代码库的开发工作流,请使用外部 MCP 服务器。两种方式可以并存——在 Obsidian 内运行 Claudian 处理笔记工作,同时在外部运行带有 MCP 的 Claude Code 进行开发。


决策框架:Obsidian与替代方案

并非所有用例都需要Obsidian。本节说明什么时候Obsidian是合适的基础,什么时候显得过度,以及什么时候其他工具更适合。

决策树

START: What is your primary content type?

├─ Structured data (tables, records, schemas)
   Use a database. SQLite, PostgreSQL, or a spreadsheet.
   Obsidian is for prose, not tabular data.

├─ Ephemeral context (current project, temporary notes)
   Use CLAUDE.md / AGENTS.md in the project repo.
   These travel with the code and reset per project.

├─ Team wiki (shared documentation, onboarding)
   Evaluate Notion, Confluence, or a shared git repo.
   Obsidian vaults are personal-first. Team sync is possible
    but not native.

└─ Growing personal knowledge corpus
   
   ├─ < 50 notes
      A folder of markdown files + grep is sufficient.
      Obsidian adds value mainly through the link graph,
       which needs density to be useful.
   
   ├─ 50 - 500 notes
      Obsidian adds value. Wiki-links create a navigable graph.
      BM25-only search (FTS5) is sufficient at this scale.
      Skip vector search and RRF until keyword collisions appear.
   
   ├─ 500 - 5,000 notes
      Full hybrid retrieval becomes valuable. Keyword collisions
       increase. Semantic search catches queries that BM25 misses.
      Add vector search + RRF fusion at this scale.
   
   └─ 5,000+ notes
       Full pipeline is essential. BM25-only returns too much noise.
       Credential filtering becomes critical (more notes = more
        accidentally pasted secrets).
       Incremental indexing matters (full reindex takes minutes).
       MCP integration pays dividends on every AI interaction.

对比矩阵

标准 Obsidian Notion Apple Notes 普通文件系统 CLAUDE.md
Local-first 否(云端) 部分支持(iCloud)
纯文本 是(markdown) 否(blocks) 否(专有格式)
图结构 是(wiki-links) 部分支持(mentions)
AI可索引 直接文件访问 需要API 需要导出 直接文件访问 已在上下文中
Plugin生态 2,500多个plugins Integrations N/A N/A
离线可用 完整支持 只读缓存 部分支持 完整支持 完整支持
可扩展到10K+笔记 是(借助API) 性能下降 否(单个文件)
成本 免费(核心功能) $10/月起 免费 免费 免费

什么时候Obsidian显得过度

  • 单项目上下文。 如果AI只需要当前代码库的上下文,请放入CLAUDE.mdAGENTS.md或项目级文档。这些文件会随repo一起移动,并自动加载。
  • 结构化数据。 如果内容是表格、记录或schemas,请使用数据库。Obsidian笔记以 prose 为主。Dataview可以查询frontmatter字段,但真正的数据库更适合处理结构化查询。
  • 临时研究。 如果笔记会在项目结束后丢弃,使用包含markdown文件的草稿目录更简单。不要为短期内容构建检索基础设施。

什么时候Obsidian是正确选择

  • 跨数月或数年积累知识。 随着语料库增长,价值会不断复利。一个每天查询、持续使用6个月的200条笔记vault,比只查询一次的5,000条笔记vault更有价值。
  • 一个语料库覆盖多个领域。 包含编程、架构、安全、设计和个人项目笔记的vault,可以受益于跨领域检索,这是项目专属CLAUDE.md无法提供的。
  • 隐私敏感内容。 Local-first意味着检索流水线绝不会把内容发送到外部服务。vault中包含您放入的任何内容,包括您不愿上传到云服务的内容。

心智模型:三层结构

该系统有三层,它们各自独立运行,但组合后会相互增强。每一层关注的问题不同,失败模式也不同。

┌─────────────────────────────────────────────────────┐
                 INTEGRATION LAYER                     
  MCP servers, hooks, skills, context injection        
  Concern: delivering context to AI tools              
  Failure: wrong context, too much context, stale      
└──────────────────────┬──────────────────────────────┘
                        query + ranked results
┌──────────────────────┴──────────────────────────────┐
                  RETRIEVAL LAYER                      
  BM25, vector KNN, RRF fusion, token budget           
  Concern: finding the right content for any query     
  Failure: wrong ranking, missed results, slow queries 
└──────────────────────┬──────────────────────────────┘
                        chunked, embedded, indexed
┌──────────────────────┴──────────────────────────────┐
                   INTAKE LAYER                        
  Note creation, signal triage, vault organization     
  Concern: what enters the vault and how it's stored   │
  Failure: noise, duplicates, missing structure        
└─────────────────────────────────────────────────────┘

摄取决定什么内容进入vault。如果没有筛选,vault会积累噪声:推文截图、没有注释的复制粘贴文章、缺少上下文的半成品想法。摄取层负责在入口处进行质量控制。它可以是评分流水线、标签约定或人工审核流程,也可以是任何确保vault包含值得检索内容的机制。

检索让vault可查询。这是系统的引擎:将笔记chunking(分块)成搜索单元,把chunks转换为embeddings(嵌入)并放入向量空间,为关键词和语义搜索建立索引,再用RRF融合结果。检索层把一个文件目录转化为可查询的知识库。没有这一层,vault只能通过手动浏览和基础搜索来导航,而无法被AI工具以编程方式访问。

集成将检索层连接到AI工具。MCP服务器将检索暴露为可调用工具。Hooks会自动注入上下文。Skills会把新知识捕获回vault。集成层是知识库与消费它的AI agents之间的接口。

这些层在设计上彼此解耦。摄取评分流水线不了解embeddings。检索器不了解信号路由规则。MCP服务器不了解笔记是如何创建的。这种解耦意味着您可以独立改进任何一层。替换embedding模型,而无需更改摄取流水线。新增MCP能力,而无需修改检索器。调整信号评分启发式规则,而无需触碰索引。


面向AI消费的Vault架构

针对AI检索优化的vault,与针对个人浏览优化的vault,遵循的是不同约定。本节介绍文件夹结构、笔记schema、frontmatter约定,以及能够提升检索质量的具体模式。

文件夹结构

为顶层文件夹使用数字前缀,以建立可预测的组织层级。这些数字不表示优先级,而是用于归类相关领域,并让结构一目了然。

vault/
├── 00-inbox/              # Unsorted captures, pending triage
├── 01-projects/           # Active project notes
├── 02-areas/              # Ongoing areas of responsibility
├── 03-resources/          # Reference material by topic
   ├── programming/
   ├── security/
   ├── ai-engineering/
   ├── design/
   └── devops/
├── 04-archive/            # Completed projects, old references
├── 05-signals/            # Scored signal intake
   ├── ai-tooling/
   ├── security/
   ├── systems/
   └── ...12 domain folders
├── 06-daily/              # Daily notes (if used)
├── 07-templates/          # Note templates (excluded from index)
├── 08-attachments/        # Images, PDFs (excluded from index)
├── .obsidian/             # Obsidian config (excluded from index)
└── .indexignore            # Paths to exclude from retrieval index

应当索引的文件夹:所有包含markdown正文的内容——项目、领域、资源、信号、每日笔记。

应当从索引中排除的文件夹:模板(其中包含占位变量,而非内容)、附件(二进制文件)、Obsidian配置,以及任何包含敏感内容且您不希望进入检索索引的文件夹。

.indexignore文件

在vault根目录创建.indexignore文件,以明确从检索索引中排除路径。其语法与.gitignore一致:

# Obsidian internal
.obsidian/

# Templates contain placeholders, not content
07-templates/

# Binary attachments
08-attachments/

# Personal health/medical notes
02-areas/health/

# Financial records
02-areas/finance/personal/

# Career documents (resumes, salary data)
02-areas/career/private/

索引器会在扫描前读取此文件,并完全跳过匹配的路径。被排除路径中的文件不会被chunking,不会生成embeddings,也不会出现在搜索结果中。

笔记Schema

每篇笔记都应包含YAML frontmatter。检索器会使用frontmatter字段进行筛选和上下文增强:

---
title: "OAuth Token Rotation Patterns"
type: note           # note | signal | project | moc | daily
domain: security     # primary domain for routing
tags:
  - authentication
  - oauth
  - token-management
created: 2026-01-15
updated: 2026-02-28
source: ""           # URL if captured from external source
status: active       # active | archived | draft
---

检索所需字段:

  • title——用于搜索结果展示,并作为BM25的标题上下文
  • type——支持按类型筛选的查询(“只显示MOC”或“只显示信号”)
  • tags——以0.3权重索引到FTS5标题上下文中,即使正文使用不同术语,也能提供关键词匹配

可选但很有价值的字段:

  • domain——支持按领域限定的查询(“只搜索安全笔记”)
  • source——为捕获内容提供出处;检索器可以在结果中包含来源URL
  • status——允许从活跃搜索中排除已归档或草稿笔记

Chunking约定

检索器会在H2(##)标题边界进行chunking。这意味着笔记结构会直接影响检索粒度:

有利于检索:

## Token Rotation Strategy

The rotation interval depends on the threat model...

## Implementation with refresh_token

The OAuth 2.0 refresh token flow requires...

## Error Handling: Expired Tokens

When a token expires mid-request...

3个H2小节会生成3个可独立搜索的chunk。每个chunk都有足够上下文,便于embedding捕捉其含义。关于“过期token处理”的查询会精确匹配第三个chunk。

不利于检索:

# OAuth Notes

Token rotation depends on threat model. The OAuth 2.0 refresh
token flow requires storing the refresh token securely. When a
token expires mid-request, the client should retry after refresh.
The rotation interval is typically 15-30 minutes for access tokens
and 7-30 days for refresh tokens...

一个没有H2标题的长小节会生成一个大chunk。embedding会在该小节的所有主题之间取平均。关于任何子主题的查询都会同等匹配整篇笔记。

经验法则:如果一个小节涵盖多个概念,请将其拆分为H2子小节。其余工作交给chunker处理。

不应放入笔记的内容

会降低检索质量的内容:

  • 未加注释地原样复制整篇文章。检索器会索引原文关键词,用并非您撰写的内容稀释vault。建议改为添加摘要、提取要点,或链接到来源URL。
  • 没有文字说明的截图。检索器索引的是markdown文本。没有alt文本或周边说明的图片,对BM25和向量搜索都是不可见的。
  • 凭据字符串。API密钥、token、密码、连接字符串。即使有凭据过滤,最安全的做法仍然是永远不要把密钥粘贴到笔记中。请改用名称引用(例如“~/.env中的Cloudflare API token”)。
  • 未经整理的自动生成内容。如果某个工具生成了一篇笔记(会议转录、Readwise高亮、RSS导入),请在其进入永久vault前进行审阅和批注。未经整理的自动导入只会增加体量,而不会增加可检索价值。

AI Workflows的插件生态

能够提升AI检索库质量的Obsidian插件可分为三类:结构类(强制一致性)、查询类(暴露元数据)和同步类(保持库内容最新)。

必备插件

Dataview。 使用frontmatter字段像查询数据库一样查询您的库。创建动态索引,例如:“过去30天内更新、标记为security的所有笔记”,或“状态为active的所有项目笔记”。Dataview不会直接帮助检索,但能帮助您发现库覆盖范围中的缺口,并找出需要更新的笔记。

TABLE type, domain, updated
FROM "03-resources"
WHERE status = "active"
SORT updated DESC
LIMIT 20

Templater。 基于模板创建带动态字段的笔记。使用预填createdtypedomain字段的模板,确保每篇新笔记一开始就具备正确的frontmatter。一致的frontmatter可提升检索过滤效果。

<%* /* New Resource Note Template */ %>
---
title: "<% tp.file.cursor() %>"
type: note
domain: <% tp.system.suggester(["programming", "security", "ai-engineering", "design", "devops"], ["programming", "security", "ai-engineering", "design", "devops"]) %>
tags: []
created: <% tp.date.now("YYYY-MM-DD") %>
updated: <% tp.date.now("YYYY-MM-DD") %>
source: ""
status: active
---

## Key Points

## Details

## References

Linter。 在整个库中强制执行格式规则。一致的标题层级(H1用于标题,H2用于章节,H3用于小节)可确保chunker生成可预测的结果。对检索重要的Linter规则包括:

  • 标题递增:强制标题层级按顺序递增(不要从H1跳到H3)
  • YAML标题:与文件名匹配
  • 行尾空格:删除(避免FTS5分词伪影)
  • 连续空行:限制为1行(生成更干净的chunks)

Git集成。 为您的库提供版本控制。跟踪随时间发生的变更,在多台机器之间同步,并从误删中恢复。Git还提供索引器用于增量变更检测的mtime数据。

有助于索引的插件

Smart Connections。 这是一个Obsidian插件,可在Obsidian内部提供AI驱动的语义搜索。Smart Connections v4默认创建本地embeddings(嵌入)——库完成索引后,语义连接和查找可完全离线运行,无需任何API调用。11 v4.5.0(2026年5月5日) 将页脚连接纳入Smart Connections Core,因此每次安装都可以在页脚显示相关笔记连接,而无需打开侧边面板。近期v4版本还为连接列表添加了图视图、可配置的停靠位置、索引运行中断后的块嵌入恢复改进,以及“Substrate”:一种跨插件环境,让Smart Connections、Smart Chat和Smart Composer共享状态。21 虽然本指南中的检索系统位于Obsidian外部(作为Python pipeline运行),但Smart Connections有助于在写作时探索语义关系。这两个系统索引相同内容,但服务于不同用例:Smart Connections用于编辑器内发现,外部retriever则通过MCP集成AI工具。

2026年4月发布的AI原生插件。 一批新的社区插件直接面向Claude Code / Codex / Gemini-CLI工作流:

Plugin 发布时间 功能
Cortex 4月4日 由Claude Code驱动的库代理——将库视为代理工作区,而不仅是笔记存储
VaultSearch 4月7日 本地优先的hybrid搜索:BM25 + 语义 + 模糊(与本指南的检索栈直接重叠)
LLM Wiki 4月9日 将您的库转换为可私密查询的知识库
Drift 4月11日 面向AI驱动Obsidian编辑的VS Code风格diff查看器;定位于Claude Code工作流
EngramQuest 4月11日 从笔记生成记忆挑战;随附面向Claude Code / Gemini CLI / Cursor的“AI Skills”
Hybrid Search MCP 3月(仍属新品) MCP服务器 + CLI,支持BM25 + 语义搜索——专为AI助手构建

请将其视为正在涌现的功能版图——未来几个季度,其中若干插件很可能会整合,或被Smart Connections / Obsidian core吸收。如果今天要选择一个,VaultSearch和Hybrid Search MCP在理念上最接近本指南的外部retriever。

Dataview说明: Dataview(长期存在的Obsidian查询插件)最后一次发布是2025年4月的0.5.70,此后实际上已处于停滞状态。对于新工作,Obsidian内置的Bases功能(1.9+)是隐含的继任者,也是推荐路径。

Metadata Menu。 提供结构化frontmatter编辑,并为字段值提供自动补全。减少typedomaintags字段中的拼写错误。一致的元数据可提升检索过滤准确性。

不利于索引的插件

Excalidraw。 将绘图作为嵌入在markdown文件中的JSON保存。该JSON在语法上是有效的markdown,但在chunking(分块)和嵌入后会产生无用内容。请通过.indexignore从索引中排除Excalidraw文件,或按文件扩展名过滤。

Kanban。 将看板状态存储为特殊格式的markdown。该格式面向Kanban渲染设计,而不是面向散文检索。chunker会生成卡片标题和元数据的碎片,这些内容不适合嵌入。请从索引中排除Kanban看板。

Calendar。 创建内容极少的每日笔记(通常只有日期标题)。空笔记或近乎空白的笔记会产生低质量chunks。如果使用每日笔记,请在其中写入实质性内容,或从索引中排除每日笔记文件夹。

关键插件配置

文件恢复 → 已启用。 防止意外删除笔记。它与检索没有直接关系,但对于您所依赖的知识库至关重要。

严格换行 → 已禁用。 相比Obsidian严格模式(单换行表示<br>),Markdown标准换行(双换行表示段落)会生成更干净的chunks。

默认新文件位置 → 指定文件夹。 将新文件路由到00-inbox/,避免未分类笔记污染领域文件夹。收件箱是暂存区;文件会在分拣后移动到领域文件夹。

Wiki-link格式 → 尽可能使用最短路径。 更短的链接目标更便于retriever在索引链接结构时解析。


Embedding Models:选择与配置

embedding模型会将文本chunk转换为用于语义搜索的数值向量。模型选择会决定检索质量、索引大小、embedding速度和运行时依赖。本节说明为什么默认选择Model2Vec的potion-base-8M,以及何时应选择其他方案。

为什么选择Model2Vec potion-base-8M

模型:minishlab/potion-base-8M 参数量:760万 维度:256 大小:约30 MB 依赖:model2vec(仅numpy,无需PyTorch) 推理:仅CPU,静态词embedding(无attention层)

Model2Vec会将sentence transformer的知识蒸馏到静态token embedding中。它不像BERT、MiniLM和其他transformer模型那样对输入运行attention层,而是通过对预先计算的token embedding进行加权平均来生成向量。5实际效果是:由于没有顺序计算,embedding速度比基于transformer的模型快50到500倍。

在当前Model2Vec结果页面上,potion-base-8M达到all-MiniLM-L6-v2全任务分数约92%的水平(51.32对55.80),同时速度快出数个数量级。6剩余的质量差距,是换取速度和简单性优势的取舍。对于较短的markdown chunk(典型知识库中平均200到400词),这种质量差异没有在长文档上那么明显,因为两个模型在短小、聚焦的文本上会收敛到相似的表示。

配置

# embedder.py
DEFAULT_MODEL = "minishlab/potion-base-8M"
EMBEDDING_DIM = 256

class Model2VecEmbedder:
    def __init__(self, model_name=DEFAULT_MODEL):
        self._model_name = model_name
        self._model = None

    def _ensure_model(self):
        if self._model is not None:
            return
        _activate_venv()  # Add isolated venv to sys.path
        from model2vec import StaticModel
        self._model = StaticModel.from_pretrained(self._model_name)

    def embed_batch(self, texts):
        self._ensure_model()
        vecs = self._model.encode(texts)
        return [v.tolist() for v in vecs]

懒加载。模型在首次使用时加载,而不是在导入时加载。当retriever以仅BM25的回退模式运行时(例如embedding venv未安装),导入embedder模块不会产生额外成本。

隔离的虚拟环境。模型在专用venv中运行(例如~/.claude/venvs/memory/),以避免与工具链其他部分发生依赖冲突。_activate_venv()函数会在运行时将venv的site-packages添加到sys.path

# Create isolated venv
python3 -m venv ~/.claude/venvs/memory
~/.claude/venvs/memory/bin/pip install model2vec

批处理。embedder以64条为一批处理文本,以摊销Model2Vec的开销。indexer会将chunk送入embed_batch(),而不是一次只为一个chunk生成embedding。

何时选择其他方案

模型 维度 大小 速度 质量(MTEB) 最适合
potion-base-8M 256 30 MB 500x 51.32 默认:本地、快速、无GPU
potion-base-32M 256 120 MB 400x 52.83 更高质量,仍为静态
potion-retrieval-32M 256 120 MB 400x 35.06(检索) 面向检索优化的静态模型
potion-multilingual-128M 256 约500 MB 300x 多语言知识库(101种语言)
all-MiniLM-L6-v2 384 80 MB 1x 55.80 更高质量,仍可本地运行
nomic-embed-text-v1.5 768 270 MB 0.5x 62.28 最佳本地质量
text-embedding-3-small 1536 API N/A 62.30 基于API,质量最高

当您希望获得比potion-base-8M更好的质量,同时仍留在静态embedding系列中时,选择potion-base-32M。它使用从baai/bge-base-en-v1.5蒸馏而来的更大词汇表,达到52.83的全任务分数(比potion-base-8M高约3%),同时保持相同的256维输出和仅numpy依赖。8模型文件大4倍,会增加内存占用,但embedding速度仍比transformer模型快数个数量级。

当主要用例是检索时(知识库搜索正是如此),选择potion-retrieval-32M。这个变体专门针对检索任务从potion-base-32M微调而来,在Model2Vec检索基准表中得分为35.06,高于potion-base-32M的32.67。8取舍在于,它针对检索而非通用embedding质量进行优化。

当您的知识库包含多种语言的笔记时,选择potion-multilingual-128M。该模型于2025年5月发布,支持101种语言,是多语言任务中表现最好的静态embedding模型。它可以为任意语言的文本生成embedding,同时保持与其他potion模型相同的仅numpy依赖。12较大的模型文件(约500 MB)是获得跨语言能力的代价。如果您的笔记中既有英文内容,也有日语、中文、德语或其他非英文语言内容,请使用它。

当检索质量比速度更重要,并且已经安装PyTorch时,选择all-MiniLM-L6-v2。与256维向量相比,384维向量会让SQLite数据库大小增加约50%。在M系列硬件上,对15,000个文件进行完整重建索引时,embedding速度会从不到1分钟降至约10分钟。

当需要尽可能好的本地检索质量,并且可以接受较慢的索引速度时,选择nomic-embed-text-v1.5。768维向量会让数据库大小大约增加到3倍。它需要PyTorch以及现代CPU或GPU。

当网络延迟和隐私可以接受作为取舍时,选择text-embedding-3-small。API会生成最高质量的embedding,但也会引入云端依赖、按token计费的成本(每百万token 0.02美元),并将您的内容发送到OpenAI服务器。

其他所有情况下都继续使用potion-base-8M。速度优势对迭代式索引非常关键(开发期间反复重建索引),仅numpy依赖避免了PyTorch安装复杂度,256维向量也能让数据库保持紧凑。

量化与降维

Model2Vec v0.5.0+支持以更低精度和更低维度加载模型。8这对于在受限硬件上部署,或在不切换模型的情况下减小数据库大小很有帮助:

from model2vec import StaticModel

# Load with int8 quantization (25% of original size)
model = StaticModel.from_pretrained("minishlab/potion-base-8M", quantize=True)

# Load with reduced dimensions (e.g., 128 instead of 256)
model = StaticModel.from_pretrained("minishlab/potion-base-8M", dimensionality=128)

量化模型能以更小的内存占用保留几乎相同的检索质量。降维遵循Matryoshka式截断,即前N个维度承载最多信息。对于短文本检索,将维度从256降到128,可以让向量存储减半,同时质量损失很小。

Model2Vec v0.8.x更新了tokenizer和持久化内部机制,弃用Python 3.9支持,并将已发布结果刷新到较新的MTEB表。升级生产indexer前,请固定或测试model2vec版本,因为即使embedding模型名称保持不变,库升级也可能改变模型加载路径。10

针对知识库特定embedding进行微调

Model2Vec v0.4.0+支持在静态embedding之上训练自定义分类模型,v0.7.0加入了词汇表量化和用于蒸馏的可配置pooling,v0.8.x则重构了tokenizer和持久化行为。10这对包含专业词汇的知识库很有意义,例如医学笔记、法律参考、领域专用术语。在这些场景中,默认potion模型可能无法捕捉语义细微差别:

from model2vec import StaticModel
from model2vec.train import train_model

# Fine-tune on vault-specific data
model = StaticModel.from_pretrained("minishlab/potion-base-8M")
trained_model = train_model(model, train_texts, train_labels)
trained_model.save_pretrained("./vault-embeddings")

对于大多数知识库,默认potion-base-8M已经能提供足够的检索质量。只有当检索持续漏掉通用模型无法捕捉的领域特定关联时,微调才值得投入。

模型哈希跟踪

indexer会存储一个由模型名称和词汇表大小派生出的哈希。如果更换embedding模型,indexer会在下一次增量运行时检测到不匹配,并自动触发完整重建索引。

def _compute_model_hash(self):
    """Hash model name + vocab size for compatibility tracking."""
    key = f"{self._model_name}:{self._model.vocab_size}"
    return hashlib.sha256(key.encode()).hexdigest()[:16]

这可以防止在同一个数据库中混用来自不同模型的向量,否则会产生毫无意义的cosine similarity分数。

失败模式

模型下载失败。首次运行会从Hugging Face下载模型。如果下载失败(网络问题、企业防火墙),retriever会回退到仅BM25模式。首次下载后,模型会缓存在本地。

维度不匹配。如果在未清空数据库的情况下切换模型,已存储向量的维度会与新的embedding不同。indexer会通过模型哈希检测到这一点,并触发完整重建索引。如果哈希检查失败(自定义模型没有正确哈希),sqlite-vec会在维度不匹配的KNN查询上报错。

大型知识库的内存压力。在单个批次中为50,000多个chunk生成embedding可能消耗大量内存。indexer会以64条为一批处理,以限制峰值内存占用。如果内存仍然紧张,请减小批次大小。


使用FTS5进行全文搜索

SQLite的FTS5扩展提供带BM25排序的全文搜索。FTS5是hybrid检索流水线中的关键词搜索组件。本节介绍FTS5配置、BM25擅长的场景,以及它的具体失效模式。

FTS5虚拟表

CREATE VIRTUAL TABLE chunks_fts USING fts5(
    chunk_text,
    section,
    heading_context,
    content=chunks,
    content_rowid=id
);

内容同步模式。content=chunks参数指示FTS5直接引用chunks表,而不是存储一份重复的文本副本。这会将存储需求减半,但也意味着在插入、更新或删除chunk时,必须手动同步FTS5。

列。索引包含3列: - chunk_text——每个chunk的主要内容(BM25权重:1.0) - section——H2标题文本(BM25权重:0.5) - heading_context——笔记标题、标签和元数据(BM25权重:0.3)

BM25排序

BM25根据词频、逆文档频率和文档长度归一化对文档进行排序。FTS5中的bm25()辅助函数接受按列设置的权重:

SELECT
    c.id, c.file_path, c.section, c.chunk_text,
    bm25(chunks_fts, 1.0, 0.5, 0.3) AS score
FROM chunks_fts
JOIN chunks c ON chunks_fts.rowid = c.id
WHERE chunks_fts MATCH ?
ORDER BY score
LIMIT 30;

列权重(1.0、0.5、0.3)表示: - chunk_text中的关键词匹配对分数贡献最大 - section(标题)中的匹配贡献为其一半 - heading_context(标题、标签)中的匹配贡献为其30%

这些权重可以调节。如果您的vault中有描述性很强、能有效预测内容质量的标题,可以提高section权重。如果标签全面且准确,可以提高heading_context权重。

BM25何时胜出

BM25擅长处理包含精确标识符的查询:

  • 函数名:_rrf_fuseembed_batchget_stale_files
  • CLI标志:--incremental--vault--model
  • 配置键:bm25_weightmax_tokensbatch_size
  • 错误消息:SQLITE_LOCKEDConnectionRefusedError
  • 特定术语:PostToolUsePreToolUseAGENTS.md

对于这些查询,BM25会立即找到精确匹配。向量搜索会返回语义相关内容,但可能将精确匹配排在概念性讨论之后。

BM25何时失效

当查询使用的术语与已存内容不同,BM25就会失效:

  • 查询:“how to handle authentication failures”→vault中包含关于“login error recovery”和“session expiration handling”的笔记。BM25不会匹配,因为关键词不同。
  • 查询:“what is the best way to manage state”→vault中包含关于“Redux store patterns”和“context providers”的笔记。BM25会漏掉这些内容,因为“state management”是通过具体技术名称表达的。

BM25在规模扩大时还会因关键词碰撞而失效。在一个包含15,000个文件的vault中,搜索“configuration”会匹配数百篇笔记,因为几乎每个项目笔记都会提到配置。结果在技术上正确,但实际上难以使用——排序无法判断哪篇“configuration”笔记与当前查询相关。

FTS5分词器

FTS5默认使用unicode61分词器,可处理ASCII和Unicode文本。对于包含大量CJK(中文、日文、韩文)内容的vault,可以考虑使用trigram分词器:

-- For CJK-heavy vaults
CREATE VIRTUAL TABLE chunks_fts USING fts5(
    chunk_text, section, heading_context,
    content=chunks, content_rowid=id,
    tokenize='trigram'
);

默认的unicode61分词器按词边界切分,这对词与词之间没有空格的语言效果较差。trigram分词器每3个字符切分一次,可以支持子串匹配,但代价是索引体积变大(约为原来的3倍)。

维护

当底层chunks表发生变化时,FTS5需要显式同步:

# After inserting chunks
cursor.execute("""
    INSERT INTO chunks_fts(chunks_fts)
    VALUES('rebuild')
""")

rebuild命令会根据内容表重建FTS5索引。批量插入(完整重建索引)后运行它,但不要在单条增量更新后运行;对于单条更新,请使用INSERT INTO chunks_fts(rowid, chunk_text, section, heading_context)同步单行。


sqlite-vec 扩展将向量 KNN(K-Nearest Neighbors)搜索引入 SQLite。本节介绍 sqlite-vec 配置、从笔记到可搜索向量的 embedding 流水线,以及具体的查询模式。

sqlite-vec 虚拟表

CREATE VIRTUAL TABLE chunk_vecs USING vec0(
    id INTEGER PRIMARY KEY,
    embedding float[256]
);

vec0 模块将 256 维浮点向量存储为打包的二进制数据。id 列与 chunks 表建立 1:1 映射,从而支持在向量结果与 chunk 元数据之间进行 join。

Embedding 流水线

流水线从笔记流向可搜索向量:

Note (.md file)
   Chunker: split at H2 boundaries
     Chunks (30-2000 chars each)
       Credential filter: scrub secrets
         Embedder: Model2Vec encode
           Vectors (256-dim float arrays)
             sqlite-vec: store as packed binary
               Ready for KNN queries

向量序列化

Python 的 struct 模块会为 sqlite-vec 存储序列化浮点向量:

import struct

def _serialize_vector(vec):
    """Pack float list into binary for sqlite-vec."""
    return struct.pack(f"{len(vec)}f", *vec)

def _deserialize_vector(blob, dim=256):
    """Unpack binary blob to float list."""
    return list(struct.unpack(f"{dim}f", blob))

KNN 查询

向量搜索查询会先对输入查询生成 embedding,然后按 cosine distance 查找 K 个最近的 chunk:

def _vector_search(self, query_text, limit=30):
    query_vec = self.embedder.embed_batch([query_text])[0]
    packed = _serialize_vector(query_vec)

    results = self.db.execute("""
        SELECT
            cv.id,
            cv.distance,
            c.file_path,
            c.section,
            c.chunk_text
        FROM chunk_vecs cv
        JOIN chunks c ON cv.id = c.id
        WHERE embedding MATCH ?
            AND k = ?
        ORDER BY distance
    """, [packed, limit]).fetchall()

    return results

sqlite-vec 中的 MATCH 运算符执行近似最近邻搜索。k 参数控制返回的结果数量。distance 列包含 cosine distance(0=相同,2=相反)。

带 Distance 约束的 KNN 分页

从 sqlite-vec v0.1.7 开始,KNN 查询支持 WHERE distance < ? 约束,可在大型结果集中进行基于游标的分页,而无需重新扫描前面的页面。14 后续的 v0.1.8 和 v0.1.9 稳定版本主要是打包和 DELETE bug 修复版本,并非新的查询模型版本,因此 v0.1.7 仍是此分页模式的功能边界。23

展望后续,v0.1.10-alpha 版本线(2026年3月31日至5月18日)首次让 sqlite-vec 超越暴力 KNN:它引入了近似最近邻索引类型,包括 rescore、实验性的 ivf(inverted-file)索引(默认未启用),以及面向向量规模过大、无法常驻内存的知识库的磁盘型 DiskANN 索引。23 这些功能会改变超大型知识库的扩展方式,但 0.1.10 版本线仍是预发布(alpha)状态。请将 ANN 索引视为实验性功能;在稳定的 0.1.10 发布之前,生产知识库仍应继续基于稳定的 v0.1.9 暴力 KNN 路径构建。

def _paginated_vector_search(self, query_vec, page_size=20, max_distance=None):
    """Paginate through KNN results using distance constraints."""
    packed = _serialize_vector(query_vec)
    constraint = f"AND distance < {max_distance}" if max_distance else ""

    results = self.db.execute(f"""
        SELECT cv.id, cv.distance, c.file_path, c.chunk_text
        FROM chunk_vecs cv
        JOIN chunks c ON cv.id = c.id
        WHERE embedding MATCH ?
            AND k = ?
            {constraint}
        ORDER BY distance
    """, [packed, page_size]).fetchall()

    # Use last result's distance as cursor for next page
    next_cursor = results[-1][1] if results else None
    return results, next_cursor

这取代了以往获取较大的 k 后再在 Python 中切片的模式,可降低针对大型知识库进行探索性查询时的内存占用。

vec0 表中的 DELETE 支持

sqlite-vec v0.1.7 为 vec0 虚拟表添加了原生 DELETE 支持,v0.1.9 修复了涉及长度超过 12 个字符的元数据文本列的 DELETE 错误路径。1423 此前,移除向量需要删除并重建表。现在,索引器的文件移除路径可以直接删除向量:

# Before v0.1.7: required workaround (drop + recreate, or mark as inactive)
# After v0.1.7: direct DELETE works
db.execute("DELETE FROM chunk_vecs WHERE id = ?", [chunk_id])

这简化了笔记被删除或移动时的增量重新索引。索引器不再需要维护影子“active IDs”表,也无需批量重建。

Vector Search 何时更有优势

当概念比具体措辞更重要时,Vector Search 表现出色:

  • 查询:”how to handle authentication failures” → 找到关于“login error recovery”的笔记(处于相同语义空间,但关键词不同)
  • 查询:”what patterns exist for caching” → 找到关于“memoization”、“Redis TTL strategies”和“HTTP cache headers”的笔记(概念相关,术语多样)
  • 查询:”approaches to testing asynchronous code” → 找到关于“pytest-asyncio fixtures”、“mock event loops”和“async test patterns”的笔记(同一概念通过实现细节表达)

Vector Search 何时失效

Vector Search 不擅长处理精确标识符:

  • 查询:_rrf_fuse → 返回关于“fusion algorithms”和“rank merging”的笔记,但实际函数定义的排序可能低于概念性讨论
  • 查询:PostToolUse → 返回关于“tool lifecycle hooks”和“post-execution handlers”的笔记,而不是具体的 hook 名称

Vector Search 也不擅长处理结构化数据。JSON 配置文件、YAML 块和代码片段生成的 embedding 往往捕捉的是结构模式,而不是语义含义。包含 "review": true 的 JSON 文件,与关于代码审查的散文式讨论,会得到不同的 embedding。

优雅降级

如果 sqlite-vec 加载失败(缺少扩展、平台不兼容、库损坏),retriever 会回退到仅 BM25 搜索:

class VectorIndex:
    def __init__(self, db_path):
        self.db = sqlite3.connect(db_path)
        self._vec_available = False
        try:
            self.db.enable_load_extension(True)
            self.db.load_extension("vec0")
            self._vec_available = True
        except Exception:
            pass  # BM25-only mode

    @property
    def vec_available(self):
        return self._vec_available

retriever 会在尝试向量查询前检查 vec_available。禁用后,所有搜索都只使用 BM25,并跳过 RRF fusion 步骤。


Reciprocal Rank Fusion(RRF)

RRF可以合并两个排序列表,而无需进行分数校准。本节介绍该算法、一个完整的查询追踪示例、k参数调优,以及为什么选择RRF而不是其他方案。如需使用可编辑排名、场景预设和可视化架构浏览器的交互式计算器,请参阅hybrid retriever深度解析

算法

RRF仅根据每个列表中的排名位置为每个文档分配分数:

score(d) = Σ (weight_i / (k + rank_i))

其中: - k是平滑常数(60,遵循Cormack等人的设置3) - rank_i是文档在结果列表i中的从1开始的排名 - weight_i是可选的按列表设置的乘数(默认值为1.0)

在多个列表中排名靠前的文档会获得更高的融合分数。只出现在一个列表中的文档,则只从该单一来源获得分数。

为什么选择RRF而不是其他方案

加权线性组合需要校准BM25分数与cosine distances。BM25分数没有上界,并且会随语料库规模变化。Cosine distances限定在[0, 2]范围内。要将二者组合起来,就需要归一化,而归一化参数取决于具体数据集。RRF只使用排名位置;无论评分方法是什么,排名位置始终是从1开始的整数。

学习型融合模型需要带标签的训练数据,即查询-文档相关性配对。对于个人知识库,这类训练数据并不存在。您需要手动评判数百个查询-文档配对,才能训练出有用的模型。RRF无需任何训练数据即可工作。

Condorcet投票方法(Borda count、Schulze method)在理论上很优雅,但实现和调优更复杂。最初的RRF论文证明,RRF在TREC评测数据上的表现优于Condorcet方法。3

实践中的融合

查询:”how does the review aggregator handle disagreements”

BM25将review-aggregator.py排在第3位(精确匹配”review”、”aggregator”、”disagreements”等关键词),但将两个配置文件排得更高(它们对”review”的匹配更突出)。Vector search将同一chunk排在第1位(在冲突解决语义上匹配)。经过RRF融合后:

Chunk BM25 Vec Fused Score
review-aggregator.py “Disagreement Resolution” #3 #1 0.0323
code-review-patterns.md “Multi-Reviewer” #4 #2 0.0317
deliberation-config.json “Review Weights” #1 0.0164

两个列表中都排名靠前的chunk会浮到顶部。只出现在一个列表中的chunk只会得到单一来源分数,并排在双列表排名结果之后。实际的分歧解决逻辑胜出,是因为两种方法都找到了它:BM25通过关键词找到,vector search通过语义找到。

如需查看包含逐排名RRF计算的完整分步追踪,可以在交互式RRF计算器中尝试不同的k值。

实现

RRF_K = 60

def _rrf_fuse(self, bm25_results, vec_results,
              bm25_weight=1.0, vec_weight=1.0):
    """Fuse BM25 and vector results using Reciprocal Rank Fusion."""
    scores = {}

    for rank, r in enumerate(bm25_results, start=1):
        cid = r["id"]
        if cid not in scores:
            scores[cid] = {
                "rrf_score": 0.0,
                "file_path": r["file_path"],
                "section": r["section"],
                "chunk_text": r["chunk_text"],
                "bm25_rank": None,
                "vec_rank": None,
            }
        scores[cid]["rrf_score"] += bm25_weight / (self._rrf_k + rank)
        scores[cid]["bm25_rank"] = rank

    for rank, r in enumerate(vec_results, start=1):
        cid = r["id"]
        if cid not in scores:
            scores[cid] = {
                "rrf_score": 0.0,
                "file_path": r["file_path"],
                "section": r["section"],
                "chunk_text": r["chunk_text"],
                "bm25_rank": None,
                "vec_rank": None,
            }
        scores[cid]["rrf_score"] += vec_weight / (self._rrf_k + rank)
        scores[cid]["vec_rank"] = rank

    fused = sorted(
        scores.values(),
        key=lambda x: x["rrf_score"],
        reverse=True,
    )
    return fused

调优k

k常数控制排名靠前的结果相对于排名较低的结果获得多少权重:

  • 较低的k(例如10):排名靠前的结果占主导。排名1的分数为1/11 = 0.091,排名10的分数为1/20 = 0.050(相差1.8倍)。当您信任各个排序器能够正确找出第一名结果时,这种设置较合适。
  • 默认k(60):较为均衡。排名1的分数为1/61 = 0.0164,排名10的分数为1/70 = 0.0143(相差1.15倍)。排名差异被压缩,因此出现在多个列表中的结果会获得更高权重。
  • 较高的k(例如200):是否同时出现在两个列表中,比排名位置本身重要得多。排名1的分数为1/201,排名10的分数为1/210,几乎相同。当单个排序器产生的排名噪声较大,但跨列表一致性可靠时,可以使用这种设置。

从k=60开始。最初的RRF论文发现,该值在多种TREC数据集上都很稳健。只有在基于您自己的查询分布衡量失败案例之后,才建议进一步调优。

平局处理

当两个chunk具有相同的RRF分数时(少见但可能发生,例如在一个列表中排名相同,且均未出现在另一个列表中),按以下规则打破平局:

  1. 优先选择同时出现在两个列表中的chunk,而不是只出现在一个列表中的chunk
  2. 在同时出现在两个列表中的chunk之间,优先选择合并排名更低的那个
  3. 在只出现在一个列表中的chunk之间,优先选择在该列表中排名更低的那个

完整检索流水线

本节追踪一次查询如何从输入到输出经过整条流水线:BM25搜索、向量搜索、RRF融合、token预算截断以及上下文组装。

端到端流程

User query: "PostToolUse hook for context compression"
  │
  ├─ BM25 Search (FTS5)
  │    → MATCH "PostToolUse hook context compression"
  │    → Top 30 results ranked by BM25 score
  │    → 12ms
  │
  ├─ Vector Search (sqlite-vec)
  │    → Embed query with Model2Vec
  │    → KNN k=30 on chunk_vecs
  │    → Top 30 results ranked by cosine distance
  │    → 8ms
  │
  └─ RRF Fusion
       → Merge 60 candidates (may overlap)
       → Score by rank position
       → Top 10 results
       → 3ms
       │
       └─ Token Budget
            → Truncate to max_tokens (default 4000)
            → Estimate at 4 chars per token
            → Return results with metadata
            → <1ms

总延迟:约23ms,基于Apple M3 Pro硬件上的49,746个chunk数据库测得。

Search API

class HybridRetriever:
    def search(self, query, limit=10, max_tokens=4000,
               bm25_weight=1.0, vec_weight=1.0):
        """
        Search the vault using hybrid BM25 + vector retrieval.

        Args:
            query: Search query text
            limit: Maximum results to return
            max_tokens: Token budget for total result text
            bm25_weight: Weight for BM25 results in RRF
            vec_weight: Weight for vector results in RRF

        Returns:
            List of SearchResult with file_path, section,
            chunk_text, rrf_score, bm25_rank, vec_rank
        """
        # BM25 search
        bm25_results = self._bm25_search(query, limit=30)

        # Vector search (if available)
        if self.index.vec_available:
            vec_results = self._vector_search(query, limit=30)
            fused = self._rrf_fuse(
                bm25_results, vec_results,
                bm25_weight, vec_weight,
            )
        else:
            fused = bm25_results  # BM25-only fallback

        # Token budget truncation
        results = []
        token_count = 0
        for r in fused[:limit]:
            chunk_tokens = len(r["chunk_text"]) // 4
            if token_count + chunk_tokens > max_tokens:
                break
            results.append(r)
            token_count += chunk_tokens

        return results

token预算截断

max_tokens参数用于防止检索器返回超过AI工具可用范围的上下文。估算方式采用每个token约4个字符(对英文散文而言是合理近似)。结果会按贪心策略截断:依排名顺序加入结果,直到预算耗尽。

这是一种保守策略。更复杂的做法会考虑每条结果的质量分数,并优先选择更短、质量更高的结果,而不是更长、质量更低的结果。贪心方法更简单,实践中效果也很好,因为RRF排名已经按相关性对结果排序。

数据库Schema(完整)

-- Chunk content and metadata
CREATE TABLE chunks (
    id INTEGER PRIMARY KEY,
    file_path TEXT NOT NULL,
    section TEXT NOT NULL,
    chunk_text TEXT NOT NULL,
    heading_context TEXT DEFAULT '',
    mtime_ns INTEGER NOT NULL,
    embedded_at REAL NOT NULL
);

CREATE INDEX idx_chunks_file ON chunks(file_path);
CREATE INDEX idx_chunks_mtime ON chunks(mtime_ns);

-- FTS5 for BM25 search (content-synced to chunks table)
CREATE VIRTUAL TABLE chunks_fts USING fts5(
    chunk_text, section, heading_context,
    content=chunks, content_rowid=id
);

-- sqlite-vec for vector KNN search
CREATE VIRTUAL TABLE chunk_vecs USING vec0(
    id INTEGER PRIMARY KEY,
    embedding float[256]
);

-- Model metadata for compatibility tracking
CREATE TABLE model_meta (
    key TEXT PRIMARY KEY,
    value TEXT
);

优雅降级路径

Full pipeline:     BM25 + Vector + RRF    Best results
No sqlite-vec:     BM25 only              Good results (no semantic)
No model download:  BM25 only              Good results (no semantic)
No FTS5:           Vector only             Decent results (no keyword)
No database:       Error                   Prompt user to run indexer

检索器会在初始化时检查能力,并调整查询策略。缺失某个组件会降低质量,但不会导致错误。唯一的硬性失败是数据库文件缺失。

生产环境统计

基于包含16,894个文件、49,746个chunk、83 MB SQLite数据库的vault测得,硬件为Apple M3 Pro:

指标
文件总数 16,894
chunk总数 49,746
数据库大小 83 MB
BM25查询延迟(p50) 12ms
向量查询延迟(p50) 8ms
RRF融合延迟 3ms
端到端搜索延迟(p50) 23ms
完整重新索引时间 约4分钟
增量重新索引时间 <10秒
embedding模型 potion-base-8M(256维)
BM25候选池 30
向量候选池 30
默认结果限制 10
默认token预算 4,000 tokens

内容哈希与变更检测

索引器需要知道自上次索引运行以来哪些文件发生了变化。本节介绍变更检测机制和哈希策略。

文件修改时间比较

索引器会在chunks表中为每个chunk存储mtime_ns(以纳秒计的文件修改时间)。在增量运行时,索引器会:

  1. 扫描vault中允许文件夹内的所有.md文件
  2. 从文件系统读取每个文件的mtime_ns
  3. 与数据库中存储的mtime_ns进行比较
  4. 识别3类文件:
  5. 新文件:路径存在于文件系统中,但不存在于数据库中
  6. 已变更文件:路径两边都存在,但mtime_ns不同
  7. 已删除文件:路径存在于数据库中,但不存在于文件系统中
def get_stale_files(self, vault_mtimes):
    """Find files whose mtime changed or are new."""
    stored = dict(self.db.execute(
        "SELECT DISTINCT file_path, mtime_ns FROM chunks"
    ).fetchall())

    stale = []
    for path, mtime in vault_mtimes.items():
        if path not in stored or stored[path] != mtime:
            stale.append(path)
    return stale

def get_deleted_files(self, vault_paths):
    """Find files in database that no longer exist in vault."""
    stored_paths = set(r[0] for r in self.db.execute(
        "SELECT DISTINCT file_path FROM chunks"
    ).fetchall())
    return stored_paths - set(vault_paths)

为什么使用mtime,而不是内容哈希

内容哈希(文件内容的SHA-256)会比mtime比较更可靠,因为它能检测到文件被触碰但内容未变的情况(例如git checkout恢复了原始mtime)。不过,哈希要求在每次增量运行时读取每个文件。对于16,894个文件,读取文件内容需要2到3秒。从文件系统读取mtime则不到100ms。

取舍在于:mtime比较偶尔会对未变更文件触发不必要的重新索引(误报),但不会漏掉实际变更。误报的代价只是每次运行多几个embedding调用。速度差异(100ms对3秒)让mtime成为务实之选,尤其是该系统会在每次AI交互时运行。

处理删除

当文件从vault中删除时,索引器会从数据库中移除该文件的所有chunk:

def remove_file(self, file_path):
    """Remove all chunks and vectors for a file."""
    chunk_ids = [r[0] for r in self.db.execute(
        "SELECT id FROM chunks WHERE file_path = ?",
        [file_path],
    ).fetchall()]

    for cid in chunk_ids:
        self.db.execute(
            "DELETE FROM chunk_vecs WHERE id = ?", [cid]
        )
    self.db.execute(
        "DELETE FROM chunks WHERE file_path = ?",
        [file_path],
    )

自sqlite-vec v0.1.7起,DELETE FROM chunk_vecs语句可原生工作;v0.1.9又修复了针对带有较长元数据文本列的vec0表执行DELETE操作的bug。1423更早版本需要变通方案(删除并重建虚拟表,或维护一个外部“active IDs”集合)。如果运行的是0.1.9之前的版本,请先升级,再依赖元数据较重schema中的直接删除。

FTS5内容同步表需要通过INSERT INTO chunks_fts(chunks_fts, rowid, ...) VALUES('delete', ?, ...)为每个被移除的行显式删除。索引器会将此作为文件移除流程的一部分处理。


增量重建索引与完整重建索引

索引器支持两种模式:增量模式(速度快,适合日常使用)和完整模式(速度慢,偶尔使用)。本节介绍各自的使用场景、幂等性保证以及损坏恢复。

增量重建索引

使用场景:编辑笔记后的日常索引。默认模式。

执行内容: 1. 扫描知识库中的文件变更(比较mtime) 2. 删除已删除文件对应的chunk 3. 对已变更文件重新chunking并重新生成embeddings 4. 为新文件插入新的chunk 5. 同步FTS5索引

典型耗时:对于包含16,000个文件的知识库,一天编辑量通常少于10秒。

python index_vault.py --incremental

完整重建索引

使用场景: - 更改embedding模型后(检测到模型哈希不匹配) - schema迁移后(新增列、变更索引) - 数据库损坏后(完整性检查失败) - 增量索引产生意外结果时

执行内容: 1. 删除所有现有数据(chunks、vectors、FTS5条目) 2. 扫描整个知识库 3. 对所有文件进行chunking 4. 为所有chunk生成embeddings 5. 从头构建FTS5索引

典型耗时:在Apple M3 Pro上处理16,894个文件约需4分钟。

python index_vault.py --full

幂等性

两种模式都是幂等的:同一命令运行两次会产生相同结果。索引器会先删除某个文件已有的chunk,再插入新的chunk。因此,对已经是最新状态的数据库重新运行增量索引会产生零变更。重新运行完整索引会生成完全相同的数据库。

损坏恢复

如果SQLite数据库损坏(写入期间断电、磁盘错误、事务中途进程被终止):

# Check integrity
sqlite3 vectors.db "PRAGMA integrity_check;"

# If corruption detected, full reindex rebuilds from source files
python index_vault.py --full

真实数据源始终是知识库文件,而不是数据库。数据库是派生产物,可以随时重建。这是一项关键设计属性:您永远不需要备份数据库。

--incremental标志

索引器使用--incremental运行时:

  1. 模型哈希检查。将存储的模型哈希与当前模型进行比较。如果不同,自动切换到完整重建索引模式,并向用户发出警告。
  2. 文件扫描。遍历允许的文件夹,收集文件路径和mtime。
  3. 变更检测。与已存储数据进行比较。
  4. 批量处理。以64个文件为一批,对已变更文件重新chunking并重新生成embeddings。
  5. 进度报告。打印已处理文件数量和耗时。
  6. 优雅关闭。处理SIGINT时,先完成当前文件再停止。

凭据过滤与数据边界

个人笔记中可能包含密钥:API密钥、bearer tokens、数据库连接字符串、调试期间粘贴的私钥。凭据过滤器会阻止这些内容进入检索索引。

问题

一篇关于调试OAuth集成的笔记可能包含:

The token was: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...
I used this curl command:
  curl -H "Authorization: Bearer sk-ant-api03-abc123..."

如果不进行过滤,JWT和API密钥都会被chunking、生成embeddings,并存入数据库。搜索“authentication”会返回包含真实密钥的chunk。更糟的是,如果检索器通过MCP将结果提供给AI工具,这些密钥会出现在AI的上下文窗口中,并可能进入工具日志。

基于模式的过滤

凭据过滤器会在每个chunk入库存储前运行,匹配25种供应商特定模式以及通用模式:

供应商特定模式:

Pattern Example Regex
OpenAI API key sk-... sk-[a-zA-Z0-9_-]{20,}
Anthropic API key sk-ant-api03-... sk-ant-api\d{2}-[a-zA-Z0-9_-]{20,}
GitHub PAT ghp_... gh[ps]_[a-zA-Z0-9]{36,}
AWS Access Key AKIA... AKIA[0-9A-Z]{16}
Stripe key sk_live_... [sr]k_(live\|test)_[a-zA-Z0-9]{24,}
Cloudflare token ... 各类模式

通用模式:

Pattern Detection
JWT tokens eyJ[a-zA-Z0-9_-]+\.eyJ[a-zA-Z0-9_-]+
Bearer tokens Bearer\s+[a-zA-Z0-9_\-\.]+
Private keys -----BEGIN (RSA\|EC\|OPENSSH) PRIVATE KEY-----
高熵base64 字符串熵值>4.5 bits/char,且长度40+字符
密码赋值 password\s*[:=]\s*["'][^"']+["']

过滤器实现

def clean_content(text):
    """Scrub credentials from text before indexing."""
    result = ScanResult(is_clean=True, match_count=0, patterns=[])

    for pattern in CREDENTIAL_PATTERNS:
        matches = pattern.regex.findall(text)
        if matches:
            text = pattern.regex.sub(
                f"[REDACTED:{pattern.name}]", text
            )
            result.is_clean = False
            result.match_count += len(matches)
            result.patterns.append(pattern.name)

    return text, result

关键设计选择:

  1. 先过滤,再生成embedding。用于生成embedding的是清理后的文本。向量表示永远不会编码凭据模式。查询“API key”会返回讨论API密钥管理的笔记,而不是包含真实密钥的笔记。

  2. 替换,而不是删除。[REDACTED:pattern-name]标记会保留周围文本的语义上下文。embedding会捕捉到“这里曾有类似凭据的内容”,但不会编码凭据本身。

  3. 记录模式,不记录值。过滤器会记录匹配到哪些模式(例如“Scrubbed 2 credential(s) from oauth-debug.md [jwt, bearer-token]”),但绝不会记录凭据值。

基于路径的排除

.indexignore文件提供按路径进行的粗粒度排除。凭据过滤器则在已索引文件内部提供细粒度清理。二者缺一不可:

  • .indexignore用于明确包含敏感内容的整个文件夹(健康笔记、财务记录、职业文档)
  • 凭据过滤器用于清理意外嵌入在原本可索引内容中的密钥

数据分类

对于包含多样内容的知识库,可以考虑按敏感度对笔记进行分类:

Level Examples Index? Filter?
Public 博客草稿、技术笔记
Internal 项目计划、架构决策
Sensitive 薪资数据、健康记录 否(.indexignore) N/A
Restricted 凭据、私钥 否(.indexignore) N/A

MCP 服务器架构

Model Context Protocol(MCP)服务器将检索器作为 AI 代理可调用的工具公开。本节介绍服务器设计、能力范围和权限边界。

协议选择:STDIO 与 HTTP

MCP 支持两种传输模式:

STDIO — AI 工具将 MCP 服务器作为子进程启动,并通过 stdin/stdout 通信。这是本地工具的标准模式。Claude Code、Codex CLI 和 Cursor 都支持 STDIO MCP 服务器。

{
  "mcpServers": {
    "obsidian": {
      "command": "python",
      "args": ["/path/to/obsidian_mcp.py"],
      "env": {
        "VAULT_PATH": "/path/to/vault",
        "DB_PATH": "/path/to/vectors.db"
      }
    }
  }
}

HTTP — MCP 服务器作为独立的 HTTP 服务运行。适用于远程访问、多客户端设置,或 vault 位于共享服务器上的团队配置。

{
  "mcpServers": {
    "obsidian": {
      "url": "http://localhost:3333/mcp"
    }
  }
}

建议:个人 vault 使用 STDIO。它更简单、更安全(不会暴露到网络),而且服务器生命周期由 AI 工具管理。仅当多个工具或多台机器需要并发访问同一 vault 时,才使用 HTTP。

MCP 规范演进。2025年6月的 MCP 规范新增了 OAuth 2.1 授权、结构化工具输出(带类型的返回 schema)和 elicitation(由服务器发起的用户提示)。2025年11月发布的版本将 Streamable HTTP 作为一等传输模式推出,加入用于自动浏览服务器能力的 .well-known URL 发现机制、声明工具为只读或会修改内容的结构化工具注释,以及 SDK 分层标准化系统。79 下一次修订现已明确:2026-07-28 规范于2026年5月21日进入 Release Candidate 阶段,这是 MCP 自发布以来规模最大的一次修订。其主要变化包括:无状态协议核心(移除了 initialize 握手和 Mcp-Session-Id 标头,因此服务器不再跟踪每个连接的会话状态)、MCP Apps(服务器可返回在沙盒化客户端 iframe 中显示的服务端渲染 HTML)、Tasks 从实验性核心功能升级为正式扩展(为长时间运行的操作提供 tasks/gettasks/updatetasks/cancel)、强化的 OAuth 2.0 / OIDC 授权,以及 12个月功能弃用生命周期政策。它已按计划作为2026年7月28日修订版发布,现为 Current 规范(已于2026年8月14日验证)。24 对于个人 vault 服务器,STDIO 仍是最简单的路径;无状态核心也让单用户 STDIO 服务器更加精简。Streamable HTTP 传输、.well-known 发现机制和 MCP Apps 主要惠及采用多租户路由和负载均衡的企业 HTTP 部署。请关注MCP 路线图,了解可能影响传输方式选择的更新。

能力设计

MCP 服务器应公开一组精简的工具:

search — 主要工具。执行 hybrid 检索并返回排序后的结果。

{
  "name": "obsidian_search",
  "description": "Search the Obsidian vault using hybrid BM25 + vector retrieval",
  "parameters": {
    "query": { "type": "string", "description": "Search query" },
    "limit": { "type": "integer", "default": 5 },
    "max_tokens": { "type": "integer", "default": 2000 }
  }
}

read_note — 按路径读取特定笔记的完整内容。当代理希望查看搜索结果的完整上下文时很有用。

{
  "name": "obsidian_read_note",
  "description": "Read the full content of a note by file path",
  "parameters": {
    "file_path": { "type": "string", "description": "Relative path within vault" }
  }
}

list_notes — 列出符合筛选条件的笔记(按文件夹、标签、类型或日期范围)。当代理没有具体查询时,可用于探索。

{
  "name": "obsidian_list_notes",
  "description": "List notes matching filters",
  "parameters": {
    "folder": { "type": "string", "description": "Folder path within vault" },
    "tag": { "type": "string", "description": "Tag to filter by" },
    "limit": { "type": "integer", "default": 20 }
  }
}

get_context — 一个便捷工具,执行搜索并将结果格式化为适合注入对话的上下文块。

{
  "name": "obsidian_get_context",
  "description": "Get formatted context from vault for a topic",
  "parameters": {
    "topic": { "type": "string", "description": "Topic to get context for" },
    "max_tokens": { "type": "integer", "default": 2000 }
  }
}

权限边界

MCP 服务器应严格执行以下边界:

  1. 只读。服务器读取 vault 和索引数据库,但不会创建、修改或删除笔记。写入操作(例如捕获新笔记)由独立的 hooks 或 skills 处理,而非 MCP 服务器。

  2. 限定于 vault。服务器只读取已配置 vault 路径内的文件。必须拒绝路径遍历尝试(../../etc/passwd)。

  3. 凭据过滤输出。即使数据库包含预先过滤的内容,也应在输出时执行凭据过滤,作为纵深防御措施。

  4. Token 限制响应。对所有工具响应强制执行 max_tokens,防止 AI 工具接收过大的上下文块。

错误处理

MCP 工具应返回结构化错误消息,以帮助 AI 工具恢复:

def search(self, query, limit=5, max_tokens=2000):
    if not self.db_path.exists():
        return {
            "error": "Index database not found. Run the indexer first.",
            "suggestion": "python index_vault.py --full"
        }

    results = self.retriever.search(query, limit, max_tokens)

    if not results:
        return {
            "results": [],
            "message": f"No results found for '{query}'. Try broader terms."
        }

    return {
        "results": [
            {
                "file_path": r["file_path"],
                "section": r["section"],
                "text": r["chunk_text"],
                "score": round(r["rrf_score"], 4),
            }
            for r in results
        ],
        "count": len(results),
        "query": query,
    }

Claude Code 集成

Claude Code 是 Obsidian 检索系统的主要使用者。本节涵盖 MCP 配置、hook 集成以及 obsidian_bridge.py 模式。

MCP 配置

使用 claude mcp add 注册自定义服务器(用户范围会写入 ~/.claude.json-s project 会写入可共享的 .mcp.json~/.claude/settings.json 不是 MCP 配置入口):

claude mcp add obsidian -s user \
  -e VAULT_PATH=/absolute/path/to/vault \
  -e DB_PATH=/absolute/path/to/vectors.db \
  -- python /path/to/obsidian_mcp.py

如果您更倾向于手动编写,等效的 .mcp.json 条目如下:

{
  "mcpServers": {
    "obsidian": {
      "command": "python",
      "args": ["/path/to/obsidian_mcp.py"],
      "env": {
        "VAULT_PATH": "/absolute/path/to/vault",
        "DB_PATH": "/absolute/path/to/vectors.db"
      }
    }
  }
}

添加配置后,重启 Claude Code。MCP 服务器将作为子进程启动。请验证其是否正在运行:

> What tools do you have from the obsidian MCP server?

Claude Code 应列出可用工具(obsidian_searchobsidian_read_note 等)。

Hook 集成

Hook 会在已定义的生命周期节点扩展 Claude Code 的行为。与 Obsidian 集成相关的有两个 hook:

Hook 在 settings 中注册~/.claude/settings.json 中的 hooks 键下,包含事件名称和 matcher),并通过 stdin 接收 JSON 负载——不存在会被 Claude Code 自动发现的 hooks 目录,工具详情也绝不会通过 $1/$2 参数传入。

UserPromptSubmit hook——在您提交提示时查询知识库,并注入相关上下文(此事件的 stdout 会被加入对话):

{
  "hooks": {
    "UserPromptSubmit": [
      {
        "hooks": [{ "type": "command", "command": "/path/to/obsidian-context.sh" }]
      }
    ]
  }
}
#!/bin/bash
# obsidian-context.sh — read the JSON payload from stdin
PROMPT=$(jq -r '.prompt // empty')
[ -z "$PROMPT" ] && exit 0
CONTEXT=$(python /path/to/retriever.py search "$PROMPT" --limit 3 --max-tokens 1500)
if [ -n "$CONTEXT" ]; then
    printf 'Relevant vault context:\n%s\n' "$CONTEXT"   # stdout -> added as context
fi

PostToolUse hook——将重要工具输出捕获回知识库,以便日后检索(通过 matcher 注册,因此只会针对您关注的工具触发):

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write|Bash",
        "hooks": [{ "type": "command", "command": "/path/to/capture-insight.sh" }]
      }
    ]
  }
}
#!/bin/bash
# capture-insight.sh — tool name and response arrive as stdin JSON
PAYLOAD=$(cat)
TOOL_NAME=$(printf '%s' "$PAYLOAD" | jq -r '.tool_name')
OUTPUT=$(printf '%s' "$PAYLOAD" | jq -r '.tool_response // "" | tostring')
if [ ${#OUTPUT} -gt 500 ]; then
    python /path/to/capture.py --text "$OUTPUT" --source "claude-code-$TOOL_NAME"
fi

obsidian_bridge.py 模式

桥接模块提供了一个可供 hooks 和 skills 调用的 Python API:

# obsidian_bridge.py
from retriever import HybridRetriever

_retriever = None

def get_retriever():
    global _retriever
    if _retriever is None:
        _retriever = HybridRetriever(
            db_path="/path/to/vectors.db",
            vault_path="/path/to/vault",
        )
    return _retriever

def search_vault(query, limit=5, max_tokens=2000):
    """Search vault and return formatted context."""
    retriever = get_retriever()
    results = retriever.search(query, limit, max_tokens)

    if not results:
        return ""

    lines = ["## Vault Context\n"]
    for r in results:
        lines.append(f"**{r['file_path']}** — {r['section']}")
        lines.append(f"> {r['chunk_text'][:500]}")
        lines.append("")

    return "\n".join(lines)

/capture Skill

用于将洞见捕获回知识库的 Claude Code skill:

/capture "OAuth token rotation requires both access and refresh token invalidation"
  --domain security
  --tags oauth,tokens

该 skill 会在 00-inbox/ 中创建一条带有正确 frontmatter 的新笔记,并触发增量重新索引,使新笔记能够立即被检索。

自定义命令模式

Claude Code skills 可以将知识库操作封装为具名命令。实践者已构建 Obsidian 专用命令库,将知识库同时作为读取来源和写入目标。

信号扫描。/scan-intel 命令会查询外部来源,根据个人研究兴趣对发现进行评分,并将符合条件的信号以带有 frontmatter 的知识库笔记形式写入:

/scan-intel --topics "agent infrastructure, security" --lookback 7d

该命令从已配置的来源(arXiv、HN、RSS)获取内容,应用评分模型(相关性、可执行性、深度、权威性),并将通过筛选的信号写入特定主题的知识库文件夹。知识库由此成为自动化情报管道的下游使用者。

船长日志。/captains-log 命令会汇总所有仓库的每日 git 活动,将结构化日志条目写入知识库,并包含已做出的决策、领悟和待处理线索:

/captains-log

该命令从 GitHub 提取提交历史,按仓库分组,并格式化为叙事式日志条目。随着时间推移,这些每日日志会形成可检索的记录,说明发布了什么以及原因何在。

Obsidian 捕获。/obsidian-capture 命令会从当前 Claude Code 会话中提取一条洞见,并将其连同正确的元数据直接写入知识库:

/obsidian-capture "SAST gates in agent loops increase security degradation"
  --folder AI-Tools --tags security,agents

这一模式可扩展到任何知识库操作:创建 MOC、更新项目状态笔记、关联相关信号,或根据累积的每日日志生成每周摘要。

社区示例。实践者正在发布各自的命令库。一位开发者分享了 22 个自定义的 Obsidian + Claude Code 命令,覆盖每日复盘、项目规划、研究捕获和内容工作流。1另一位开发者构建了一个“Visual Explainer” skill,可根据代码分析在知识库中生成图表笔记。2命令各有不同,但架构始终一致:Claude Code skills 作为接口,知识库笔记作为存储层,检索基础设施作为查询引擎。

上下文窗口管理

集成时应注意 Claude Code 的上下文窗口:

  • 将每次查询注入的上下文限制在 1,500-2,000 tokens。超过此范围会挤占 agent 的工作记忆。
  • 包含来源归属信息。始终包含文件路径和章节标题,以便 agent 能引用来源。
  • 截断 chunk 文本。长 chunk 应使用 ... 截断,而非完全省略。前 300-500 个字符通常包含关键信息。
  • 不要在每个提示中注入。注入通过 UserPromptSubmit 运行(其 stdout 会传递给模型的事件),因此应在此处控制预算:跳过简短的对话式提示,仅在提示提及代码、文件或过往决策时注入,并限制注入块大小。PreToolUse 等工具范围事件可用于拦截或记录,但其 stdout 永远不会传递给模型。

Codex CLI 集成

Codex CLI 通过 config.toml 连接到 MCP 服务器。该集成模式与 Claude Code 在配置语法和指令传递方面有所不同。

MCP 配置

添加到 ~/.codex/config.toml(Codex 读取 $CODEX_HOME/config.toml;项目级指令应放在 AGENTS.md 中,而非项目配置文件):

[mcp_servers.obsidian]
command = "python"
args = ["/path/to/obsidian_mcp.py"]

[mcp_servers.obsidian.env]
VAULT_PATH = "/absolute/path/to/vault"
DB_PATH = "/absolute/path/to/vectors.db"

AGENTS.md 模式

Codex CLI 会读取 AGENTS.md 中的项目级指令。请加入知识库搜索指南:

## Available Tools

### Obsidian Vault (MCP: obsidian)
Use the `obsidian_search` tool to find relevant context from the knowledge base.
Search the vault when you need:
- Background on a concept or pattern
- Prior decisions or rationale
- Reference material for implementation

Example queries:
- "authentication patterns in FastAPI"
- "how does the review aggregator work"
- "sqlite-vec configuration"

与 Claude Code 的差异

功能 Claude Code Codex CLI
MCP 配置 claude mcp add~/.claude.json / 项目 .mcp.json ~/.codex/config.toml
Hooks 在 Settings 中注册,31 个生命周期事件,通过 stdin 接收 JSON 支持(稳定接口;具有独立事件集)
Skills ~/.claude/skills/ ~/.codex/skills/(稳定)
指令文件 CLAUDE.md AGENTS.md
权限机制 模式:Manual / acceptEdits / auto(自2026年8月14日起,Pro/Max/Team 默认启用)/ plan / bypassPermissions 审批策略 untrusted / on-request / never × 沙箱 read-only / workspace-write / danger-full-access--full-auto 已在 v0.147.0 中移除)

关键差异:两种工具现在都支持 hooks 和 skills;不同之处在于其形式。Codex 将审批策略与操作系统级沙箱模式配对使用,而不是采用 Claude Code 的权限模式;其 hook 事件也不同——应迁移模式(工作前查询知识库、工作后捕获),而不是配置。对于 Codex 中长期生效的“先搜索知识库”指令,AGENTS.md 仍是正确的位置。

Cursor 和其他工具

Cursor 及其他支持 MCP 的 AI 工具都可以连接到同一个 Obsidian MCP 服务器。本节介绍常用工具的配置方法。

Cursor

在项目根目录的 .cursor/mcp.json 中添加:

{
  "mcpServers": {
    "obsidian": {
      "command": "python",
      "args": ["/path/to/obsidian_mcp.py"],
      "env": {
        "VAULT_PATH": "/absolute/path/to/vault",
        "DB_PATH": "/absolute/path/to/vectors.db"
      }
    }
  }
}

Cursor 的 .cursorrules 文件可以包含使用 vault 的说明:

When working on implementation tasks, search the Obsidian vault
for relevant context before writing code. Use the obsidian_search
tool with descriptive queries about the concept you're implementing.

兼容性矩阵

工具 MCP 支持 传输方式 配置位置
Claude Code 完整 STDIO claude mcp add~/.claude.json / 项目 .mcp.json
Codex CLI 完整 STDIO ~/.codex/config.toml
Cursor 完整 STDIO .cursor/mcp.json
Windsurf 完整 STDIO ~/.codeium/windsurf/mcp_config.json
Continue.dev 完整 STDIO + HTTP ~/.continue/config.yamlmcpServers
Zed 完整(context servers) STDIO settings.jsoncontext_servers
Claudian(Obsidian 插件) 不适用(内嵌) Claude Code CLI Obsidian 插件设置
Agent Client(Obsidian 插件) 不适用(内嵌) ACP Obsidian 插件设置

不支持 MCP 工具的后备方案

对于不支持 MCP 的工具,可以将 retriever 封装为 CLI:

# Search from command line
python retriever_cli.py search "query text" --limit 5

# Output formatted for copy-paste into any tool
python retriever_cli.py context "query text" --format markdown

CLI 会输出结构化文本,可手动粘贴到任何 AI 工具的输入中。虽然不如 MCP 集成优雅,但具有通用性。


从结构化笔记进行 Prompt 缓存

vault 中的结构化笔记可作为可复用的上下文块,减少 AI 交互过程中的 token 用量。本节介绍缓存键设计和 token 预算管理。

模式

无需在每次交互时搜索上下文,而是从结构良好的 vault 笔记预先构建上下文块并进行缓存:

# cache_keys.py
CONTEXT_BLOCKS = {
    "auth-patterns": {
        "vault_query": "authentication patterns implementation",
        "max_tokens": 1500,
        "ttl_hours": 24,  # Rebuild daily
    },
    "api-conventions": {
        "vault_query": "API design conventions REST patterns",
        "max_tokens": 1000,
        "ttl_hours": 168,  # Rebuild weekly
    },
    "project-architecture": {
        "vault_query": "current project architecture decisions",
        "max_tokens": 2000,
        "ttl_hours": 12,  # Rebuild twice daily
    },
}

缓存失效

缓存失效依据两种信号:

  1. TTL 到期。每个上下文块都有存活时间。TTL 到期后,会通过重新查询 vault 来重建该块。
  2. Vault 变更检测。当 indexer 检测到曾为某个缓存上下文块提供内容的文件发生变化时,会立即使该块失效。

Token 预算管理

一次会话开始时会设定总上下文预算。缓存块会占用其中一部分预算:

Total context budget:    8,000 tokens
├─ System prompt:        1,500 tokens
├─ Cached blocks:        3,000 tokens (pre-loaded)
├─ Dynamic search:       2,000 tokens (on-demand)
└─ Conversation:         1,500 tokens (remaining)

缓存块会在会话开始时加载。动态搜索结果则按每个查询填充剩余预算。这种 hybrid 方法既为 agent 提供了常用上下文的基础,又为特定查询保留了预算。

缓存前后的 Token 用量

未使用缓存:每个相关查询都会触发一次 vault 搜索,返回 1,500-2,000 token 的上下文。在一次会话的 10 次查询中,agent 会消耗 15,000-20,000 token 的 vault 上下文。

使用缓存:3 个预构建上下文块总共占用 4,500 token。每个唯一查询的额外搜索会增加 1,500-2,000 token。在 10 次查询中,如果其中 6 次由缓存块覆盖,agent 消耗的 token 为 4,500 +(4 * 1,500)= 10,500,约为未缓存用量的一半。


捕获冗长输出的压缩摘要

工具输出可能十分冗长:堆栈跟踪、文件列表、测试结果。Hook 无法缩减模型实际看到的内容——到 PostToolUse 触发时,完整输出已经进入上下文窗口,hook 输出的任何内容都无法替换它。不过,hook 可以 将压缩摘要写入 vault,使后续会话获取两行结论,而不是重新运行或重读 5,000 token 的原始内容。应将其视为跨会话记忆的捕获模式,而非会话内的上下文节省方案(在会话内,真正有效的手段是 /compact、限定范围的 prompt,以及请求更简洁的输出)。

问题

运行测试的 Bash 工具调用可能返回:

PASSED tests/test_auth.py::test_login_success
PASSED tests/test_auth.py::test_login_failure
PASSED tests/test_auth.py::test_token_refresh
PASSED tests/test_auth.py::test_session_expiry
... (200 more lines)
FAILED tests/test_api.py::test_rate_limit_exceeded

完整输出为 5,000 token,但关键信息只有 2 行:200 个通过,1 个失败。

Hook 实现

通过带有 Bash matcher 的 PostToolUse 注册(在 settings 中注册,stdin JSON——请参阅上文的 Hook Integration):

#!/bin/bash
# summarize-and-capture.sh — write a compressed summary to the vault
PAYLOAD=$(cat)
OUTPUT=$(printf '%s' "$PAYLOAD" | jq -r '.tool_response // "" | tostring')

# Only summarize large outputs
[ ${#OUTPUT} -lt 2000 ] && exit 0

if printf '%s' "$OUTPUT" | grep -q "PASSED\|FAILED"; then
    PASSED=$(printf '%s' "$OUTPUT" | grep -c "PASSED")
    FAILED=$(printf '%s' "$OUTPUT" | grep -c "FAILED")
    SUMMARY="Tests: $PASSED passed, $FAILED failed"
    [ "$FAILED" -gt 0 ] && SUMMARY="$SUMMARY
$(printf '%s' "$OUTPUT" | grep 'FAILED')"
    python /path/to/capture.py --text "$SUMMARY" --source "test-run-summary"
fi
exit 0

每次 hook 调用都是一个全新的进程,因此无需递归保护——hook 自身的写入不会再次触发它,导出的变量也不会保留到下一次调用。

压缩启发式规则

输出类型 检测方式 压缩策略
测试结果 PASSED / FAILED 关键词 统计通过/失败数量,仅显示失败项
文件列表 命令中包含 lsfind 截断为前 20 个条目 + 总数
堆栈跟踪 Traceback 关键词 保留首尾调用帧及错误消息
Git 状态 modified: / new file: 按状态汇总数量
构建输出 warning: / error: 移除信息行,保留警告/错误

信号接入与分诊流水线

接入层决定哪些内容进入知识库。缺乏筛选时,知识库会不断积累噪声。本节介绍将信号路由到领域文件夹的评分流水线。

来源

信号来自多个渠道:

  • RSS订阅源: 技术博客、安全公告、发布说明
  • 通过 Web Clipper 添加的书签: 官方 Obsidian Web Clipper 扩展(Chrome、Firefox、Safari)是在浏览器端捕获内容时保真度最高的接入方式。2026年4月的发布周期使其在 AI 工作流中明显更实用:22
    • 1.4.0(4月9日): 交互式 YouTube 字幕稿 UI——可固定视频、在字幕稿中拖动定位、自动滚动并高亮当前位置。此外,“在阅读器中打开”默认选项可一键将捕获内容直接发送至阅读器模式。
    • 1.5.0–1.5.1(4月15日): 高亮查看器——可浏览和搜索整个知识库中已捕获的高亮内容。淡入过渡至阅读器模式。YouTube 播放/暂停更流畅。1.5.1 修复了 webpack 编译回归问题。
    • 1.6.0–1.6.2(4月21日至23日): 重构了高亮标注 UX,并支持移动端。Defuddle 0.18 为 LinkedIn、Threads、Bluesky、Discourse 和 Medium 添加了特定来源的提取器。1.6.2 修复了 Safari 嵌入模式下的剪贴板回归问题。 请按来源域名配置模板,使 YouTube 字幕稿、GitHub README 以及长篇文章分别进入命名合理的笔记,并带有适用于下方评分流水线的正确 frontmatter。
  • 新闻邮件: 从电子邮件新闻通讯中摘录的关键片段
  • 手动捕获: 阅读、交流或研究过程中撰写的笔记
  • 工具输出: 通过 hooks 捕获的重要 AI 工具输出
  • iOS 分享扩展: Obsidian 的 iOS 应用(于2026年初更新)提供了分享扩展,可将 Safari、社交网络及其他应用中的内容直接保存到知识库,无需打开 Obsidian;1.13 系列新增了带模板变量的可配置分享表目标,其中包括 url,因此捕获页面会自动将其来源链接记录到 frontmatter 中。19 这提供了一条低摩擦的移动端接入路径——从 Safari 分享文章后,它会作为已准备好评分的知识库笔记到达。
  • Obsidian CLI: Shell 脚本和 hooks 可通过 obsidian file create 创建笔记,或通过 obsidian file append 向现有笔记追加内容,从而在桌面端实现自动化接入流水线。

评分维度

每条信号均按4个维度评分(每项为0.0至1.0):

维度 问题 低分(0.0-0.3) 高分(0.7-1.0)
相关性 它是否与我的活跃领域相关? 关联较弱、超出范围 与当前工作直接相关
可操作性 我能使用这些信息吗? 纯理论、无应用场景 可应用的具体技术或模式
深度 内容有多实质? 标题、浅层摘要 包含示例的详细分析
权威性 来源的可信度如何? 匿名博客、未经验证 一手来源、同行评审、知名专家

综合评分与路由

composite = (relevance * 0.35) + (actionability * 0.25) +
            (depth * 0.25) + (authority * 0.15)
分数范围 操作
0.55+ 自动路由到领域文件夹
0.40 - 0.55 加入人工审核队列
< 0.40 丢弃(不存储)

领域路由

得分高于0.55的信号会根据关键词匹配和主题分类,被路由到12个领域文件夹之一:

05-signals/
├── ai-tooling/        # Claude, LLMs, AI development tools
├── security/          # Vulnerabilities, auth, cryptography
├── systems/           # Architecture, distributed systems
├── programming/       # Languages, patterns, algorithms
├── web/               # Frontend, backends, APIs
├── data/              # Databases, data engineering
├── devops/            # CI/CD, containers, infrastructure
├── design/            # UI/UX, product design
├── mobile/            # iOS, Android, cross-platform
├── career/            # Industry trends, hiring, growth
├── research/          # Academic papers, whitepapers
└── other/             # Signals that don't fit a domain

生产统计

运行14个月后:

指标 数值
已处理信号总数 7,771
自动路由(>0.55) 4,832(62%)
等待审核(0.40-0.55) 1,543(20%)
已丢弃(<0.40) 1,396(18%)
活跃领域文件夹 12
日均信号数 ~18

知识图谱模式

Obsidian 的 wiki-link 图谱编码了笔记之间的关系。本节介绍链接语义、用于上下文扩展的图遍历,以及会降低图谱质量的反模式。

每个 wiki-link 都会在图中创建一条有向边。Obsidian 会同时跟踪正向链接和 backlink:

  • 正向链接: 笔记 A 包含 [[Note B]] → A 链接至 B
  • Backlink: 笔记 B 显示笔记 A 引用了它

图谱会根据上下文编码不同类型的关系:

链接模式 语义 示例
内联链接 “与……相关” “详情请参阅 [[OAuth Token Rotation]]”
标题链接 “包含子主题” “## Related\n- [[Token Rotation]]\n- [[Session Management]]”
类标签链接 “归类为” ”[[type/reference]]”
MOC 链接 “属于……的一部分” 列出相关笔记的 Maps of Content 笔记

Maps of Content(MOCs)

MOC 是索引笔记,可将相关笔记组织成便于导航的结构:

---
title: "Authentication & Security MOC"
type: moc
domain: security
---

## Core Concepts
- [[OAuth 2.0 Overview]]
- [[JWT Token Anatomy]]
- [[Session Management Patterns]]

## Implementation Patterns
- [[OAuth Token Rotation]]
- [[Refresh Token Security]]
- [[PKCE Flow Implementation]]

## Failure Modes
- [[Token Expiry Handling]]
- [[Session Fixation Prevention]]
- [[CSRF Defense Strategies]]

MOC 可通过两种方式提升检索效果:

  1. 直接匹配。 搜索“身份验证概览”时会匹配 MOC 本身,为 agent 提供经整理的相关笔记列表。
  2. 上下文扩展。 找到特定笔记后,检索器可检查该笔记是否出现在任何 MOC 中,并将 MOC 的结构纳入结果,为 agent 提供更广泛主题的地图。

用于上下文扩展的图遍历

检索器的未来增强方向:找到排名靠前的结果后,沿链接扩展上下文:

def expand_context(results, depth=1):
    """Follow wiki-links from top results to find related context."""
    expanded = set()
    for result in results:
        # Parse wiki-links from chunk text
        links = extract_wiki_links(result["chunk_text"])
        for link_target in links:
            # Resolve link to file path
            target_path = resolve_wiki_link(link_target)
            if target_path and target_path not in expanded:
                expanded.add(target_path)
                # Include target's most relevant chunk
                target_chunks = get_chunks_for_file(target_path)
                # ... rank and include best chunk
    return results + list(expanded_results)

当前检索器尚未实现这一点,但它是图谱结构的自然扩展。

反模式

孤立簇。 一组彼此链接、却与知识库其余部分没有连接的笔记。Obsidian 中的图谱面板会将它们显示为彼此断开的孤岛。孤立簇表明缺少 MOC 或跨领域链接。

标签蔓延。 标签使用不一致,或创建了过多细粒度标签。一个包含5,000篇笔记、却有500个唯一标签的知识库,平均每10个标签只有1篇笔记——这些标签并不适合筛选。应整合为20至50个与领域文件夹对应的高层级标签。

链接密集、内容稀少的笔记。 完全由 wiki-link 组成、没有任何正文的笔记。这类笔记的索引效果不佳,因为 chunker 没有可用于嵌入的文本。至少添加一段上下文,说明这些链接笔记为何相关。

为所有内容建立双向链接。 并非每次引用都需要 wiki-link。顺带提及“OAuth”并不需要 [[OAuth 2.0 Overview]]。应将 wiki-link 保留给有意建立、可供导航的关系:点击链接时应能提供有用的上下文。

开发者工作流配方

将知识库检索与日常开发任务结合起来的实用工作流。

早晨上下文加载

通过加载相关上下文开始一天的工作:

Search my vault for notes about [current project] updated in the last week

检索器会返回与当前项目相关的近期笔记,帮助您快速回顾上次进展。相比重新阅读昨天的提交消息,这种方式更高效。

编码过程中的研究捕获

实现功能时,无需离开编辑器即可捕获洞见:

/capture "FastAPI dependency injection with async generators requires yield,
not return. The generator is the dependency lifecycle."
  --domain programming
  --tags fastapi,dependency-injection

捕获的洞见会立即建立索引,并可供后续检索。数月积累下来,这些微型捕获会形成一套针对具体实现的知识语料库。

项目启动

开始新项目或新功能时:

  1. 搜索知识库:“我对[technology/pattern]了解什么?”
  2. 查看前5条结果,了解以往决策和注意事项
  3. 检查该领域是否已有MOC;如果没有,则创建一个
  4. 搜索故障模式:“[technology]的问题”

使用知识库搜索进行调试

遇到错误或异常行为时:

Search my vault for [error message or symptom]

以往的调试笔记往往包含根因和修复方法。对于跨项目反复出现的问题,这尤其有价值——知识库会记住您遗忘的内容。

代码审查准备

审查PR之前:

Search my vault for patterns and conventions about [module being changed]

知识库会返回与待审查代码相关的以往决策、架构约束和编码标准。审查基于组织知识,而不仅仅是diff。


性能调优

本节介绍针对不同知识库规模和使用模式的优化策略。

索引大小管理

知识库大小 Chunks DB大小 完整重建索引 增量更新
500条笔记 ~1,500 3 MB 15秒 <1秒
2,000条笔记 ~6,000 12 MB 45秒 2秒
5,000条笔记 ~15,000 30 MB 2分钟 4秒
15,000条笔记 ~50,000 83 MB 4分钟 <10秒
50,000条笔记 ~150,000 250 MB 15分钟 30秒

达到50,000条以上笔记时,可以考虑: - 将批大小从64增加到128,以加快embeddings生成 - 使用WAL模式(默认)支持并发访问 - 在非高峰时段运行完整重建索引

查询优化

WAL模式。 SQLite的Write-Ahead Logging模式允许索引器写入时并发读取:

db.execute("PRAGMA journal_mode=WAL")

当MCP服务器在索引器执行增量更新期间处理查询时,这一点至关重要。

连接池。 MCP服务器应复用数据库连接,而不是每次查询都打开新连接。一个启用WAL模式的长期连接即可支持并发读取。

# MCP server initialization
db = sqlite3.connect(DB_PATH, check_same_thread=False)
db.execute("PRAGMA journal_mode=WAL")
db.execute("PRAGMA mmap_size=268435456")  # 256 MB mmap

内存映射I/O。 mmap_size pragma会指示SQLite对数据库文件使用内存映射I/O。对于83 MB的数据库,将整个文件映射到内存中可以消除大部分磁盘读取。

FTS5优化。 完整重建索引后,运行:

INSERT INTO chunks_fts(chunks_fts) VALUES('optimize');

这会合并FTS5的内部b-tree段,降低后续搜索的查询延迟。

扩展性基准测试

在Apple M3 Pro、36 GB RAM、NVMe SSD上测得:

操作 500条笔记 5K条笔记 15K条笔记 50K条笔记
BM25查询 2ms 5ms 12ms 25ms
Vector查询 1ms 3ms 8ms 20ms
RRF融合 <1ms <1ms 3ms 5ms
完整搜索 3ms 8ms 23ms 50ms

所有基准测试均包括数据库访问、查询执行和结果格式化。MCP STDIO通信的网络延迟会额外增加1-2ms。


故障排查

索引漂移

症状: 搜索返回过期结果,或漏掉最近新增的笔记。

原因: 添加笔记后未运行增量索引器,或者文件的mtime未更新(例如,从另一台机器同步时保留了时间戳)。

修复: 运行完整重建索引:python index_vault.py --full

Embedding模型切换

症状: 更换embedding模型后,vector搜索返回毫无意义的结果。

原因: 旧向量(来自之前的模型)正在与新的查询向量比较。维度或向量空间语义不兼容。

修复: 索引器应检测模型哈希不匹配,并自动触发完整重建索引。如果没有触发,请手动清空数据库并重建索引:

rm vectors.db
python index_vault.py --full

FTS5维护

症状: 多次增量更新后,FTS5查询返回错误或不完整结果。

原因: 经过大量小规模更新后,FTS5内部段可能变得碎片化。

修复: 重建并优化:

INSERT INTO chunks_fts(chunks_fts) VALUES('rebuild');
INSERT INTO chunks_fts(chunks_fts) VALUES('optimize');

MCP超时

症状: AI工具报告MCP服务器超时。

原因: 第一次查询会触发模型加载(惰性初始化),耗时2-5秒。AI工具的默认MCP超时时间可能更短。

修复: 在服务器启动时预热模型:

# In MCP server initialization
retriever = HybridRetriever(db_path, vault_path)
retriever.search("warmup", limit=1)  # Trigger model load

SQLite文件锁

症状: 出现SQLITE_BUSYSQLITE_LOCKED错误。

原因: 多个进程同时写入数据库。WAL模式允许并发读取,但只允许一个写入者。

修复: 确保只有一个进程(索引器)写入数据库。MCP服务器和hooks应只读。如果需要并发写入,请使用WAL模式并设置busy timeout:

db.execute("PRAGMA busy_timeout=5000")  # Wait up to 5 seconds

sqlite-vec无法加载

症状: Vector搜索被禁用;检索器以仅BM25模式运行。

原因: sqlite-vec扩展未安装、在库路径中找不到,或与SQLite版本不兼容。

修复:

# Install via pip
pip install sqlite-vec

# Or compile from source
git clone https://github.com/asg017/sqlite-vec
cd sqlite-vec && make

验证扩展是否加载:

import sqlite3
db = sqlite3.connect(":memory:")
db.enable_load_extension(True)
db.load_extension("vec0")
print("sqlite-vec loaded successfully")

大型知识库内存问题

症状: 对大型知识库(50,000条以上笔记)执行完整重建索引时出现内存不足错误。

原因: Embedding批大小过大,或所有文件内容被同时加载到内存中。

修复: 减小批大小,并以增量方式处理文件:

BATCH_SIZE = 32  # Reduce from 64

同时确保索引器逐个处理文件(读取、chunking并为每个文件生成embedding后,再进入下一个文件),而不是将所有文件一次性加载到内存。


迁移指南

从Apple Notes迁移

  1. 通过“Export All”选项(macOS)导出Apple Notes,或使用apple-notes-liberator等迁移工具
  2. 使用markdownifypandoc将HTML导出转换为markdown
  3. 将转换后的文件移动到知识库的00-inbox/文件夹
  4. 检查并为每条笔记添加frontmatter
  5. 将笔记移动到合适的领域文件夹

从Notion迁移

  1. 从Notion导出:Settings → Export → Markdown & CSV
  2. 将导出文件解压到知识库的00-inbox/文件夹
  3. 修复Notion特有的markdown痕迹:
  4. Notion使用- [ ]表示清单——这些是标准markdown
  5. Notion将属性表作为HTML包含在内——转换为YAML frontmatter
  6. Notion将图片嵌入为相对路径——将图片复制到附件文件夹
  7. 添加标准frontmatter(typedomaintags
  8. 将Notion页面链接替换为Obsidian wiki-links

从Google Docs迁移

  1. 使用Google Takeout导出所有文档
  2. .docx文件转换为markdown:pandoc -f docx -t markdown input.docx -o output.md
  3. 批量转换:for f in *.docx; do pandoc -f docx -t markdown "$f" -o "${f%.docx}.md"; done
  4. 移动到知识库,添加frontmatter,并整理到文件夹中

从普通Markdown迁移(非Obsidian)

如果您已经有一个markdown文件目录:

  1. 将该目录作为Obsidian知识库打开(Obsidian → Open Vault → Open folder)
  2. 如果该目录受版本控制,请将.obsidian/添加到.gitignore
  3. 创建frontmatter模板并应用到现有文件
  4. 在阅读和整理时,开始使用[[wiki-links]]链接笔记
  5. 立即运行索引器——检索系统从第1天起即可工作

从其他检索系统迁移

如果您正从不同的embedding/搜索系统迁移:

  1. 不要尝试迁移向量。 不同模型会生成不兼容的向量空间。请使用新模型运行完整重建索引。
  2. 迁移内容,而不是索引。 知识库文件才是真实来源。索引只是派生产物。
  3. 迁移后进行验证。 运行10-20个您已知答案的查询,并确认结果符合预期。

更新日志

日期 变更 来源
2026-08-14 首次全面质量门禁审计——通读整篇指南的评估;R1得分为8.29,发现3项CRITICAL和5项MAJOR问题,均已在此行修复。这些CRITICAL问题会损害读者体验:快速入门将npm obsidian-mcp-server作为“最简单的基于文件的选项”安装——该包是cyanheads基于REST-API的服务器(需要Local REST API插件和OBSIDIAN_API_KEY;没有--vault标志),而基于文件的服务器是npm obsidian-mcp(StevenStavrakis)——服务器表也存在相同的名称冲突,现已通过明确的npm名称一并修正;两个Claude Code MCP配置块都教用户在~/.claude/settings.json中设置mcpServers,但Claude Code会悄然忽略它——已改写为使用claude mcp add(用户作用域→~/.claude.json),并提供.mcp.json项目作用域变体,同时修正了兼容性矩阵单元格;hook示例使用位置参数$1/$2以及~/.claude/hooks/pre-tool-use/自动发现目录——这是Claude Code从未提供过的接口——现已改写为通过设置注册的hook,使用jq从stdin读取JSON(上下文注入移至UserPromptSubmit,其stdout确实会加入上下文);而“PostToolUse上下文压缩”一节的前提(hook缩减模型所见内容)并不可能实现——已改为将压缩摘要捕获至vault,以便跨会话复用,并移除了不必要的递归保护(每次hook调用都是新进程)。MAJOR问题:1.13.4→1.13.7(已验证manifest,stable与beta版本已收敛);MCP在2026-07-28的规范说明仍写着“最终规范于7月28日发布”,而它在17天前已作为Current修订版发布(已改为过去时;9改写为历史记录,并指向24);Codex对比部分教授了已移除的suggest/auto-edit/full-auto审批模式,并称“hooks/skills不受支持”——自2026年年中起,两者都是稳定的Codex界面,表格和段落已重建(CC单元格现在列出真实的权限模式,包括8月14日的自动默认值);更新了Zed/Continue/Windsurf矩阵行。次要问题:移除了.codex/config.toml项目变体(仅保留$CODEX_HOME),mcpvault从0.12.4→0.15.0,取消过期“截至”锚点的相对表述,并在采集一节纳入承诺的1.13 iOS Share Sheet url变量。R2验证确认修复完成,但在边缘处发现残留问题,并在第二轮中修复:快速入门的Codex/Cursor块仍调用名称冲突的二进制文件(现已在所有3个工具中统一使用npx -y obsidian-mcp@2 serve,与已安装包的v2语法一致);重写后的hook章节下方仍保留了一句PreToolUse注入上下文的说明(注入指引现已统一通过UserPromptSubmit进行);以及4处单行问题(未配对的括号、过时的1.13.4引用、13的版本、9残留的路线图句子)。 24 26
2026-08-07 Obsidian 1.13已进入公开渠道:1.13.4于2026年7月30日晋升(已验证manifest:desktop-releases.jsonlatestVersion为1.13.4,beta.latestVersion为1.13.6)。正文中3处“公开渠道仍为1.12.7”的引用均已更新。现在1.13系列已正式可用,其提供的功能包括:设置界面全面升级(独立窗口、按名称/描述搜索、键盘+Vim导航)、带逐文件导航和Live Preview调整大小控件的全屏图像查看器、可搜索的Bookmarks、Sync多选,以及——对本指南读者最相关的是——Obsidian URI安全机制:除非已加入允许列表,否则obsidian://操作现在需要确认对话框。本指南的自动化流程通过MCP和CLI实现,不受影响;但凡是通过URI驱动Obsidian的工作流(Shortcuts、脚本、其他启动器),现在都需要将操作加入允许列表一次,否则每次都会提示。面向开发者:新增Settings API及迁移指南,--callout-color发生破坏性变更(需要有效的CSS颜色,不再接受RGB三元组——主题和代码片段必须更新),以及Electron 43.1.1、CodeMirror和Mermaid 11.13.0升级。没有AI、MCP或CLI方面的变更。Catalyst跟踪版本移至1.13.6。 26
2026-07-27 版本巡检加上一项咨询修正。MCPVault在7月23日的3个同日补丁中从0.12.1→0.12.4,由于这些补丁在7月22日巡检后的次日发布,因此均被当日巡检遗漏。v0.12.3新增wiki_link工具——可解析[[Document Name]][[Name\|Display]]、表格转义和#fragment形式,返回内容、解析后的路径以及存在歧义的替代项——并通过默认路径过滤器将.trash/排除在所有工具之外;v0.12.4将其扩展到路径限定的[[folder/Note]]链接;v0.12.2修复了patch_note损坏$模式插入的问题,规范化带vault前缀的路径,并清除了npm audit中的高严重性发现。MCP服务器章节和[^24]现已涵盖这3项内容。修正:2026-07-07行称v0.12.1“带有两项中等严重性路径过滤咨询”。事实并非如此。GitHub Advisory API将GHSA-9c83-rr99-vfwj的易受影响范围列为< 0.11.5,将GHSA-j99q-93c9-h869列为< 0.11.4——两者都在0.12系列开始前完成修复,因此撰写该行时0.12.1已经不受影响。正文和脚注现在说明首次修复的版本,而不再让“运行当前版本”暗示仍存在开放暴露。此外:Obsidian 1.13.4桌面端+移动端(7月27日)属于Catalyst抢先体验;desktop-releases.jsonmanifest仍显示latestVersion为1.12.7,beta.latestVersion为1.13.4,因此公开渠道未变,此处的版本引用仍然成立。内容属于UX级改进(lightbox文件名显示、Live Preview图像对齐与内边距、卡住文件的保存竞态、设置布局),没有AI、MCP或CLI变更。 13 26
2026-07-22 版本巡检,无工作流变更。Obsidian 1.13.3桌面端+移动端(7月21日)仅为Catalyst抢先体验——经manifest验证,公开渠道仍为1.12.7;内容属于UX级改进(图像嵌入lightbox/缩放、Live Preview行高修复、File Recovery方向键、unique URI paneType修复),没有AI/MCP/CLI变更。Catalyst跟踪从1.13.2→1.13.3。注:1.13.3于7月21日稍晚发布,发生在当天巡检结束后——上一行所称“没有新版本”在撰写时准确无误。Web Clipper 1.7.1(7月22日,GitHub发布):导入高亮、{{model}}/{{modelId}}/{{modelProvider}} Interpreter模板变量、更新的提供商预设、Defuddle 0.19.2、面向近期Anthropic模型的Interpreter修复、原生Gemini API密钥、DeepSeek和Azure OpenAI处理;商店推送可能晚于GitHub日期。没有官方MCP服务器消息;无状态规范仍计划于7月28日发布。 26
2026-07-21 准确性修正:公开桌面渠道为1.12.7,而不是1.13.1。2026-06-10条目(及之后的正文引用)将1.13.1视为公开渠道版本;1.13.1更新日志页面标注为Early access,官方自动更新manifest(obsidianmd/obsidian-releases,desktop-releases.json)列出公开渠道latestVersion为1.12.7,beta渠道为1.13.2——整个1.13.x系列仅限Catalyst。正文引用和26均已修正。针对2026-07-17→2026-07-21的版本巡检未发现新版本:核心仍为1.13.2 Catalyst,Clipper为1.7.0,没有官方MCP服务器消息,MCP无状态规范仍计划于7月28日发布。 26
2026-07-17 版本巡检,无工作流变更。Obsidian 1.13.2(7月14日)仅为Catalyst抢先体验——公开渠道仍为1.13.1,因此此处版本引用保持最新;唯一与指南相关的项目是iOS Share Sheet模板新增url变量(将共享链接插入笔记),待1.13.2进入公开渠道后将纳入采集路径章节。Web Clipper 1.7.0(6月16日,此前未被发现):升级Defuddle 0.19.0,{{content}}现在保留==highlight==标记,高亮内容会在实时页面和Reader视图之间保留。尚未公布官方Obsidian MCP服务器或AI集成;MCP规范的无状态版本仍计划于7月28日发布。已根据obsidian.md/changelog、github.com/obsidianmd/obsidian-clipper releases和blog.modelcontextprotocol.io进行验证。
2026-07-07 准确性修正。MCPVault已明确为独立项目(npm @bitbonsai/mcpvault,仓库bitbonsai/mcpvault),现为v0.12.1,带有两项中等严重性路径过滤咨询(GHSA-9c83-rr99-vfwj、GHSA-j99q-93c9-h869)——此前[^24]链接指向了错误的仓库(MarkusPfundstein/mcp-obsidian)。已修正MarkusPfundstein/mcp-obsidian的状态:它处于积极维护状态(提交持续至2026年5月15日,新增search_by_tag/get_frontmatter),而非“自2025年6月起休眠”;它仍未发布带标签的版本。已根据GitHub提交历史、GitHub Security Advisories和npm进行验证。
2026-07-06 为提升可发现性进行编辑重构:将“Quick Start: First AI-Connected Vault”重命名为Obsidian MCP Setup(锚点#obsidian-mcp-setup),并新增“连接后Claude可以做什么”能力概览(搜索、读取、列出、格式化上下文;只读边界,写入由hook处理),内容从MCP Server Architecture章节整合而来。没有新增事实;内部链接已更新。
2026-06-10 版本时效性更新。Obsidian 1.13.1桌面端已进入公开渠道(2026年6月9日)——相较1.13.0,这是一次设置UX+CodeMirror升级,没有重大AI/自动化变更。当前版本的正文引用从1.13.0移至1.13.1(公开版,2026年6月9日)。 26
2026-06-09 生态系统更新。MCP 2026-07-28规范进入Release Candidate(2026年5月21日公布)——这是自发布以来最大的一次MCP修订:无状态协议核心(移除initialize握手和Mcp-Session-Id)、MCP Apps(在沙盒iframe中渲染服务器端HTML)、Tasks从实验性核心升级为官方扩展、OAuth 2.0/OIDC强化,以及12个月弃用生命周期政策(最终规范于2026年7月28日发布);将MCP Spec Evolution说明中推测性的“暂定于2026年年中”路线图表述替换为明确的RC。sqlite-vec v0.1.10-alpha(2026年3月31日–5月18日)新增近似最近邻索引类型(rescore、实验性的ivf、基于磁盘的DiskANN),突破暴力KNN的限制——鉴于0.1.10系列仍为预发布版本,已标记为前瞻性/实验性功能。Obsidian 1.13.0桌面端(抢先体验,2026年5月28日)已作为当前版本更新至各处正文引用;这是一次UX/安全/开发工具版本,没有新增AI/自动化能力。 24 23 25
2026-06-08 维护检查。Model2Vec v0.8.2(2026年5月29日)发布:这是一个维护版本,为训练新增冻结权重选项,并修复多词token、训练重构和非量化权重处理问题;脚注已更新。没有其他内容比现有基线更新:Obsidian最新版本仍为1.13.0(5月28日,已在下文记录),sqlite-vec稳定版仍为v0.1.9(v0.1.10仍为alpha),MCP规范仍是2025-11-25修订版。除Model2Vec版本说明外,正文没有变更。 10
2026-05-28 Obsidian 1.13.0桌面端+1.13.0移动端(Catalyst抢先体验)发布。桌面端:经过重新设计的Settings面板,可在独立窗口中打开,内置搜索和键盘导航;Obsidian URI现在会在执行操作前显示确认对话框;从网络驱动器加载HTML资源前新增警告;Search加入Bookmarks视图;增强编辑器图像处理;改进File Explorer / Properties / Sync;大量面向开发者的API和错误修复。移动端:新的iOS Share Sheet,支持配置目标位置;可从标签切换器重新排序标签;平板电脑上可通过长按手势调整分割视图和固定侧边栏大小;Bases在表格视图中新增调整列宽的菜单项;iOS和搜索错误修复。对AI工作流的影响:Obsidian URI上的确认对话框为URI驱动的MCP/agent集成增加了有意设置的门槛;Bases列宽调整菜单使Bases更适合作为agent查询的vault前端索引;iOS Share Sheet可配置目标位置,使iPhone采集路径(已记录为主要入口)能更快接入Claude/Codex流程。
2026-05-06 更新并验证来源的时效性:Smart Connections v4.5.0将页脚连接移入Core;sqlite-vec v0.1.8/v0.1.9稳定版本更新了打包和DELETE行为;Model2Vec v0.8.x更新tokenizer/持久化内部实现及基准测试表;将Obsidian CLI时间线从“1.12.7引入CLI”修正为“1.12.0引入CLI,1.12.7改进安装/运行时打包”。
2026-04-27 Web Clipper 4月周期:1.4.0(交互式YouTube转录UI+默认Open in Reader)、1.5.0(Highlights查看器)、1.6.0(Highlighter UX全面升级+面向LinkedIn/Threads/Bluesky/Discourse/Medium的Defuddle 0.18源提取器)、1.6.1+1.6.2(Reader和Safari修复)。将Web Clipper重新定位为AI工作流主要的浏览器端采集路径,而非一笔带过的书签提及。该窗口期内没有Obsidian桌面端、Sync或Bases版本发布。
2026-04-16 Smart Connections v4.3.0(图谱视图、可配置停靠区、块embeddings恢复、Substrate跨插件环境)。记录2026年4月AI原生插件浪潮(Cortex、VaultSearch、LLM Wiki、Drift、EngramQuest、Hybrid Search MCP)。将MarkusPfundstein/mcp-obsidian标记为维护模式(最后一次提交于2025年6月)。Dataview处于休眠状态;Bases是新项目的继任者。Obsidian CLI 1.12.7仍是AI助手的首选桥接方案。
2026-04-01 新增Obsidian CLI章节(用于AI工作流的v1.12命令)。新增agent插件章节(Claudian、Agent Client)。记录用于vault组织的Bases核心插件。将插件数量更新至2,500+。新增iOS Share Extension作为采集来源。使用嵌入式agent插件更新兼容性矩阵。
2026-03-30 MCPVault v0.11.0:新增list_all_tags工具,支持.base/.canvas,重命名为@bitbonsai/mcpvault。Obsidian Desktop v1.12.7捆绑CLI二进制文件,以加快终端交互。
2026-03-23 记录sqlite-vec v0.1.7稳定版:支持vec0表的DELETE,支持用于分页的KNN距离约束。宣布将在即将发布的版本中提供DiskANN近似最近邻索引。
2026-03-07 将potion-multilingual-128M(101种语言,2025年5月)加入embedding模型对比。sqlite-vec为v0.1.7-alpha.10(CI/CD修复,无功能变更)。确认MCP规范和检索技术仍为最新。
2026-03-03 更新MCP规范演进(2025年11月已发布:Streamable HTTP、.well-known、工具注释)。新增Model2Vec微调和BPE/Unigram tokenizer支持。新增社区MCP服务器对比表。将Smart Connections更新至v4。
2026-03-02 将potion-base-32M和potion-retrieval-32M加入模型对比。新增量化/降维章节。新增MCP规范演进说明。
2026-03-01 初始发布

参考资料


  1. Internet Vin,“我与 Obsidian 和 Claude Code 一起使用的 22 个命令”,2026年3月,x.com/internetvin/status/2026461256677245131。 

  2. Nicopreme,带有斜杠命令的“Visual Explainer”agent skill,x.com/nicopreme/status/2023495040258261460。 

  3. Cormack, G.V.、Clarke, C.L.A. 和 Buettcher, S. Reciprocal Rank Fusion 优于 Condorcet 和单个排序学习方法。SIGIR,2009。介绍了 RRF:使用 k=60 作为无需调参的参数,用于合并排序列表。 

  4. OpenAI Embeddings 定价。text-embedding-3-small:每百万 tokens 0.02 美元。完整重建索引的 vault 预估成本:约 0.30 美元。 

  5. van Dongen, T. 等。Model2Vec:将任意 Sentence Transformer 转换为小型快速模型。arXiv,2025。介绍了从句子转换器生成静态 embeddings 的蒸馏方法。 

  6. potion-base-8M 模型卡Model2Vec 结果。当前发布的表格显示,potion-base-8M 的 Avg(All)为 51.32、Avg(MTEB)为 51.08;相比之下,all-MiniLM-L6-v2 的 Avg(All)为 55.80、Avg(MTEB)为 55.93,即在全任务得分上约保留 92%。 

  7. Model Context Protocol 规范。用于将 AI 工具连接到数据源的 MCP 标准。 

  8. Model2Vec Potion Modelspotion-base-32Mpotion-retrieval-32M。当前模型卡显示,potion-base-32M 的 Avg(All)为 52.83,potion-retrieval-32M 在检索表中的得分为 35.06。 

  9. 关于下一次 MCP 协议发布的更新。历史记录:2025年11月发布的版本提供了 Streamable HTTP 传输、.well-known URL 发现、结构化工具注解和 SDK 层级标准化。该版本预告的发布周期以 2026年7月28日修订版告终——即现行规范(参见 24)。 

  10. Model2Vec Releases。v0.4.0(2025年2月):训练/微调支持。v0.5.0(2025年4月):后端重写、量化、降维。v0.7.0(2025年10月):词汇量化、BPE/Unigram tokenizer 支持。v0.8.0/v0.8.1(2026年3月):tokenizer 和持久化重构、Python 3.9 弃用、MTEB V2 结果更新,以及 Windows 路径兼容性。v0.8.2(2026年5月29日):维护版本,为训练添加了冻结权重选项,并修复多词 token、重构训练流程和修复非量化权重处理。 

  11. Smart Connections for Obsidian。Smart Connections v4:本地优先的 AI embeddings;初始索引完成后,语义搜索可离线使用。 

  12. potion-multilingual-128M。Minish Lab,2025年5月。支持 101 种语言的静态 embedding 模型,是表现最佳的多语言静态 embeddings。与其他 potion 模型一样,仅依赖 numpy。 

  13. MCPVault — bitbonsai/mcpvault。npm @bitbonsai/mcpvault,最新版本为 v0.15.0(发布于 2026-08-09);0.12.2–0.12.4 系列均于 2026-07-23 发布(0.12.2 于 09:51,0.12.4 于 10:10——0.12.3 虽出现在两者之间的仓库变更日志中,但从未发布到 npm);这是与 MarkusPfundstein/mcp-obsidian 不同的项目,并非其更名版本。v0.11.0(2026年3月)新增 list_all_tags 工具,用于扫描 frontmatter 和 hashtags 并统计数量;同时改进了点号文件夹处理,并支持 .base/.canvas 文件。0.12.2–0.12.4 的内容来自仓库的CHANGELOG.md,这是唯一的发布记录——该仓库的 GitHub releases endpoint 返回空列表,因此 npm 发布时间和变更日志是主要来源。0.12.2:patch_note 会按字面插入 newString,而非展开 $'$&$`$$(issue #149 / PR #153);以 vault 为前缀的绝对路径或 ~/ 风格路径会规范化为相对 vault 的路径(issue #122 / PR #151);仅通过更新 lockfile 即清除了 npm audit 的高严重性发现(PR #154)。0.12.3:新增 wiki_link 工具(PR #101),并通过默认路径过滤器从所有工具中排除 .trash/。0.12.4:wiki_link 会根据完整的相对 vault 路径而不是 basename 解析诸如 [[folder/Note]] 的带路径链接。两项中等严重性的 GitHub Security Advisories 会影响其路径过滤器:GHSA-9c83-rr99-vfwj(受限目录仅在 vault 根目录被拒绝,嵌套目录未受限)和GHSA-j99q-93c9-h869(可通过大小写以及末尾点号/空格等价性绕过拒绝列表)。根据 GitHub Advisory API,其受影响版本范围分别为 < 0.11.5< 0.11.4,首个修复版本分别为 0.11.50.11.4——两者均早于 0.12.0,因此包括 0.12.1 在内的所有 0.12.x 版本均已修复。Advisory 范围和 npm 时间戳已于 2026-08-14 再次验证。 

  14. sqlite-vec v0.1.7 Release。2026年3月17日。稳定版本:为 vec0 虚拟表提供 DELETE 支持,为分页提供 KNN 距离约束,并改进模糊测试。宣布将在未来版本中提供 DiskANN 近似最近邻索引。 

  15. Bases 简介。Obsidian 核心插件,于 v1.9.10 引入。使用 frontmatter 属性作为字段,在 vault 文件之上提供类似数据库的视图(表格、画廊、日历、看板)。文件以 .base 格式保存。 

  16. Obsidian Desktop v1.12.0 更新日志Obsidian Desktop v1.12.7 更新日志。v1.12.0 引入了用于基于终端的 vault 自动化的 CLI;v1.12.7 通过独立二进制文件、TUI 和 socket 文件行为改进了安装/运行时打包。另请参阅CLI 文档。 

  17. Claudian。将 Claude Code 作为 vault 中 AI 协作者嵌入的 Obsidian 插件。提供侧边栏聊天、上下文感知提示词、视觉支持、斜杠命令和权限模式。 

  18. Agent Client。通过 Agent Client Protocol(ACP)为 Claude Code、Codex CLI 和 Gemini CLI 提供统一界面的 Obsidian 插件。支持笔记提及、shell 执行和操作审批。 

  19. Obsidian iOS 更新日志。2026年初的更新包括 Share Extension,可将其他应用中的内容直接保存到 vault;还包括 Daily Note 和 Bookmark 小组件修复,以及 View Note 小组件刷新改进。 

  20. MarkusPfundstein/mcp-obsidian。仍在积极维护——提交记录延续至 2026年5月15日,近期工作增加了包括 search_by_tagget_frontmatter 在内的工具,并扩大了测试覆盖范围(已根据仓库提交历史和 tools.py 验证)。仍未提供标记发布版本,因此请从固定的 commit 安装。基于 Local-REST-API;论坛讨论(2026年4月)显示,社区在新配置中正逐步迁移到一流的 Obsidian CLI bridge(1.12.x),但 mcp-obsidian 对现有 REST-API 部署而言仍是可用且持续更新的选项。 

  21. Smart Connections v4.5.0 Release。2026年5月5日。页脚连接成为 Core 功能;近期 v4 版本还包括连接列表的图谱视图、可配置的连接面板位置、改进的区块 embedding 恢复、Substrate 跨插件状态、transformer 回退修复,以及减少重复的连接计算。 

  22. obsidianmd/obsidian-clipper releases——Web Clipper 版本与功能对应关系的主要来源。2026年4月周期:1.4.0(4月9日,YouTube transcript UI + 默认 Open in Reader)、1.5.0(4月15日,Highlights viewer + Reader 淡入)、1.5.1(4月15日,webpack 编译修复)、1.6.0(4月21日,Highlighter UX + Defuddle 0.18,支持 LinkedIn/Threads/Bluesky/Discourse/Medium 提取器)、1.6.1(4月22日,Reader outline 修复 + highlights 搜索)、1.6.2(4月23日,Safari embedded-mode clipboard 修复)。同时列于Mozilla Add-ons 商店Chrome Web Store。 

  23. sqlite-vec v0.1.8sqlite-vec v0.1.9sqlite-vec v0.1.10-alpha.3sqlite-vec v0.1.10-alpha.4。v0.1.8 修复了 npm 打包;v0.1.9 修复了元数据文本列超过 12 个字符时的 DELETE bug;v0.1.10-alpha.3 添加了对 INSERT OR REPLACE INTO 的正确支持;v0.1.10-alpha.4(2026年5月18日)修复了使用新 ivf/diskann 功能的 vec0 表上 ALTER TABLE RENAME 失败的问题,以及 DiskANN 中缓存语句清理的 bug。0.1.10 系列仍为预发布版本。 

  24. MCP 2026-07-28 规范候选发布版。于 2026年5月21日宣布;最终规范于 2026年7月28日发布。这是 MCP 自推出以来规模最大的一次修订:无状态协议核心(移除 initialize 握手和 Mcp-Session-Id header)、MCP Apps(在沙盒化客户端 iframe 中呈现的服务器渲染 HTML)、Tasks 从实验性核心升级为正式扩展(tasks/gettasks/updatetasks/cancel)、OAuth 2.0 / OIDC 授权加固,以及 12 个月的功能弃用生命周期政策。 

  25. Obsidian Desktop v1.13.0 更新日志。抢先体验版,2026年5月28日。UX/安全性/开发者工具发布:改版后的 Settings 面板将在独立窗口中打开,并支持搜索和键盘导航;Obsidian URI 触发前提供确认对话框;为插件开发者提供新的 Settings API;并修复了 flatpak 安装的 CLI 问题。除 1.12.x 的 CLI 功能面外,没有重大的新增 AI/自动化能力。 

  26. Obsidian 更新日志。Obsidian 1.13.1 desktop 于 2026年6月9日作为 Catalyst 抢先体验版本发布——相较于 1.13.0,主要是 Settings UX 优化和 CodeMirror 升级,没有新增 AI/自动化能力。1.13.1 更新日志页面本身标有“Early access”,而官方自动更新 manifest(obsidianmd/obsidian-releases,desktop-releases.json)列出的公开 latestVersion 为 1.12.7,beta channel 上为 1.13.2;已于 2026-07-21 验证。于 2026-07-27 再次验证:manifest 仍报告 latestVersion 为 1.12.7,beta.latestVersion 现为 1.13.4。位于 obsidian.md/changelog.xml 的 Atom feed 为每项 1.13.x 条目——从 1.13.1 到 1.13.4——标记“(Early access)”;标题为“(Public)”的最新条目仍为 1.12.7,日期为 2026-03-23,与 obsidian-releases GitHub release list 一致。于 2026-08-07 再次验证:manifest 现报告 latestVersion1.13.4(于 2026年7月30日公开发布),beta.latestVersion 为 1.13.6——1.13 系列已正式可用,上述历史行准确描述了其在相应日期的 Catalyst 专属时期。于 2026-08-14 再次验证:manifest 报告 latestVersion1.13.7beta.latestVersion 也为 1.13.7——稳定版与 beta 版已趋于一致。 

VAULT obsidian.md INDEXED