你有没有遇到过这种情况:公司有几百份文档、合同、技术方案散落在各部门电脑里,每次查一个条款要翻半天?RAG(Retrieval-Augmented Generation,检索增强生成)就是解决这个问题的。它把「检索相关文档」和「AI 生成回答」两个步骤串起来,让 AI 能基于你的私有文档回答问题,而不是靠训练数据里那点过时的记忆。

本教程用 DeepSeek-V4(2026 年国产开源模型的标杆)+ LangChain + Chroma 向量数据库,在你本地电脑上跑一个完全离线的私有知识库问答系统。不需要连外网,数据也不会传到云端。

RAG 系统架构:文档 → 切块 → 向量化 → 存入 Chroma → 检索 → 大模型回答
RAG 系统架构:文档 → 切块 → 向量化 → 存入 Chroma → 检索 → 大模型回答

RAG 的工作流程

简单说就是四步:

  1. 把文档切成小块(比如每段 500 字)
  2. 每块用嵌入模型(Embedding Model)转成向量(一串数字,表示语义)
  3. 所有向量存在向量数据库里(Chroma)
  4. 用户提问时,先在数据库中检索相关块,然后把检索结果和问题一起喂给大模型,让它基于这些资料回答

这样大模型的回答就有了「依据」——不是凭空编的,是文档里真实存在的内容。

第一步:环境准备

确保你有 Python 3.10+ 和至少 16GB 内存。DeepSeek-V4 可以通过 Ollama 运行:

  1. 安装 Ollama:ollama.com/download(Windows/Mac/Linux 都有)
  2. 拉取 DeepSeek-V4 模型:
ollama pull deepseek-v4:8b

这里选 8B 参数版本,对显存要求低(约 6GB),普通电脑就能跑。如果你有 24GB 以上显存,也可以拉 deepseek-v4:70b 的大参数版。

测试模型是否正常:

ollama run deepseek-v4:8b

输入「你好」看是否有回复。

第二步:安装 Python 依赖

pip install langchain langchain-community chromadb sentence-transformers ollama

各包的作用:

  • langchain:编排整个 RAG 流程的框架
  • chromadb:轻量级向量数据库,数据落盘,重启不丢
  • sentence-transformers:本地的嵌入模型(如 all-MiniLM-L6-v2),负责把文字转为向量
  • ollama:调用本地大模型的 Python 客户端

第三步:准备知识库文档

在项目目录新建一个 data/ 文件夹,把你需要检索的文档放进去。支持 txt、md、pdf、docx 格式。

示例:我们放一篇公司产品文档 product-intro.txt,内容如下:

Fidu AI 导航站于 2025 年上线,是国内首个零依赖纯 Node.js 的 AI 工具聚合平台。
平台聚合了 200+ AI 工具,覆��绘画、编程、办公、视频等 12 个品类。
日均访问用户超过 5000 人,累计收录 10 万+ AI 工具。

Fidu 采用 Cloudflare 全栈部署:Pages 托管前端、Workers 处理 API、D1 做数据库。
所有 API 路由由纯 Node.js 零依赖实现,不依赖 Express、Koa 等第三方框架。
认证系统基于 HMAC-SHA256 自签 JWT,密码使用 Node.js 内置 crypto.scrypt 加密。
社区功能包括用户文章发布、点赞评论、收藏关注等全栈交互系统。

第四步:构建 RAG 核心代码

新建一个 rag.py 文件,完整代码如下:

from langchain_community.document_loaders import TextLoader, DirectoryLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.vectorstores import Chroma
from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain.chains import RetrievalQA
from langchain_community.llms import Ollama
import os

# 1. 加载文档
loader = DirectoryLoader('./data/', glob='**/*.txt', loader_cls=TextLoader)
documents = loader.load()
print(f'Loaded {len(documents)} documents')

# 2. 切分文本块(每块 500 字,重叠 100 字保证上下文不丢失)
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=500, chunk_overlap=100,
    separators=['\n\n', '\n', '。', ',', ' ']
)
chunks = text_splitter.split_documents(documents)
print(f'Split into {len(chunks)} chunks')

# 3. 向量化并存入 Chroma
embeddings = HuggingFaceEmbeddings(
    model_name='shibing624/text2vec-base-chinese'
)
vectorstore = Chroma.from_documents(
    chunks, embeddings,
    persist_directory='./chroma_db'
)
vectorstore.persist()
print('Vector store saved')

# 4. 创建问答链
llm = Ollama(model='deepseek-v4:8b', temperature=0.1)
qa_chain = RetrievalQA.from_chain_type(
    llm=llm,
    chain_type='stuff',
    retriever=vectorstore.as_retriever(search_kwargs={'k': 3}),
    return_source_documents=True
)

# 5. 提问
question = 'Fidu 站点的认证系统是怎么实现的?'
result = qa_chain({'query': question})
print(f'\n问题: {question}')
print(f'回答: {result["result"]}')
print(f'\n参考来源:')
for doc in result['source_documents']:
    print(f'  - {doc.metadata.get("source", "unknown")}')

这个脚本会:加载 data/ 下的所有 txt 文件 → 切成小块 → 向量化存入 Chroma → 提问并给出带引用的答案。

RAG 系统回答结果,包含引用来源
RAG 系统回答结果,包含引用来源

关键参数解读

  • chunk_size=500:每个文本块约 500 个字符。太小丢失上下文,太大检索不准。中文建议 300-600
  • chunk_overlap=100:相邻块之间重叠 100 字符,确保不会因为切分点刚好切断一句话而丢失信息
  • search_kwargs={'k': 3}:每次检索取最相关的 3 个块。太少信息不足,太多干扰模型
  • temperature=0.1:RAG 场景下温度要低,保证回答基于文档而不是自由发挥

第五步:支持中文的最佳实践

上面的示例用了英文向量模型 all-MiniLM,对中文效果一般。换成中文专用模型:

embeddings = HuggingFaceEmbeddings(model_name='shibing624/text2vec-base-chinese')

这个模型专为中文优化,在 C-MTEB 中文语义检索评测中排名靠前。如果你想更准,可以用 BGE 系列:BAAI/bge-large-zh-v1.5,但需要更多显存。

进阶方向

  • 接入前端界面:用 Gradio 或 Streamlit 做一个 Web 对话界面,参考教程 3 的思路用 Cursor 写
  • 拓展文档格式:用 Unstructured 库支持 PDF、DOCX、PPT、Excel 等多种格式
  • 优化检索质量:加入重排序(Reranker),对初检结果二次排序,如 BAAI/bge-reranker-v2-m3
  • 混合检索:结合关键词检索(BM25)+ 语义检索,互补各自的盲区
  • 增量更新:文档更新后不需要重建整个向量库,用 vectorstore.add_documents(new_docs) 增量添加