返回博客

RAG 本地实践:用 Ollama + Embedding 搭建私有知识库

大模型虽然强大,但有两个致命弱点:知识截止幻觉问题。RAG(Retrieval-Augmented Generation,检索增强生成)通过在回答前检索相关知识,有效解决了这两个问题。

但云端 RAG 服务存在隐私风险。本文介绍如何完全本地化搭建 RAG 系统,数据不出本机,同时获得接近 GPT-4 的问答体验。

核心优势:完全离线、数据私有、零 API 费用、响应速度快

技术架构

组件选型作用
LLMOllama本地运行大模型,提供生成能力
Embeddingnomic-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"])

性能优化

踩坑记录

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 方案让大模型真正"可用":

对于个人知识管理、企业内部文档问答等场景,本地 RAG 是性价比最高的方案。