RAG
2026-06-15
本地知识库 RAG 入门实践
RAG
向量数据库
Embedding
知识库
背景
大模型的知识受限于训练数据,对于个人笔记、项目文档或内部规范这类私有内容,它往往“不知道”或者“瞎编”。RAG(Retrieval-Augmented Generation,检索增强生成)提供了一种低成本解决方案:先把文档向量化存进数据库,查询时检索最相关的片段,再把这些片段作为上下文交给模型生成答案。
我最近整理了大量学习笔记,想做一个可以“问答”的个人知识库。与其微调模型,不如先试试 RAG。这次实践主要使用了本地 Embedding 模型和 Chroma 向量数据库。
核心思路
RAG 的流程可以分成两个阶段:索引(Indexing)和检索生成(Retrieval & Generation)。
索引阶段
- 1 加载原始文档(Markdown、PDF、TXT 等)。
- 2 对文档进行分块(Chunking),控制每块的大小与重叠。
- 3 使用 Embedding 模型把每块文本转换为向量。
- 4 将向量与原文一起存入向量数据库。
检索生成阶段
- 1 把用户问题也转换为向量。
- 2 在向量库中搜索最相似的 Top-K 文本块。
- 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),进一步提升问答的准确率和用户体验。