RAG 检索增强生成教程¶
概述¶
RAG(Retrieval-Augmented Generation,检索增强生成)是将信息检索与大语言模型结合的技术,让AI能够基于最新、特定的数据进行回答。
RAG工作原理¶
flowchart TB
subgraph 用户输入
Q[用户问题]
end
subgraph 文档处理
D[原始文档] --> S[文档分割]
S --> E[向量嵌入]
E --> V[(向量数据库)]
end
subgraph 检索阶段
Q --> QE[问题向量化]
QE --> V
V --> R[检索相关文档]
end
subgraph 生成阶段
R --> P[构建Prompt]
Q --> P
P --> LLM[大语言模型]
LLM --> A[生成答案]
end
style Q fill:#e3f2fd
style V fill:#fff3e0
style LLM fill:#e8f5e9
style A fill:#f3e5f5 RAG vs 传统LLM¶
graph LR
subgraph 传统LLM
Q1[用户问题] --> LLM1[LLM]
LLM1 --> A1[回答]
end
subgraph RAG
Q2[用户问题] --> LLM2[LLM]
D[知识库] --> R[检索]
R --> LLM2
LLM2 --> A2[回答]
end
style LLM1 fill:#ffcdd2
style D fill:#c8e6c9
style A2 fill:#e8f5e9 为什么需要RAG¶
# 传统LLM的局限
1. 知识截止:无法获取最新信息
2. 幻觉问题:可能生成不存在的内容
3. 领域知识:缺乏专业领域知识
# RAG的优势
1. 实时信息:检索最新数据
2. 减少幻觉:基于真实文档回答
3. 可溯源:可以标注信息来源
RAG核心组件¶
1. 文档处理¶
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.document_loaders import (
PyPDFLoader,
TextLoader,
UnstructuredMarkdownLoader
)
# 加载PDF文档
loader = PyPDFLoader("document.pdf")
documents = loader.load()
# 加载文本文件
loader = TextLoader("document.txt")
documents = loader.load()
# 文档分割
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=500,
chunk_overlap=50,
length_function=len
)
chunks = text_splitter.split_documents(documents)
2. 向量嵌入¶
from langchain_openai import OpenAIEmbeddings
# 使用OpenAI嵌入
embeddings = OpenAIEmbeddings()
# 生成向量
text = "这是一个测试文档"
vector = embeddings.embed_query(text)
print(f"向量维度: {len(vector)}")
3. 向量存储¶
from langchain_community.vectorstores import FAISS
# 创建向量数据库
vectorstore = FAISS.from_documents(chunks, embeddings)
# 添加更多文档
vectorstore.add_documents(new_chunks)
# 保存到本地
vectorstore.save_local("faiss_index")
# 加载本地向量库
vectorstore = FAISS.load_local("faiss_index", embeddings)
4. 检索器¶
# 基本检索
retriever = vectorstore.as_retriever(
search_type="similarity",
search_kwargs={"k": 3}
)
# 检索相关文档
query = "什么是机器学习?"
docs = retriever.invoke(query)
for doc in docs:
print(f"内容: {doc.page_content[:100]}...")
print(f"来源: {doc.metadata}\n")
完整RAG系统¶
使用LangChain构建¶
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_community.vectorstores import FAISS
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.document_loaders import PyPDFLoader
from langchain.chains import RetrievalQA
from langchain.prompts import PromptTemplate
# 1. 加载文档
loader = PyPDFLoader("knowledge_base.pdf")
documents = loader.load()
# 2. 文档分割
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=1000,
chunk_overlap=200
)
chunks = text_splitter.split_documents(documents)
# 3. 创建向量数据库
embeddings = OpenAIEmbeddings()
vectorstore = FAISS.from_documents(chunks, embeddings)
# 4. 创建检索器
retriever = vectorstore.as_retriever(
search_type="similarity",
search_kwargs={"k": 3}
)
# 5. 定义Prompt
prompt_template = """基于以下上下文回答问题。如果上下文中没有相关信息,请说明你不确定。
上下文:
{context}
问题:{question}
回答:"""
prompt = PromptTemplate(
template=prompt_template,
input_variables=["context", "question"]
)
# 6. 创建LLM
llm = ChatOpenAI(model="gpt-5.5", temperature=0)
# 7. 创建QA链
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff",
retriever=retriever,
chain_type_kwargs={"prompt": prompt},
return_source_documents=True
)
# 8. 查询
result = qa_chain.invoke({"query": "什么是深度学习?"})
print(f"回答: {result['result']}")
print(f"\n来源文档:")
for doc in result['source_documents']:
print(f"- {doc.metadata.get('source', '未知')}")
高级RAG技术¶
1. 混合检索¶
from langchain.retrievers import EnsembleRetriever
from langchain_community.retrievers import BM25Retriever
# BM25检索器(关键词匹配)
bm25_retriever = BM25Retriever.from_documents(chunks)
bm25_retriever.k = 3
# 向量检索器(语义匹配)
vector_retriever = vectorstore.as_retriever(search_kwargs={"k": 3})
# 混合检索
ensemble_retriever = EnsembleRetriever(
retrievers=[bm25_retriever, vector_retriever],
weights=[0.4, 0.6] # 权重
)
docs = ensemble_retriever.invoke("什么是神经网络?")
2. 查询改写¶
from langchain.prompts import ChatPromptTemplate
# 查询改写Prompt
rewrite_prompt = ChatPromptTemplate.from_template(
"请将以下用户问题改写为更适合搜索的形式:\n\n"
"原始问题:{question}\n"
"改写后的搜索查询:"
)
# 或使用多查询
from langchain.retrievers.multi_query import MultiQueryRetriever
multi_query_retriever = MultiQueryRetriever.from_llm(
retriever=vectorstore.as_retriever(),
llm=llm
)
docs = multi_query_retriever.invoke("如何学习编程?")
3. 上下文压缩¶
from langchain.retrievers import ContextualCompressionRetriever
from langchain.retrievers.document_compressors import LLMChainExtractor
# 文档压缩器
compressor = LLMChainExtractor.from_llm(llm)
# 压缩检索器
compression_retriever = ContextualCompressionRetriever(
base_compressor=compressor,
base_retriever=retriever
)
docs = compression_retriever.invoke("什么是机器学习?")
# 返回压缩后的相关片段
4. 自查询检索¶
from langchain.retrievers.self_query.base import SelfQueryRetriever
from langchain.chains.query_constructor.base import AttributeInfo
# 定义元数据字段
metadata_field_info = [
AttributeInfo(
name="source",
description="文档来源,如'website'、'pdf'等",
type="string",
),
AttributeInfo(
name="date",
description="文档创建日期",
type="string",
),
]
document_content_description = "技术文档内容"
# 创建自查询检索器
self_query_retriever = SelfQueryRetriever.from_llm(
llm=llm,
vectorstore=vectorstore,
document_contents=document_content_description,
metadata_field_info=metadata_field_info,
)
docs = self_query_retriever.invoke("2024年发布的关于深度学习的文档")
向量数据库对比¶
| 数据库 | 特点 | 适用场景 |
|---|---|---|
| FAISS | Facebook开源,高效 | 本地部署,大规模数据 |
| Pinecone | 云服务,易用 | 生产环境,快速上手 |
| Weaviate | GraphQL接口 | 复杂查询,多模态 |
| Milvus | 分布式,高性能 | 大规模生产环境 |
| Chroma | 轻量级 | 原型开发,小规模数据 |
实战示例:文档问答系统¶
import os
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_community.vectorstores import FAISS
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.document_loaders import DirectoryLoader, TextLoader
from langchain.chains import RetrievalQA
from langchain.prompts import PromptTemplate
import gradio as gr
# 设置API密钥
os.environ["OPENAI_API_KEY"] = "your-api-key"
class DocumentQA:
def __init__(self, doc_dir):
self.doc_dir = doc_dir
self.setup_chain()
def setup_chain(self):
# 加载文档
loader = DirectoryLoader(
self.doc_dir,
glob="**/*.txt",
loader_cls=TextLoader
)
documents = loader.load()
# 分割文档
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=1000,
chunk_overlap=200
)
chunks = text_splitter.split_documents(documents)
# 创建向量库
embeddings = OpenAIEmbeddings()
self.vectorstore = FAISS.from_documents(chunks, embeddings)
# 创建QA链
prompt_template = """基于以下上下文回答问题。如果不确定,请说明。
上下文:{context}
问题:{question}
回答:"""
prompt = PromptTemplate(
template=prompt_template,
input_variables=["context", "question"]
)
llm = ChatOpenAI(model="gpt-5.5")
self.qa_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff",
retriever=self.vectorstore.as_retriever(),
chain_type_kwargs={"prompt": prompt}
)
def ask(self, question):
result = self.qa_chain.invoke({"query": question})
return result['result']
# 创建Gradio界面
qa = DocumentQA("./documents")
interface = gr.Interface(
fn=qa.ask,
inputs=gr.Textbox(label="请输入问题"),
outputs=gr.Textbox(label="回答"),
title="文档问答系统",
description="基于RAG的智能文档问答"
)
interface.launch()
优化建议¶
# 提升RAG效果
1. 文档质量
- 清洗文档,去除噪音
- 合理分割,保持语义完整
2. 检索优化
- 调整chunk_size和overlap
- 使用混合检索
- 添加重排序
3. Prompt优化
- 设计更好的提示模板
- 添加few-shot示例
4. 后处理
- 相关性过滤
- 上下文压缩
下一步学习¶
- LangChain框架教程 - 深入学习RAG框架
- 向量数据库教程 - 选择合适的向量库
- 大语言模型原理 - 理解LLM工作原理