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 本身并不复杂------复杂的是让它在真实数据上表现稳定。慢慢调,多踩坑,才是正经路子。

相关推荐
wyhua20082 分钟前
Installing the classic Jupyter Notebook interface
python
yexuhgu7 分钟前
Redis怎样节省海量状态存储内存_利用Bitmap结构替代传统String存储
jvm·数据库·python
极光代码工作室8 分钟前
基于大数据的交通流量分析系统
大数据·hadoop·python·数据分析·数据可视化
2301_7796224111 分钟前
如何修复SQL嵌套查询死锁_调整锁粒度与执行顺序
jvm·数据库·python
iAm_Ike13 分钟前
HTML怎么显示灵感便签关联项目_HTML拖拽绑定项目入口【详解】
jvm·数据库·python
2301_8092047016 分钟前
SQL如何实现实时数据的滑动窗口分析_SQL性能调优
jvm·数据库·python
木子墨51616 分钟前
工程算法实战 | 数据库ORDER BY的底层:内存排序 → 外部归并 → 索引优化
数据结构·数据库·python·sql·算法·动态规划
yexuhgu17 分钟前
如何在 JavaScript 循环中动态构建 HTML 字符串
jvm·数据库·python
wang3zc19 分钟前
使用BERTopic对名言数据集进行批量主题建模的完整实践指南
jvm·数据库·python
码界筑梦坊21 分钟前
361-基于Python的空气质量气候数据分析预测系统
python·信息可视化·数据分析·flask·vue·毕业设计