RAG 检索增强生成完全指南

Maurice | 灵阙学院 2026-02-27

为什么需要 RAG

大语言模型有两个核心短板:知识截止日期幻觉。RAG(Retrieval-Augmented Generation)通过在推理时注入外部知识,让模型基于真实文档回答问题,从根本上缓解了这两个问题。

与微调相比,RAG 不需要重新训练模型,知识更新只需替换文档库,成本低且可审计。

核心架构:三阶段流水线

┌─────────────────────────────────────────────────────────┐
│                    RAG Pipeline                         │
├──────────┬──────────────┬──────────────┬───────────────┤
│  Ingest  │   Retrieve   │   Rerank     │   Generate    │
│          │              │              │               │
│ Document │ Query ->     │ Cross-encoder│ LLM +         │
│ Chunk    │ Embedding -> │ Score ->     │ Retrieved     │
│ Embed    │ Vector Search│ Top-K Filter │ Context ->    │
│ Store    │              │              │ Answer        │
└──────────┴──────────────┴──────────────┴───────────────┘

阶段一:文档索引(Indexing)

分块策略对比

策略 原理 优势 劣势 适用场景
固定长度 按字符/token 数切分 实现简单,速度快 可能切断语义 结构化日志、代码
递归分割 按段落/句子/字符逐级回退 尽量保留语义边界 需调参 通用文档(推荐默认)
语义分割 用 Embedding 相似度检测语义断点 语义完整性最佳 计算成本高 长文、论文、法律文书
文档结构 按 Markdown/HTML 标题层级切分 保留文档结构 依赖格式规范 技术文档、Wiki
滑动窗口 固定窗口+重叠区域 减少边界信息丢失 存储冗余 对召回率要求高的场景

分块代码示例

from langchain.text_splitter import RecursiveCharacterTextSplitter

# 递归分割 -- 推荐默认方案
splitter = RecursiveCharacterTextSplitter(
    chunk_size=512,
    chunk_overlap=64,
    separators=["\n\n", "\n", "。", ";", " ", ""],
    length_function=len,
)

chunks = splitter.split_documents(documents)
print(f"Total chunks: {len(chunks)}")
from langchain_experimental.text_splitter import SemanticChunker
from langchain_openai import OpenAIEmbeddings

# 语义分割 -- 适合长文精细检索
semantic_splitter = SemanticChunker(
    OpenAIEmbeddings(model="text-embedding-3-small"),
    breakpoint_threshold_type="percentile",
    breakpoint_threshold_amount=90,
)

semantic_chunks = semantic_splitter.split_documents(documents)

Embedding 模型对比

模型 维度 MTEB 均分 中文能力 价格 部署方式
OpenAI text-embedding-3-large 3072 64.6 良好 $0.13/1M tokens API
OpenAI text-embedding-3-small 1536 62.3 良好 $0.02/1M tokens API
Cohere embed-v4 1024 66.3 良好 $0.10/1M tokens API
BGE-M3 (BAAI) 1024 65.0 优秀 免费 本地/API
Jina-embeddings-v3 1024 65.5 优秀 $0.02/1M tokens API/本地
GTE-Qwen2 (阿里) 1536 64.8 优秀 免费 本地

选型建议:中文场景优先 BGE-M3 或 Jina-v3;英文通用场景 OpenAI text-embedding-3-small 性价比最高;对精度要求极高用 Cohere embed-v4。

阶段二:检索(Retrieval)

向量检索 + 关键词混合

单纯向量检索在精确匹配(产品编号、人名、专有名词)上表现不佳。混合检索(Hybrid Search)结合 BM25 关键词匹配与向量语义匹配,是生产环境的推荐方案。

from langchain_community.retrievers import BM25Retriever
from langchain.retrievers import EnsembleRetriever
from langchain_qdrant import QdrantVectorStore

# 向量检索器
vector_retriever = QdrantVectorStore.from_documents(
    chunks, embedding=embeddings, collection_name="docs"
).as_retriever(search_kwargs={"k": 20})

# BM25 关键词检索器
bm25_retriever = BM25Retriever.from_documents(chunks, k=20)

# 混合检索 -- RRF 融合
hybrid_retriever = EnsembleRetriever(
    retrievers=[bm25_retriever, vector_retriever],
    weights=[0.4, 0.6],  # 语义权重略高
)

results = hybrid_retriever.invoke("什么是增值税留抵退税政策?")

阶段三:重排序(Reranking)

初次检索返回 Top-20,用 Cross-Encoder 精排后取 Top-5 送入 LLM。这一步对最终回答质量影响巨大。

from langchain.retrievers import ContextualCompressionRetriever
from langchain_cohere import CohereRerank

reranker = CohereRerank(model="rerank-v3.5", top_n=5)

compression_retriever = ContextualCompressionRetriever(
    base_compressor=reranker,
    base_retriever=hybrid_retriever,
)

reranked = compression_retriever.invoke("留抵退税的申请条件")

阶段四:生成(Generation)

from langchain_openai import ChatOpenAI
from langchain.chains import RetrievalQA
from langchain.prompts import PromptTemplate

prompt = PromptTemplate.from_template("""
你是一位税务合规专家。请严格基于以下检索到的上下文回答问题。
如果上下文中没有相关信息,明确说明"根据现有资料无法回答"。

上下文:
{context}

问题:{question}

回答(附引用来源):
""")

qa_chain = RetrievalQA.from_chain_type(
    llm=ChatOpenAI(model="gpt-4o", temperature=0),
    retriever=compression_retriever,
    chain_type_kwargs={"prompt": prompt},
    return_source_documents=True,
)

result = qa_chain.invoke({"query": "小规模纳税人的增值税免征额是多少?"})
print(result["result"])

评估指标

指标 定义 计算方式 目标值
Faithfulness 回答是否忠于检索文档 LLM-as-Judge 逐句验证 > 0.85
Answer Relevancy 回答与问题的相关性 反向生成问题再比较 > 0.80
Context Precision 相关文档排名是否靠前 加权精确率 > 0.75
Context Recall 是否召回了所有相关文档 标注集对比 > 0.70
from ragas import evaluate
from ragas.metrics import faithfulness, answer_relevancy, context_precision

score = evaluate(
    dataset=eval_dataset,
    metrics=[faithfulness, answer_relevancy, context_precision],
)
print(score.to_pandas())

进阶模式

┌──────────────────────────────────────────────────────┐
│              Advanced RAG Patterns                   │
├──────────────────────────────────────────────────────┤
│                                                      │
│  Naive RAG ──→ Advanced RAG ──→ Modular RAG         │
│                                                      │
│  Query Rewriting    HyDE           Graph RAG         │
│  Step-back Prompt   Self-RAG       Agentic RAG      │
│  Multi-query        CRAG           Adaptive RAG     │
│                                                      │
└──────────────────────────────────────────────────────┘
  • Query Rewriting:用 LLM 改写用户问题,消除歧义,提升检索命中率
  • HyDE:先让 LLM 生成假设性回答,再用该回答做检索(适合开放式问题)
  • Self-RAG:模型自行判断是否需要检索、检索结果是否相关、回答是否有依据
  • Graph RAG:将文档构建为知识图谱,检索时同时利用图结构关系
  • Agentic RAG:检索器作为 Agent 的工具之一,Agent 自主决定何时检索、检索什么

生产部署清单

  • 分块参数已根据文档类型调优(chunk_size / overlap)
  • 混合检索已启用(向量 + BM25)
  • Reranker 已部署(Cohere/BGE-Reranker)
  • 评估流水线已接入(RAGAS / 自定义评测集)
  • 文档更新管道已自动化(增量索引)
  • 引用溯源已实现(返回 source_documents + 页码/段落)
  • 安全过滤已部署(PII 脱敏、权限隔离)

Maurice | maurice_wen@proton.me