RAG 本地实践:用 Ollama + Embedding 搭建私有知识库
大模型虽然强大,但有两个致命弱点:知识截止和幻觉问题。RAG(Retrieval-Augmented Generation,检索增强生成)通过在回答前检索相关知识,有效解决了这两个问题。
但云端 RAG 服务存在隐私风险。本文介绍如何完全本地化搭建 RAG 系统,数据不出本机,同时获得接近 GPT-4 的问答体验。
核心优势:完全离线、数据私有、零 API 费用、响应速度快
技术架构
| 组件 | 选型 | 作用 |
|---|---|---|
| LLM | Ollama | 本地运行大模型,提供生成能力 |
| Embedding | nomic-embed-text / mxbai-embed-large | 文本向量化,用于语义检索 |
| 向量数据库 | ChromaDB / Qdrant | 存储和检索向量 |
| 框架 | LangChain / LlamaIndex | 编排 RAG 流程 |
环境准备
1. 安装 Ollama
# macOS / Linux
curl -fsSL https://ollama.com/install.sh | sh
# 拉取模型(推荐 qwen2.5:7b 中文效果好)
ollama pull qwen2.5:7b
ollama pull nomic-embed-text
2. 安装依赖
pip install ollama chromadb langchain langchain-ollama
核心实现
文档加载与切分
from langchain_community.document_loaders import TextLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
# 加载文档
loader = TextLoader("docs/my_notes.txt")
docs = loader.load()
# 切分文档(每块 500 字符,重叠 50)
splitter = RecursiveCharacterTextSplitter(
chunk_size=500, chunk_overlap=50
)
chunks = splitter.split_documents(docs)
向量化与存储
from langchain_ollama import OllamaEmbeddings
from langchain_chroma import Chroma
# 初始化 Embedding 模型
embeddings = OllamaEmbeddings(model="nomic-embed-text")
# 存入向量数据库
vectorstore = Chroma.from_documents(
documents=chunks,
embedding=embeddings,
persist_directory="./chroma_db"
)
检索与生成
from langchain_ollama import ChatOllama
from langchain.chains import RetrievalQA
# 初始化 LLM
llm = ChatOllama(model="qwen2.5:7b", temperature=0.7)
# 创建 RAG Chain
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
retriever=vectorstore.as_retriever(search_kwargs={"k": 3}),
return_source_documents=True
)
# 提问
result = qa_chain.invoke({"query": "我的项目用了什么技术栈?"})
print(result["result"])
性能优化
- 文档切分策略:按语义段落切分,避免在句子中间断开
- 重排序(Rerank):用 cross-encoder 对检索结果重排序,提升相关性
- 混合检索:结合关键词检索(BM25)和向量检索
- 量化模型:使用 4-bit 量化模型减少显存占用
踩坑记录
Embedding 模型选择:nomic-embed-text 对英文效果好,中文建议用 mxbai-embed-large 或 bge-m3
文档切分大小:chunk_size 太大导致检索不精确,太小导致上下文丢失,建议 300-500 字符
显存不足:7B 模型需要 4-8GB 显存,可用量化版本(qwen2.5:7b-q4_K_M)
进阶:Web 界面
用 Streamlit 快速搭建问答界面:
import streamlit as st
st.title("📚 私有知识库问答")
question = st.text_input("提问")
if question:
with st.spinner("思考中..."):
result = qa_chain.invoke({"query": question})
st.write(result["result"])
with st.expander("参考来源"):
for doc in result["source_documents"]:
st.markdown(f"- {doc.page_content[:200]}...")
总结
本地 RAG 方案让大模型真正"可用":
- ✅ 数据完全私有,适合敏感信息
- ✅ 无 API 费用,长期使用成本低
- ✅ 响应速度快,无需网络等待
- ✅ 可定制性强,模型、参数完全可控
对于个人知识管理、企业内部文档问答等场景,本地 RAG 是性价比最高的方案。
参考资源:
Ollama:github.com/ollama/ollama
LangChain:github.com/langchain-ai/langchain
ChromaDB:github.com/chroma-core/chroma
Ollama:github.com/ollama/ollama
LangChain:github.com/langchain-ai/langchain
ChromaDB:github.com/chroma-core/chroma