RAG 2026-06-15

本地知识库 RAG 入门实践

RAG 向量数据库 Embedding 知识库

背景

大模型的知识受限于训练数据,对于个人笔记、项目文档或内部规范这类私有内容,它往往“不知道”或者“瞎编”。RAG(Retrieval-Augmented Generation,检索增强生成)提供了一种低成本解决方案:先把文档向量化存进数据库,查询时检索最相关的片段,再把这些片段作为上下文交给模型生成答案。

我最近整理了大量学习笔记,想做一个可以“问答”的个人知识库。与其微调模型,不如先试试 RAG。这次实践主要使用了本地 Embedding 模型和 Chroma 向量数据库。

核心思路

RAG 的流程可以分成两个阶段:索引(Indexing)和检索生成(Retrieval & Generation)。

索引阶段

  1. 1 加载原始文档(Markdown、PDF、TXT 等)。
  2. 2 对文档进行分块(Chunking),控制每块的大小与重叠。
  3. 3 使用 Embedding 模型把每块文本转换为向量。
  4. 4 将向量与原文一起存入向量数据库。

检索生成阶段

  1. 1 把用户问题也转换为向量。
  2. 2 在向量库中搜索最相似的 Top-K 文本块。
  3. 3 将检索结果作为上下文,结合问题生成答案。

示例

在分块策略上,我对比了两种方案:按固定字符数切分和按 Markdown 标题切分。对于结构化的学习笔记,按标题切分能保留更完整的语义单元,检索准确率明显更高。

# 伪代码:构建索引
from langchain_community.vectorstores import Chroma
from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain.text_splitter import MarkdownHeaderTextSplitter

splitter = MarkdownHeaderTextSplitter(headers_to_split_on=[("#", "Header 1"), ("##", "Header 2")])
chunks = splitter.split_text(markdown_content)

embedding = HuggingFaceEmbeddings(model_name="BAAI/bge-small-zh")
vectorstore = Chroma.from_documents(chunks, embedding, persist_directory="./chroma_db")

# 查询
retriever = vectorstore.as_retriever(search_kwargs={"k": 4})
relevant_docs = retriever.invoke("什么是 ReAct 模式?")

实际测试时,我发现如果 Top-K 设置得太小,模型可能拿不到足够背景;设置得太大,又会引入无关信息。目前在笔记场景下,K=4 是一个不错的起点。

总结

RAG 让大模型能够“读”我的私有笔记,而且实现成本远低于微调。在这次实践中,分块策略和 Embedding 模型选择对最终效果影响最大。

后续我还想尝试加入重排序(Reranker)和查询改写(Query Rewriting),进一步提升问答的准确率和用户体验。