从 Codex + Obsidian 到本地 RAG:我的私人知识库实践

一句话结论

我最终搭出的不是一个会自动收藏资料的"第二大脑",而是两条彼此独立又能衔接的本地链路:Codex 把杂乱来源持续编译成可信 Wiki,本地 RAG 再从这份 Wiki 中检索证据、约束回答并把结论链接回原笔记。

我最开始想解决的问题其实很朴素:资料越来越多,但真正需要时总是找不到。与 AI 的对话中也会产生有价值的结论,但如果不主动沉淀,任务结束后它们仍然只会留在会话记录里。

现在遇到值得保留的内容,我不会同步整段聊天,而是让 Codex 提取可复用部分并写入收集箱,再由整理流程核验后更新 Wiki。

我不缺另一个收藏夹,也不想把私人资料全部搬进某个只能通过网页访问的封闭系统。我需要的是一套自己看得见、改得动、能迁移,也允许 AI 参与维护的本地知识系统。

最后选定的底座是 Codex + Obsidian:Obsidian 负责阅读、链接和浏览,Codex 直接处理同一个本地 Markdown 目录。知识库稳定运行后,我又在它上面搭了一套本地优先的 RAG 应用"语境",并将代码开源为 DWmister/obsidian-context-rag

这两层解决的是不同问题:

  • Codex + Obsidian 负责让知识变得更可靠、更完整;
  • RAG 负责在提问时找到证据,并控制模型只能依据证据回答。

知识没有整理好,RAG 只会更快地召回噪声;只有整理、没有检索,资料增长后又难以高效利用。整理负责提升知识质量,RAG 负责在提问时找到证据。两者应该衔接,而不是笼统地混成一个"AI 知识库"。

第一步:选择 Codex 与 Obsidian 的协作入口

Obsidian 的 Vault 本质上是本地文件夹,笔记以 Markdown 纯文本保存。社区也有 Claudian 这类插件,可以把 Codex 等 coding agent 直接嵌入 Obsidian,并让 Vault 成为 agent 的工作目录。

我当时没有采用插件方案,也没有另写连接层,而是直接在 Codex 中把 Vault 目录作为项目打开。两种方式都围绕同一组本地文件工作,区别主要在交互入口:Claudian 把 agent 放进 Obsidian,我的方案则是在 Codex 中维护、在 Obsidian 中阅读。这只是我的实现选择,不代表 Codex 与 Obsidian 只能这样连接。

这种方案简单,却有几个我很看重的性质:

  • Markdown 不依赖某个厂商数据库,迁移和备份都直接;
  • 我随时可以检查 Codex 实际修改了什么;
  • Obsidian 的双向链接继续负责知识导航;
  • Git、脚本和其他本地工具都能处理同一份文件;
  • RAG 可以只读访问 Wiki,不需要再维护一份手工导出的知识副本。

真正困难的不是"让 AI 能写 Markdown",而是防止它把库写得越来越乱。只给一句"帮我整理资料"远远不够,我需要把目录职责、事实标准和完成条件固定下来。

收集箱不是知识,Wiki 才是当前结论

我的知识库现在只保留两个主要内容层:

层级 目录 作用
原始入口 收集箱/ 保存网页摘录、导入文章、临时想法和个人经验,保留原文与出处
正式知识 wiki/ 综合多份材料和外部证据,保存当前可复用、可直接阅读的知识页

收集箱可以杂乱,因为它只是入口。Wiki 不能只是原文摘要的堆叠;一篇页面要回答一个明确问题,并把不同来源综合成当前结论。

一轮整理的实际流程是:

  1. 新材料先进入收集箱,原文不被覆盖;
  2. 计算收集箱内容指纹,没有变化就不联网、不改 Wiki;
  3. 有变化时先搜索相近页面,判断增量更新还是新建;
  4. 把收集箱视为线索,再用官方、原始和近期来源交叉核验;
  5. 在同一次流程中完成去重、结构调整、解释补全、语言润色、内部链接和来源;
  6. 所有页面和链接验证成功后,最后提交新的内容指纹。

对我来说,"自生长"不是文件数量自动增加,而是同一个问题的页面会随着新证据逐渐变好。

AGENTS、Skill、Automation 和指纹各管一件事

这套系统跑稳以后,我把不同层级的规则拆开了。

AGENTS.md 是项目宪法

AGENTS.md 保存每次维护都必须遵循的长期规则,例如目录职责、来源标准、写作格式,以及"一次只改一个文件、写完立即复读"。它应该足够稳定,也应该尽量短;反复发生的错误才值得上升为长期规则。

Skill 是可重复执行的工作流

整理动作本身被写成 $organize-knowledge-base Skill。它不仅是一段提示词,还包含收集箱门禁脚本、来源优先级、去重判断、写作标准和最终状态提交条件。

Skill 的价值是把"这次做对了"变成"下次仍按同一套顺序做"。我不需要在每天的任务里重新解释为什么收集箱不能直接当事实,也不用每次提醒 Codex 只有全部验证成功后才能更新状态。

Automation 只负责定时唤醒成熟流程

流程手动跑通后,我才增加每日自动整理。自动化没有获得更大的判断权,它只是按计划触发同一个 Skill,并在权限和验证条件内执行。

过早自动化会把重复页、错误分类和无来源结论一起放大。我的顺序是:先做出一次可接受结果,再把稳定步骤 Skill 化,最后才设置定时运行。

内容指纹负责避免"无变化也重写"

自动任务最容易制造一种假忙碌:明明没有新材料,仍然重新搜索、重新润色,甚至让同一页面每天产生微小漂移。

所以整理开始和结束都检查收集箱快照。没有变化时立即退出;有变化时也必须等页面、索引、来源、图片和链接全部通过检查,才提交新指纹。如果中途失败,已完成文件保留,但旧指纹不动,下一次可以从断点继续。

为什么有了 Wiki,我还要做 RAG

现代模型已经能读取不少本地文件。知识库规模不大、问题明确时,直接让 Codex 搜索 Markdown 往往就够了。我没有一开始就上向量数据库。

随着 Wiki 增长,我开始需要另一种体验:像使用搜索助手一样即时提问,看到系统究竟找到了哪些片段,并能一键回到 Obsidian 原文。这时,RAG 才从"架构名词"变成了具体需求。

我给本地 RAG 定了几条边界:

  • Vault 必须只读,应用不能反向修改笔记;
  • 收集箱默认不参与索引,只检索已经整理的 Wiki;
  • SQLite、向量和模型缓存留在本机;
  • 不持久化聊天历史,也默认不记录问题、答案和召回正文;
  • 没有配置外部模型时,本地检索和证据浏览仍然可用;
  • 配置模型后,只发送当前问题、浏览器随请求携带的最近会话历史和最终入选证据;
  • 回答必须引用真实存在的 [S1] 等证据编号,否则丢弃回答并拒答。

上图是当前本地应用的真实问答界面。问题是"RAG 的重排有什么作用?",系统返回 4 条知识库证据,回答中的实质性结论带有 [S2][S4] 引用。截图没有经过界面重绘。

从 Markdown 到可引用回答的完整链路

graph LR A["收集箱:原始材料"] --> B["Codex 整理与外部核验"] B --> C["Wiki:当前知识"] C --> D["文件监听与内容指纹"] D --> E["Markdown 解析与结构化切片"] E --> F["FTS5 全文召回"] E --> G["BGE 向量召回"] F --> H["RRF 融合"] G --> H H --> I["可选 Cross-Encoder 重排"] I --> J["去重、文档限额与上下文预算"] J --> K{"证据足够?"} K -->|"否"| L["拒答"] K -->|"是"| M["可选 LLM 基于证据生成"] M --> N["引用编号校验"] N --> O["答案与 Obsidian 深链"]

1. 增量索引,而不是每次全部重建

后端监听 Vault 中的 Markdown 变化,并在连续事件稳定后触发同步。同步仍会扫描索引范围,但通过 SHA-256 和修改时间跳过未变化文件;只有新增或修改文档才重新解析、切片和生成向量,已经删除的文档则从本地索引清理。

当前版本只扫描 wiki/,并排除各级 README.md收集箱/ 可以在配置中显式开启,但默认关闭。这是有意为之:原始材料可以提供整理线索,却不应和已经核验的知识获得同等检索权重。

截图中的 14 篇文档、215 个切片和"Vault 只读"均来自本次真实运行状态。页面顶部"已整理 Wiki 与当前产出"仍是早期版本遗留文案;当前后端代码实际只索引 Wiki,这是一个待清理的界面文字问题。

2. 先广泛召回,再逐层收窄

一篇 Markdown 会优先按标题结构切分,保留文档标题和标题路径。默认配置的目标长度是 280 tokens、最大 384 tokens,相邻超长切片重叠 48 tokens,并尽量保持表格和代码块完整。

在线检索同时走两条路径:

  • FTS5 找到字面词项直接匹配的片段;
  • BGE embedding 找到语义相近的片段。

两边结果通过 RRF 合并。RRF 关心的是各检索器给出的排名,而不是强行比较两个量纲不同的原始分数。融合之后,系统可以用 Cross-Encoder 对少量候选重新打分,再按单文档上限、近重复阈值和 token 预算选择最终证据。

这张真实截图展示了当前本地配置:4 条最终证据、链路可用、证据判断为"可回答";每个片段能看到向量分数、全文排名和 RRF 分数。重排一栏显示 ---,因为我当前在本机关闭了 reranker,而不是因为界面漏掉了它。

3. 候选不等于证据,证据也不等于答案

这是我调试过程中最重要的一次认知修正。

检索器返回的只是"可能相关的候选"。候选进入最终上下文之前,还要通过相关性阈值、重排分数、去重、单文档限额和上下文预算。即使证据成功交给模型,生成结果也要再检查引用编号。

模型如果没有引用任何真实证据,或者引用了本次不存在的 [S9],后端不会把这段文字当作可信答案展示,而是替换为统一的无证据提示。模型负责写,程序负责验证它是否真的引用了本轮证据。

两个真实踩坑,比"把 RAG 跑起来"更重要

一个泛问句,暴露了从误召回到错误展示的整条链路

**个人实践记录:**我曾用一个知识库没有答案的问题测试拒答。所有向量相似度都低于门槛,但 FTS5 因为"为什么"这个泛词命中了其他标题,导致系统继续返回几条看似相关的候选。

系统最终判断证据不足并拒答,但早期界面把召回候选统一叫作"知识库证据",页面下方仍显示四条低相关片段。结果看起来像系统一边说没有证据,一边又列出了证据。

这个案例同时暴露了两层问题:检索层把"存在全文命中"误当成了"存在有效主题词命中";展示层又没有区分检索候选、最终入选证据和被答案实际引用的证据。

后来我对"为什么、是什么、如何、怎么、请问"等低信息问法做了查询清洗,同时保留真正的主题词,并增加无证据回归测试;界面也不再把所有候选笼统地称为证据。只有名称和状态都分清,用户才能判断问题出在召回、排序、证据门禁还是生成。

这件事提醒我:全文检索很擅长精确匹配,也会非常认真地匹配无意义词。稀疏召回、向量召回、拒答阈值和界面状态必须放在同一条链路中测试。

重排提高了一点排序质量,却吃掉了交互速度

个人实践记录,适用于当时的本机 CPU、模型与约 255 个切片: BAAI/bge-reranker-base 对 20 个候选做 Cross-Encoder 推理时,本地检索约需 8~10 秒。关闭重排并缩小候选、证据和上下文后,一次纯本地检索曾实测约 45ms。

离线评测里,重排带来的 MRR 提升有限,却让日常问答明显变慢。因此我没有得出"reranker 没用"的结论,而是把它设计成可选能力:默认配置保留,当前本机覆盖关闭;以后换硬件、换模型或知识规模变大,可以重新评测再启用。

这组数字不是通用性能结论。不同 CPU、模型、候选数量、批次和语料都会改变结果。真正可复用的原则是:只有当重排在自己的评测集上改善 MRR 或 nDCG,并且延迟可以接受时,才值得默认开启。

本地优先不是"完全不联网",而是边界可见

这个项目的本地优先有明确含义:Vault 只读;Markdown、SQLite、向量和模型缓存在本机;问题与回答默认不写日志;聊天历史只由浏览器临时持有。

如果没有配置 LLM,系统只展示本地检索证据。如果配置了 OpenAI-compatible 服务,当前问题、浏览器随请求携带的最近会话历史与最终证据会发往用户选择的接口,用于生成自然语言回答。它不是全离线系统,所以我不会用"资料永不离开电脑"来宣传它。

更准确的说法是:哪些数据留在本机、哪些数据会在什么条件下发送,都能从配置和代码里确认。对私人知识库而言,可检查的边界比模糊的"AI 隐私安全"口号更重要。

我如何判断这套 RAG 是否真的可用

"页面能返回答案"不是验收标准。我在项目 README 中写入了几项离线评测门槛:初召回 Recall@30 不低于 95%,重排后 Recall@6 不低于 90%,reranker 只有在 MRR 或 nDCG@6 优于 RRF 基线时才默认开启,无证据问题的拒答准确率必须达到 100%。

这些是项目目标,不代表每次换语料、模型或配置后天然满足。私人问题集保存在不提交 Git 的本地文件中;只要索引范围、embedding、切片或阈值改变,就需要重新跑评测。

相比"回答看起来不错",我更关心下面几个问题:

  • 正确证据是否进入初召回;
  • 最相关片段是否在最终证据里;
  • 没有答案时是否真的拒答;
  • 引用能否打开对应 Obsidian 页面与标题;
  • 降级时系统是否明确告诉用户少了哪一层能力;
  • 隐私设置和日志设置是否与页面显示一致。

这套系统现在怎样分工

我不会让 RAG 负责整理知识,也不会让每日整理任务顺手回答所有问题。

Codex 面向文件和工作流:它阅读新材料、联网核验、更新 Wiki、维护链接和来源。RAG 面向即时问题:它只读索引已经整理好的 Wiki,快速找回证据,并把答案约束在证据范围内。

我没有只在提示词里要求模型遵守边界,而是把权限落实到系统结构中:Codex 在知识库维护规则约束下写入文件,RAG 则只能读取已经整理好的 Wiki,不能反向修改 Vault。模型可以理解、起草和建议,但最终能够执行什么,由程序和文件权限决定。

现在,我可以把新材料丢进收集箱,让 Codex 在固定规则下增量整理;也可以打开"语境",问一个问题、检查真实证据,再跳回 Obsidian 原文继续阅读。

这不是一个无需维护的自动大脑。它仍然需要我决定什么值得进入 Wiki、什么属于个人经验、什么需要拒答。但正因为边界清楚,它开始像一套可以长期生长的个人基础设施,而不只是一次 AI Demo。

相关推荐
QZSJTR1 小时前
技术解析|从SEO到GEO:生成式搜索时代实体企业数字化适配方案
人工智能
安逸sgr1 小时前
如何减少 Prompt 引起的幻觉和答非所问?
人工智能·ai·大模型·prompt·agent·智能体
Vince的修炼之路1 小时前
大模型 Skills 技术深度分析
人工智能·架构
小码哥哥1 小时前
企业级AI知识库:高效安全的知识管理新范式
人工智能·安全
AI大模型-小华2 小时前
ChatGPT 服务充值与账户管理实操指南
人工智能·chatgpt·ai编程·codex·chatgpt plus·chatgpt pro
小码哥哥2 小时前
构建企业级 AI 知识库:通往高效与安全的知识管理新范式2
人工智能·安全
tokenKe2 小时前
OpenWork:把 AI Agent 工作台 从订阅制变成开源 + 本地的革命 | SSP Github Daily
人工智能·开源·github
leoZ2312 小时前
CSDN 博客写作任务说明书 · 《Claude Code 实战》系列 · 第 5 篇
人工智能
WA内核拾荒者2 小时前
WhatsApp 对话内容的质量评估体系与自动化检测方案
大数据·人工智能·自动化