# Python + LangChain 本地 RAG 实战:让 AI 学你的知识
Ollama 跑通了,下一个问题是:怎么让它学会你自己的东西?
单纯跑模型,AI 一问三不知。你扔给它一份公司文档,它该不知道还是不知道。这时候该 RAG 上场了——Retrieval Augmented Generation,检索增强生成。听起来高大上其实就是那么回事:先找到相关内容,再让 AI 根据这些内容回答。
这篇文章就教你用 Python + LangChain,在本地搭一个完整的 RAG 问答系统。
## RAG 到底是怎么回事
传统 LLM 有几个硬伤:训练数据有截止日期、不知道你的私有数据、偶尔会一本正经地胡说八道。RAG 通过一套流程来补这些短板:
1. 把 PDF、txt、markdown 文档读进来
2. 把长文档切成小块
3. 把文本转成向量存起来
4. 用户提问时,先找出最相关的几个小块
5. 把这些小块塞进 Prompt 里
6. 最后让 LLM 基于这个增强后的上下文生成答案
说白了就是:先检索,再生成。
环境准备很简单:
“`bash
pip install langchain langchain-community langchain-ollama ollama chroma beautifulsoup4 pypdf
“`
本文用的版本:Python 3.10+、LangChain 0.3+、Chroma 向量数据库、Ollama 的 llama3:latest 模型。
## 实际问题
你可能遇到过这些场景:
– 公司有一堆内部文档,想让 AI 帮忙查
– 自己的笔记、日记、博客想让它分析
– 扔一个 PDF 报告进去,想问点什么
– 不希望 AI 凭空编造,必须有据可查
这些需求,RAG 都能解决。
## 一步步来
### 第一步:准备知识文档
先建个测试目录扔点文档进去:
“`python
import os
# 创建测试目录
docs_folder = “./knowledge_base”
os.makedirs(docs_folder, exist_ok=True)
# 扔几个测试文档进去
sample_docs = [
(“公司介绍.txt”, “””我们的公司成立于2020年,专注于人工智能领域。
创始团队来自谷歌、微软等知名科技公司。
公司总部位于北京,在上海和深圳设有分部。
2023年获得红杉资本B轮融资5000万美元。””),
(“产品手册.txt”, “””产品名称:SmartAI Assistant
版本:3.2.1
主要功能:智能问答、文档分析、数据可视化
支持语言:中文、英文、日文
系统要求:Mac/Windows/Linux
定价:企业版999元/年,团队版299元/年”””
)
]
for filename, content in sample_docs:
with open(f”{docs_folder}/{filename}”, “w”, encoding=”utf-8″) as f:
f.write(content)
print(“文档就绪”)
“`
### 第二步:加载文档、切块
用 LangChain 的文档加载器处理:
“`python
from langchain_community.document_loaders import TextLoader
from langchain.text_splitter import CharacterTextSplitter
import os
# 加载文件夹里的文档
def load_documents(folder_path):
documents = []
for filename in os.listdir(folder_path):
if filename.endswith((“.txt”, “.md”, “.pdf”)):
filepath = os.path.join(folder_path, filename)
loader = TextLoader(filepath, encoding=”utf-8″)
docs = loader.load()
documents.extend(docs)
return documents
# 加载并切块
raw_documents = load_documents(docs_folder)
# 切块策略:每个块 200 字符,相邻块重叠 50 字符
text_splitter = CharacterTextSplitter(
chunk_size=200,
chunk_overlap=50,
separator=”\n”
)
docs = text_splitter.split_documents(raw_documents)
print(f”共 {len(docs)} 个文档块”)
for i, doc in enumerate(docs[:3]):
print(f”块 {i+1}: {doc.page_content[:50]}…”)
“`
### 第三步:建向量数据库
Chroma 是本地向量数据库的好选择:
“`python
from langchain_ollama import OllamaEmbeddings
from langchain_community.vectorstores import Chroma
# 嵌入模型用 Ollama 的 nomic-embed-text
embeddings = OllamaEmbeddings(
model=”nomic-embed-text”,
base_url=”http://localhost:11434″
)
# 存入 Chroma
vectorstore = Chroma.from_documents(
documents=docs,
embedding=embeddings,
persist_directory=”./chroma_db”
)
print(“向量数据库建好了”)
“`
### 第四步:拼装 RAG 链
检索和生成要连起来:
“`python
from langchain_ollama import ChatOllama
from langchain import hub
from langchain_core.output_parsers import StrOutputParser
# 用本地模型
llm = ChatOllama(
model=”llama3:latest”,
base_url=”http://localhost:11434″,
temperature=0
)
# LangChain Hub 上现成的 RAG prompt
prompt = hub.pull(“rlm/rag-prompt”)
# 检索器:找最相关的 3 个块
retriever = vectorstore.as_retriever(
search_kwargs={“k”: 3}
)
# RAG 链
def format_docs(docs):
return “\n\n”.join(doc.page_content for doc in docs)
rag_chain = (
{“context”: retriever | format_docs, “question”: lambda x: x}
| prompt
| llm
| StrOutputParser()
)
print(“RAG 链完成”)
“`
## 完整代码
上面的步骤整合到一个脚本里:
“`python
#!/usr/bin/env python3
“””本地 RAG 问答系统”””
import os
from langchain_community.document_loaders import TextLoader
from langchain.text_splitter import CharacterTextSplitter
from langchain_ollama import OllamaEmbeddings, ChatOllama
from langchain_community.vectorstores import Chroma
from langchain import hub
from langchain_core.output_parsers import StrOutputParser
class LocalRAG:
def __init__(self, docs_folder=”./knowledge_base”):
self.docs_folder = docs_folder
self.embeddings = None
self.vectorstore = None
self.llm = None
self.rag_chain = None
def init(self):
print(“加载文档…”)
documents = self._load_documents()
print(“切块…”)
chunks = self._split_documents(documents)
print(“建向量库…”)
self._create_vectorstore(chunks)
print(“拼装 RAG 链…”)
self._build_rag_chain()
print(“搞定”)
def _load_documents(self):
documents = []
for root, dirs, files in os.walk(self.docs_folder):
for file in files:
if file.endswith((“.txt”, “.md”)):
loader = TextLoader(
os.path.join(root, file),
encoding=”utf-8″
)
documents.extend(loader.load())
return documents
def _split_documents(self, documents):
splitter = CharacterTextSplitter(
chunk_size=200,
chunk_overlap=50
)
return splitter.split_documents(documents)
def _create_vectorstore(self, chunks):
self.embeddings = OllamaEmbeddings(
model=”nomic-embed-text”
)
self.vectorstore = Chroma.from_documents(
documents=chunks,
embedding=self.embeddings,
persist_directory=”./chroma_db”
)
def _build_rag_chain(self):
self.llm = ChatOllama(
model=”llama3:latest”,
temperature=0
)
retriever = self.vectorstore.as_retriever(search_kwargs={“k”: 3})
prompt = hub.pull(“rlm/rag-prompt”)
def format_docs(docs):
return “\n\n”.join(doc.page_content for doc in docs)
self.rag_chain = (
{“context”: retriever | format_docs, “question”: lambda x: x}
| prompt
| self.llm
| StrOutputParser()
)
def ask(self, question):
if not self.rag_chain:
raise RuntimeError(“先调用 init()”)
print(f”\n问题: {question}”)
print(“思考中…”)
answer = self.rag_chain.invoke(question)
print(f”回答: {answer}”)
return answer
if __name__ == “__main__”:
# 初始化
rag = LocalRAG(“./knowledge_base”)
rag.init()
# 问答测试
questions = [
“公司成立于哪一年?”,
“产品多少钱一年?”,
“创始团队来自哪里?”
]
for q in questions:
rag.ask(q)
print(“-” * 50)
“`
## 跑起来
“`bash
$ python rag_chatbot.py
加载文档…
切块…
建向量库…
拼装 RAG 链…
搞定
问题: 公司成立于哪一年?
思考中…
回答: 我们的公司成立于2020年,专注于人工智能领域。
问题: 产品多少钱一年?
思考中…
回答: 企业版999元/年,团队版299元/年
问题: 创始团队来自哪里?
思考中…
回答: 创始团队来自谷歌、微软等知名科技公司。
“`
像模像样了。AI 不仅能回答,还能从你给的文档里找到答案。
## 总结
这套流程跑下来,你应该掌握了:
1. 文档加载:txt、md、pdf 都能读
2. 文本切块:重叠机制保证语义不丢
3. 向量存储:Ollama 的 nomic-embed-text 做嵌入,Chroma 本地持久化
4. RAG 链路:检索增强 + LLM 生成
想玩更大?可以试试:
– 加载 PDF:用 PyPDFLoader
– 加载网页:用 WebBaseLoader
– 调参数:改 chunk_size、改 k 值
– 换模型:qwen2.5、deepseek 都可以
– 加界面:Gradio 搭一个简单的 Demo
RAG 的核心价值在于:让任何人都能基于自己的知识库和 AI 对话。企业做内部知识库、个人做私有助手、客服系统接文档——都能用这个思路。自己去试试吧。