跳转至

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. 后处理
   - 相关性过滤
   - 上下文压缩

下一步学习

  1. LangChain框架教程 - 深入学习RAG框架
  2. 向量数据库教程 - 选择合适的向量库
  3. 大语言模型原理 - 理解LLM工作原理