RAG系统 进阶 RAG 架构 检索 生成

RAG架构概览:从检索到生成的完整技术链路

AIEng Hub
阅读约 20 分钟

引言

RAG(Retrieval-Augmented Generation)已成为构建LLM应用的主流架构范式。它将信息检索与文本生成有机结合,让AI系统既能利用大模型的推理能力,又能访问实时、私有的外部知识。

然而,RAG并非单一技术,而是一套包含多个组件的系统工程。从文档摄入到最终答案生成,每一步都涉及关键的设计决策。理解整体架构,是构建可靠RAG系统的第一步。

本文将系统梳理RAG的完整技术链路,涵盖离线和在线两大流水线、核心组件深度解析、常见架构模式以及关键权衡。

1. RAG系统总体架构

下图展示了一个生产级RAG系统的完整架构:

┌─────────────────────────────────────────────────────────────────────┐
│                         RAG 系统总体架构                              │
├─────────────────────────────────────────────────────────────────────┤
│                                                                      │
│  ┌──────────── 离线流水线(Indexing Pipeline)──────────────────┐    │
│  │                                                               │    │
│  │  原始文档 ──► 文档解析 ──► 文本分块 ──► 向量化 ──► 索引存储     │    │
│  │  (PDF/HTML/ │           │           │         │              │    │
│  │   Markdown) │           │           │         │              │    │
│  │             ▼           ▼           ▼         ▼              │    │
│  │       文档加载器    文本分割器   Embedding  向量数据库        │    │
│  │                                  模型      + 元数据          │    │
│  └───────────────────────────────────────────────────────────────┘    │
│                                                                      │
│  ┌──────────── 在线流水线(Query Pipeline)────────────────────┐    │
│  │                                                               │    │
│  │  用户查询 ──► 查询理解 ──► 向量检索 ──► 重排序 ──► 上下文构建    │    │
│  │      │          │            │          │          │         │    │
│  │      ▼          ▼            ▼          ▼          ▼         │    │
│  │  原始问题    查询改写/   相似度搜索   Reranker    Prompt      │    │
│  │              HyDE                     模型      组装        │    │
│  │                                                     │         │    │
│  │                                                     ▼         │    │
│  │                                               LLM 生成 ──► 最终回答  │
│  └───────────────────────────────────────────────────────────────┘    │
│                                                                      │
└─────────────────────────────────────────────────────────────────────┘

整个系统分为两条核心流水线:离线流水线(Indexing Pipeline)负责将知识文档处理为可检索的索引;在线流水线(Query Pipeline)负责将用户查询转化为最终答案。

2. 离线流水线:知识索引

离线流水线的任务是将原始文档转化为结构化的可检索索引。这是RAG系统的基础设施,通常在系统上线前一次性完成,并在知识更新时增量执行。

2.1 文档加载与解析

from llama_index.core import SimpleDirectoryReader
from langchain.document_loaders import PyPDFLoader, TextLoader

# LlamaIndex 方式
documents = SimpleDirectoryReader("./data").load_data()

# LangChain 方式
loader = PyPDFLoader("document.pdf")
docs = loader.load()

不同的文档类型对应不同的解析策略:

文档类型推荐加载器注意事项
PDFPyPDFLoader / PyMuPDFLoader注意表格和图片的提取
HTMLSeleniumURLLoader / BeautifulSoup需要清理HTML标签和脚本
MarkdownMarkdownTextSplitter保留层级结构信息
WordDocx2txtLoader处理图片和表格需额外工具
代码TextLoader注意语法结构和注释的处理

2.2 文本分块(Chunking)

分块是影响检索质量的关键步骤。分块太小会丢失语义,太大则引入噪声。

from langchain.text_splitter import RecursiveCharacterTextSplitter

text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=512,          # 每块字符数
    chunk_overlap=128,       # 块间重叠字符数
    separators=["\n\n", "\n", "", ". ", " ", ""],
    length_function=len,
)

chunks = text_splitter.split_documents(docs)

分块策略对比:

策略粒度适用场景优点缺点
固定大小统一通用场景实现简单可能切断语义单元
递归分割自适应大多数场景保持段落完整性块大小不均
语义分割语义块长文档语义完整依赖模型推理
文档结构章节/段落结构化文档保留原文结构对非结构化文档无效

2.3 向量化与索引

from langchain_openai import OpenAIEmbeddings
from langchain.vectorstores import Chroma

# 初始化嵌入模型
embeddings = OpenAIEmbeddings(
    model="text-embedding-3-small",  # 1536维
)

# 创建向量索引并持久化
vectorstore = Chroma.from_documents(
    documents=chunks,
    embedding=embeddings,
    persist_directory="./chroma_db",
    collection_metadata={"hnsw:space": "cosine"},  # 使用余弦距离
)

# 保存元数据索引(用于过滤)
chunk_metadatas = [
    {"source": doc.metadata.get("source"), 
     "page": doc.metadata.get("page"),
     "section": doc.metadata.get("section")}
    for doc in chunks
]

向量索引的核心选型要点:

  • 向量维度:高维(1536/3072)精度高但计算慢,低维(384/768)速度快但可能损失精度
  • 索引算法:HNSW(准确率高但内存大)、IVF(速度快但不保证精确)、Flat(暴力搜索,小数据集适用)
  • 距离度量:余弦相似度(最常用)、点积(适用于归一化向量)、L2距离

3. 在线流水线:查询到答案

在线流水线是RAG系统的运行时路径,每次用户查询都会流经这条链路。

3.1 查询理解与改写

原始用户问题往往不适合直接用于向量检索。查询理解模块负责将用户输入转化为更有效的检索查询。

from langchain.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)

# 查询改写 Prompt
query_rewrite_prompt = ChatPromptTemplate.from_template("""
你是一个查询改写专家。将用户的问题改写成3个独立的关键词查询,
每个查询针对不同的语义维度,用于向量数据库检索。

原始问题:{question}

请用逗号分隔输出3个改写后的查询:
""")

def rewrite_query(question: str) -> list[str]:
    response = llm.invoke(
        query_rewrite_prompt.format(question=question)
    )
    queries = response.content.strip().split(",")
    return [q.strip() for q in queries[:3]]

常见查询理解策略:

  1. 查询改写 - 将口语化问题转为适合检索的关键词形式
  2. HyDE(假设文档嵌入) - 先生成一个假设回答,再用该回答进行检索
  3. 多查询扩展 - 从不同角度生成多个子查询
  4. 查询分解 - 将复杂问题拆解为多个简单子问题

3.2 向量检索

from langchain.retrievers import EnsembleRetriever
from langchain.retrievers import BM25Retriever

# 向量检索器
vector_retriever = vectorstore.as_retriever(
    search_type="similarity",      # 或 "mmr" (最大边际相关性)
    search_kwargs={"k": 10},       # 返回 top-k 结果
)

# BM25 关键词检索器(混合检索用)
bm25_retriever = BM25Retriever.from_documents(
    documents=chunks, k=5
)

# 集成检索器(混合检索)
ensemble_retriever = EnsembleRetriever(
    retrievers=[bm25_retriever, vector_retriever],
    weights=[0.3, 0.7],  # 可调节权重
)

检索方式对比:

方式原理适用场景召回率精度
纯向量检索语义相似度语义匹配
关键词检索BM25/稀疏向量精确匹配
混合检索向量+关键词融合通用最优最高
结构化检索元数据过滤+向量有明确过滤条件依赖过滤条件

3.3 重排序(Reranking)

检索出的 top-k 结果中,真实相关的文档可能排在后面。重排序模块使用更精确的模型对结果重新打分。

from llama_index.core.postprocessor import SentenceTransformerRerank
from langchain.retrievers import ContextualCompressionRetriever
from langchain.retrievers.document_compressors import LLMChainFilter

# LlamaIndex 重排序
reranker = SentenceTransformerRerank(
    model="BAAI/bge-reranker-v2-m3",
    top_n=3,  # 只保留前3个最相关的
)

# LangChain 上下文压缩(使用 LLM 过滤)
compressor = LLMChainFilter.from_llm(llm)
compression_retriever = ContextualCompressionRetriever(
    base_compressor=compressor,
    base_retriever=vector_retriever,
)

主流 Reranker 模型对比:

模型参数量语言特点
BAAI/bge-reranker-v2-m3567M多语言性价比优秀
Cohere RerankAPI多语言托管的专有服务
cross-encoder/ms-marco-MiniLM-L-6-v222M英文推理速度快
jina-reranker-v2278M多语言支持长上下文

3.4 LLM 生成

将检索到的相关文档与用户查询组装成提示词,送入 LLM 生成最终答案。

from langchain.prompts import ChatPromptTemplate
from langchain.chains import RetrievalQA

# 上下文组装提示模板
qa_prompt = ChatPromptTemplate.from_messages([
    ("system", """你是一个基于知识的问答助手。请严格根据提供的上下文信息回答问题。
如果上下文中没有相关信息,请明确说"找不到相关信息"。
请在回答末尾标注引用的文档来源。

上下文:
{context}"""),
    ("human", "{question}"),
])

# 构建完整的 RAG 问答链
qa_chain = RetrievalQA.from_chain_type(
    llm=ChatOpenAI(model="gpt-4o", temperature=0.1),
    chain_type="stuff",  # 将所有文档一次性放入上下文
    retriever=ensemble_retriever,
    chain_type_kwargs={
        "prompt": qa_prompt,
        "document_separator": "\n---\n",
    },
    return_source_documents=True,
)

# 执行查询
result = qa_chain.invoke({"query": "RAG系统的核心组件有哪些?"})
print(result["result"])

chain_type 选择:

类型原理适用限制
stuff所有文档放入一个 prompt文档少且小受限于上下文窗口
map_reduce分别处理再汇总文档多多次 LLM 调用
refine逐个文档迭代优化信息逐步累积串行、速度慢
map_rerank分别处理并评分需要选最佳需要评分机制

4. 核心组件深度解析

4.1 Retriever(检索器)

Retriever 是 RAG 的信息入口,其质量直接决定系统上限。核心设计维度包括:

  • 召回策略:向量检索 vs 关键词检索 vs 混合检索
  • 索引结构:HNSW、IVF、Flat 的选择影响性能
  • 分块粒度:决定检索到的是段落还是句子
  • 元数据过滤:通过时间、来源、类别等字段精确定位
# 高级检索器配置示例
retriever = vectorstore.as_retriever(
    search_type="mmr",               # 最大边际相关性,兼顾相关性和多样性
    search_kwargs={
        "k": 10,                     # 检索数量
        "fetch_k": 30,               # MMR 候选池大小
        "lambda_mult": 0.25,         # 多样性权重(0=高多样,1=高相关)
        "filter": {"date": {"$gte": "2024-01-01"}},  # 时间过滤
    },
)

4.2 Generator(生成器)

Generator 负责基于检索结果生成最终答案。关键考量包括:

  • 模型选择:GPT-4o、Claude 3.5、Llama 3 等的基础能力
  • 上下文窗口:窗口大小决定能携带多少检索结果
  • 温度参数:事实性问答设 0-0.3,创意任务可适当调高
  • 功能调用:是否支持结构化输出、引用标注
# 结构化输出示例
from pydantic import BaseModel
from langchain.output_parsers import PydanticOutputParser

class AnswerWithCitations(BaseModel):
    answer: str
    citations: list[str]
    confidence: float

parser = PydanticOutputParser(pydantic_object=AnswerWithCitations)

structured_prompt = ChatPromptTemplate.from_messages([
    ("system", "根据上下文回答问题。\\n{format_instructions}"),
    ("human", "问题:{question}\\n上下文:{context}"),
]).partial(format_instructions=parser.get_format_instructions())

4.3 Reranker(重排序器)

Reranker 是检索质量的关键保障,它在粗排之后对结果进行精排。

方面双编码器(Bi-encoder)交叉编码器(Cross-encoder)
计算方式查询和文档分别编码查询和文档一起编码
推理速度快(可预计算向量)慢(需要逐对计算)
精度中等高(全交互注意力)
使用位置向量检索(粗排)重排序(精排)
典型模型text-embedding-3bge-reranker-v2

重排序的典型流程:

  1. 粗排阶段:向量检索返回 top-20 到 top-50 结果
  2. 精排阶段:Reranker 在 top-3 到 top-5 结果上重排序
  3. 截断阶段:只保留精排后的 top-3 结果送入 LLM

5. 常见架构模式

5.1 Naive RAG(基础RAG)

最简单的实现方式,适用于入门和小型项目。

用户查询 → 向量检索 → LLM生成 → 最终回答
# Naive RAG - 最小实现
qa_chain = RetrievalQA.from_chain_type(
    llm=llm,
    chain_type="stuff",
    retriever=vectorstore.as_retriever(),
)

优点:实现简单、快速验证 缺点:无查询优化、无重排序、检索质量依赖单一策略

5.2 Advanced RAG(进阶RAG)

在基础之上增加预处理和后处理环节,提升检索质量。

用户查询 → 查询改写 → 混合检索 → 重排序 → LLM生成 → 引用标注 → 答案

            HyDE / 多查询

进阶优化手段:

  • 预检索优化:查询改写、HyDE、查询分解
  • 检索增强:混合检索(向量+BM25)、多路召回、元数据过滤
  • 后检索优化:重排序、上下文压缩、动态截断

5.3 Modular RAG(模块化RAG)

将 RAG 拆分为可插拔模块,灵活组合不同策略。

from typing import Protocol

class Retriever(Protocol):
    def retrieve(self, query: str, top_k: int) -> list[Document]:
        ...

class QueryProcessor(Protocol):
    def process(self, query: str) -> str:
        ...

class Reranker(Protocol):
    def rerank(self, query: str, docs: list[Document]) -> list[Document]:
        ...

class Generator(Protocol):
    def generate(self, query: str, context: list[Document]) -> str:
        ...

# 模块化组装
class ModularRAGPipeline:
    def __init__(self, 
                 query_processor: QueryProcessor,
                 retriever: Retriever,
                 reranker: Reranker,
                 generator: Generator):
        self.query_processor = query_processor
        self.retriever = retriever
        self.reranker = reranker
        self.generator = generator
    
    def run(self, query: str) -> str:
        processed = self.query_processor.process(query)
        docs = self.retriever.retrieve(processed, top_k=10)
        reranked = self.reranker.rerank(query, docs)
        return self.generator.generate(query, reranked)

架构模式对比:

维度Naive RAGAdvanced RAGModular RAG
组件数量35-75+(可扩展)
检索质量中-高
延迟中-高
可定制性
维护成本中-高
适用场景demo/原型生产环境复杂生产系统

6. 关键权衡

设计 RAG 系统时,需要在多个维度间权衡。

6.1 检索质量 vs 延迟

优化方向质量提升延迟影响方案
更多检索结果↑↑k 从 5 增加到 20
重排序↑↑增加 Reranker 调用
混合检索↑↑两路检索 + 融合
缓存命中↓↓复用相似查询结果

6.2 上下文窗口 vs 成本

策略上下文占用Token 成本信息完整性
少量文档可能缺失关键信息
大量文档可能引入噪声
自适应窗口动态平衡
分层摘要中(+摘要成本)兼顾全局

6.3 精确度 vs 多样性

MMR(最大边际相关性)参数调优:
  lambda_mult = 0 → 完全多样性(结果覆盖面广)
  lambda_mult = 1 → 完全精确度(结果高度相关)
  推荐值:0.25-0.5 → 在相关性和多样性间取得平衡

6.4 通用建议

  • 数据量 < 1000 文档:Naive RAG + 单路向量检索足够
  • 数据量 1000-100000 文档:Advanced RAG + 混合检索 + 重排序
  • 数据量 > 100000 文档:Modular RAG + 分层索引 + 多级检索
  • 需要高实时性:减少检索和重排序步骤,使用缓存
  • 需要高精度:增加查询改写、多路召回、重排序和结构化输出

7. 总结

RAG 架构从宏观上可以理解为一条从”知识索引”到”知识检索”再到”知识生成”的完整链路。本文所介绍的核心组件和架构模式构成了生产级 RAG 系统的基础框架:

环节核心组件关键决策常见陷阱
索引文档解析器、文本分割器、Embedding 模型、向量数据库分块策略、嵌入模型选型分块不合理、忽略元数据
检索Retriever、Reranker、查询处理器检索策略、重排序方案检索深度不足、未做过滤
生成LLM、Prompt 模板、输出解析器模型选择、上下文组装prompt 太简单、无引用
编排Pipeline / Chain / Graph架构模式选择忽略容错和监控

推荐后续阅读: