RAG 从零到一:用 Python 给大模型接上你的私有知识库

大模型很聪明,但它有个致命弱点------它只知道训练截止日期之前的信息,而且不知道你公司内部的任何东西。

RAG(Retrieval-Augmented Generation,检索增强生成)就是解决这个问题的标准方案:先从你的私有文档里检索出相关内容,再把这些内容拼进 prompt 让大模型回答。

本文带你从零实现一个完整的 RAG 系统,代码可以直接跑。

整体架构

RAG 的流程分两个阶段:

建库阶段(离线):

  1. 加载文档(PDF、txt、网页等)
  2. 切分成小块(chunk)
  3. 向量化每个 chunk
  4. 存入向量数据库

查询阶段(在线):

  1. 用户提问
  2. 把问题向量化
  3. 从向量库里找最相似的 chunk
  4. 把 chunk + 问题拼成 prompt
  5. 大模型生成回答

环境准备

bash 复制代码
pip install langchain langchain-community chromadb openai tiktoken

本文用 ChromaDB 做向量库,用 OpenAI Embedding 做向量化,大模型调 GPT-3.5。如果想换成国内模型(DeepSeek、通义等),只需换掉 LLM 和 Embedding 的初始化部分。

第一步:加载并切分文档

python 复制代码
from langchain.document_loaders import TextLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter

# 加载文档
loader = TextLoader("knowledge.txt", encoding="utf-8")
documents = loader.load()

# 切分:每块 500 字符,重叠 50 字符
splitter = RecursiveCharacterTextSplitter(
    chunk_size=500,
    chunk_overlap=50,
)
chunks = splitter.split_documents(documents)
print(f"切分出 {len(chunks)} 个 chunk")

chunk_overlap 是关键参数------让相邻 chunk 有一定重叠,避免一句话被切断后上下文丢失。

第二步:向量化并存入 ChromaDB

python 复制代码
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import Chroma

embeddings = OpenAIEmbeddings()

# 建库(第一次运行会调 Embedding API,有费用)
vectorstore = Chroma.from_documents(
    documents=chunks,
    embedding=embeddings,
    persist_directory="./chroma_db"  # 持久化到本地
)
vectorstore.persist()
print("向量库建立完成")

第三步:检索 + 生成

python 复制代码
from langchain.chat_models import ChatOpenAI
from langchain.chains import RetrievalQA

# 加载已有的向量库
vectorstore = Chroma(
    persist_directory="./chroma_db",
    embedding_function=OpenAIEmbeddings()
)

llm = ChatOpenAI(model_name="gpt-3.5-turbo", temperature=0)

qa_chain = RetrievalQA.from_chain_type(
    llm=llm,
    chain_type="stuff",
    retriever=vectorstore.as_retriever(search_kwargs={"k": 3}),  # 取最相关的3个chunk
    return_source_documents=True  # 同时返回来源,方便溯源
)

# 开始提问
question = "我们产品的退款政策是什么?"
result = qa_chain({"query": question})

print("回答:", result["result"])
print("\n来源文档:")
for doc in result["source_documents"]:
    print("-", doc.page_content[:100])

几个实际踩坑点

1. chunk 大小要根据内容调

技术文档、合同这类信息密度高的,chunk_size 设 300-500 比较合适;FAQ 问答类可以更小,100-200 就够。太大会引入噪音,太小会丢失上下文。

2. Embedding 模型和查询要用同一个

建库和查询必须用同一个 Embedding 模型,不然向量空间不一致,检索结果会很差。

3. k 值不是越大越好

retriever 里的 k(返回几个 chunk)建议从 3 开始。k 太大会把不相关内容塞进 prompt,反而干扰模型回答。

4. 中文切分要注意

RecursiveCharacterTextSplitter 对中文支持还行,但如果文档是纯中文,建议加上中文标点作为切分分隔符:

python 复制代码
splitter = RecursiveCharacterTextSplitter(
    chunk_size=300,
    chunk_overlap=30,
    separators=["\n\n", "\n", "。", "!", "?", ";", " ", ""]
)

替换成本地/国产模型

不想用 OpenAI 的话,换成 DeepSeek 只需改两行:

python 复制代码
from langchain.chat_models import ChatOpenAI

llm = ChatOpenAI(
    model_name="deepseek-chat",
    openai_api_key="your-deepseek-key",
    openai_api_base="https://api.deepseek.com/v1"
)

Embedding 可以换成 HuggingFace 的免费模型:

python 复制代码
from langchain.embeddings import HuggingFaceEmbeddings

embeddings = HuggingFaceEmbeddings(
    model_name="BAAI/bge-small-zh-v1.5"  # 中文效果不错
)

下一步

这是最基础的 RAG 实现。实际项目里还会遇到:

  • 文档更新怎么增量入库
  • 多路召回(关键词 + 向量混合检索)
  • Rerank 对召回结果重排序
  • 对话历史管理(多轮问答)

这些进阶内容在 gufacode.com 的 RAG 教程里有完整讲解,从原理到工程落地都有覆盖,可以继续深入。


跑通这个基础版本之后,你会发现 RAG 本身并不复杂------复杂的是让它在真实数据上表现稳定。慢慢调,多踩坑,才是正经路子。

相关推荐
我叫黑大帅2 小时前
受保护的海报图片读取方案 - 在不公开静态资源目录下如何获取静态资源
后端·python·面试
思绪无限2 小时前
YOLOv5至YOLOv12升级:农作物害虫检测系统的设计与实现(完整代码+界面+数据集项目)
人工智能·python·深度学习·目标检测·计算机视觉·yolov12·农作物害虫检测
码界筑梦坊2 小时前
94-基于Python的商品物流数据可视化分析系统
开发语言·python·mysql·信息可视化·数据分析·毕业设计·fastapi
元Y亨H2 小时前
Python 获取 Windows 设备信息笔记
windows·python
微刻时光2 小时前
影刀RPA:For循环与ForEach循环深度解析与实战指南
人工智能·python·低代码·自动化·rpa·影刀实战
KIHU快狐2 小时前
快狐KIHU|110寸壁挂触控一体机G+G电容屏安卓系统汽车展厅查询展示
android·python·汽车
斯维赤2 小时前
每天学习一个小算法:快速排序
java·python·学习·算法·排序算法
2501_914245932 小时前
C#怎么使用属性Property C#自动属性和完整属性的区别get set怎么用【基础】
jvm·数据库·python
deephub2 小时前
LLM 幻觉的架构级修复:推理参数、RAG、受约束解码与生成后验证
人工智能·python·大语言模型·ai幻觉