给个人知识库接入 RAG
作为一个长期使用 Obsidian 的重度用户,我的笔记库累计了上千张卡片。检索靠「全文搜索」越来越力不从心:关键词匹配不到语义相近的内容。
于是我用 RAG(Retrieval-Augmented Generation,检索增强生成)给笔记库装了一个「能对话的搜索引擎」。本文记录完整过程,附关键参数与实测数据,可直接复用。
一、整体架构
RAG 的原理一句话:先检索,再生成。架构如下:
[Obsidian 笔记库]
│ 解析 + 分块
▼
[Embedding 模型] ──向量化──▶ [向量数据库]
│ 相似度检索(top-k)
▼
[用户问题] ──embedding──▶ [检索器] ──候选片段──▶ [LLM] ──▶ 答案
▲ │
└──── 上下文(检索结果)────┘
二、关键决策与实测数据
1. 分块策略(最重要的一步)
分块质量直接决定检索质量。我对比了三种方案:
| 分块方式 | 召回率(Recall@5) | 问题 |
|---|---|---|
| 固定 500 字切块 | 0.62 | 切断了语义完整段落 |
| 按标题层级切块 | 0.78 | 长章节仍超限 |
| 标题层级 + 递归切块 | 0.87 | 依赖笔记结构规范 |
结论:先按 Markdown 标题切块,再对超长块递归切分,块大小 300~500 字,重叠 50 字。
2. 嵌入模型选择
中文场景下,我对比了 bge-large-zh-v1.5 与通用多语言模型:
- bge-large-zh-v1.5:中文语义更准,维度 1024,单次嵌入成本约 0.05 元/万字符;
- 本地运行 8GB 显存即可,延迟约 40ms/块。
3. 检索与重排
仅靠向量相似度容易召回「表面相似、语义无关」的结果,因此加了**重排(rerank)**环节:
# 简化示意:向量检索 + 重排的管线
from sentence_transformers import CrossEncoder
vector_hits = vector_db.search(query_emb, top_k=20) # 初筛
reranker = CrossEncoder("bge-reranker-base") # 精排
scored = reranker.rank(query, [h.text for h in vector_hits])
final = scored[:5] # 取前 5 进上下文
加入重排后,答案准确率(人工评估)从 68% 提升到 83%。
三、实测问答效果
| 提问 | 回答质量 |
|---|---|
| 「我关于卡片笔记法的观点有哪些?」 | ✅ 准确聚合 4 张卡片的核心观点 |
| 「费曼技巧和间隔重复有什么关系?」 | ⚠️ 能答出两者,但联系部分有过度推断 |
| 「2024 年我定的目标是什么?」 | ❌ 检索失败(笔记未规范结构化) |
两个教训:
- RAG 的上限由笔记质量决定——结构化笔记的检索效果远好于散装碎片;
- 生成的答案会「编造」——务必给 LLM 加提示词:「只能基于给定上下文回答,不知道就直说」。
四、何时不该用 RAG
- 笔记少于 100 张:全文搜索 + 标签足够;
- 对时效性要求极高(如实时资讯):RAG 快照滞后;
- 需要精确引用页码:向量检索天然损失定位精度。
RAG 是「知识的放大器」,不是「知识的替代品」。 放大器的上限,永远是输入信号的保真度。
一句话总结:RAG 让笔记库从「存」走向「用」——但前提是,你的笔记本身值得被检索。