什么是RAG(检索增强生成)?
RAG(Retrieval-Augmented Generation,检索增强生成)是2023年以来大语言模型应用中最重要的一项技术架构。它通过将外部知识检索与语言模型生成能力相结合,有效解决了大模型”幻觉”问题、知识时效性问题以及私有知识无法接入等核心痛点。
简单来说,RAG的工作流程分为三个阶段:检索(Retrieve)→ 增强(Augment)→ 生成(Generate)。当用户提出一个问题时,系统首先从知识库中检索出相关文档片段,然后将这些片段作为上下文信息与原始问题一起拼接到提示词中,最后交给大模型生成回答。这种方式让大模型在回答时有了”参考书”可查,而不是完全依赖自己的参数记忆。
与传统的微调(Fine-tuning)方案相比,RAG具有几个显著优势:无需重新训练模型即可引入新知识、知识更新只需修改向量数据库、部署成本低、可解释性强。正因为这些优势,RAG已经成为企业构建知识问答系统、智能客服、文档分析等应用的首选方案。

RAG核心技术组件详解
一个完整的RAG系统由多个核心组件构成,每个组件都有多种实现选择。下面我们来逐一解析。
1. 文档解析与分块(Chunking)
文档解析是RAG系统的第一道工序。原始文档可以是PDF、Word、HTML、Markdown等各种格式。常用的解析工具有:
- Unstructured.io:支持多种文档格式的解析,安装简单,社区活跃
- PyMuPDF(fitz):PDF解析速度最快的库之一
- LangChain文档加载器:提供了50+种文档加载器,开箱即用
- LlamaParse:专为RAG优化的文档解析服务,对表格和图片有很好的支持
文档分块是影响检索质量的关键因素。常见的分块策略包括:
| 策略名称 | 分块方式 | 适用场景 |
|---|---|---|
| 固定大小分块 | 按字符数/Token数切分 | 通用场景,实现简单 |
| 递归分块 | 按段落→句子→子句逐级切分 | Markdown、代码文档 |
| 语义分块 | 使用嵌入模型检测语义边界 | 高质量场景,计算成本较高 |
| Agent式分块 | LLM自主决定切分位置 | 极端复杂文档 |
在实践中,推荐使用递归分块+重叠窗口的组合策略。LangChain的 RecursiveCharacterTextSplitter 是最常用的实现,默认按 “\n\n” → “\n” → ” ” → “” 的层级进行切分,配合适当的chunk_size(通常500-1500字符)和chunk_overlap(10%-20%)参数。
2. 向量化与嵌入(Embedding)
将文本转化为向量是RAG系统的核心步骤。高质量的嵌入模型直接决定了检索的准确率。2024年以来,嵌入模型的发展集中在以下几个方向:
- BGE系列(BAAI):BGE-M3支持多语言、多粒度,是目前最广泛使用的开源嵌入模型
- E5系列(微软):在大规模文本匹配数据上训练,英文场景表现优异
- OpenAI Embeddings:text-embedding-3-small/large,API调用方便但需付费
- Jina Embeddings:支持长达8192 Token的输入,适合长文档
- 智源M3E:国产中文嵌入模型,中文场景性价比高
一个实用的嵌入函数示例:
from sentence_transformers import SentenceTransformer
import numpy as np
# 加载BGE中文嵌入模型
model = SentenceTransformer(BAAI/bge-large-zh-v1.5)
def get_embedding(text: str) -> list:
"""为输入文本生成向量嵌入"""
# BGE模型建议在查询前添加指令前缀
return model.encode(text, normalize_embeddings=True).tolist()
# 批量处理文档片段
chunks = ["文档第一段内容...", "文档第二段内容..."]
embeddings = model.encode(chunks, normalize_embeddings=True)
print(f"向量维度: {embeddings.shape[1]}") # 输出: 1024
3. 向量数据库
向量数据库负责存储和检索嵌入向量。市面上的向量数据库选择非常丰富:
| 数据库 | 部署方式 | 索引算法 | 适用规模 |
|---|---|---|---|
| Chroma | 嵌入式 | HNSW | 小规模 <100万 |
| FAISS | 嵌入式 | IVF+HNSW | 中规模 <1000万 |
| Milvus | 分布式 | IVF_FLAT/HNSW | 大规模 亿级 |
| Qdrant | 单机/分布式 | HNSW | 中大规模 |
| PGVector | PostgreSQL插件 | IVFFlat/HNSW | 中等规模 |
对于个人开发者和小团队,Chroma 是最友好的选择,它无需单独部署服务,可以嵌入到Python应用中直接使用。对于生产环境,Milvus 或 Qdrant 提供了更好的性能和可靠性。
完整RAG应用实战:搭建知识问答系统
接下来,我们从头搭建一个完整的RAG知识问答系统。这个系统将读取本地Markdown文档,构建向量索引,并基于用户提问检索相关文档生成回答。
环境准备
pip install langchain langchain-community chromadb sentence-transformers
pip install openai # 或其他LLM提供商的SDK
Step 1: 文档加载与分块
from langchain_community.document_loaders import DirectoryLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
# 加载文档目录中的所有Markdown文件
loader = DirectoryLoader(
"./knowledge_base/",
glob="**/*.md",
show_progress=True
)
docs = loader.load()
# 递归分块
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=1000,
chunk_overlap=200,
separators=["\n## ", "\n### ", "\n\n", "\n", " ", ""]
)
chunks = text_splitter.split_documents(docs)
print(f"文档分块完成,共 {len(chunks)} 个片段")
Step 2: 构建向量索引
from langchain_community.embeddings import HuggingFaceBgeEmbeddings
from langchain_community.vectorstores import Chroma
# 配置BGE嵌入模型
model_name = "BAAI/bge-small-zh-v1.5"
model_kwargs = {"device": "cpu"}
encode_kwargs = {"normalize_embeddings": True}
embeddings = HuggingFaceBgeEmbeddings(
model_name=model_name,
model_kwargs=model_kwargs,
encode_kwargs=encode_kwargs
)
# 创建Chroma向量存储(自动持久化到磁盘)
vectorstore = Chroma.from_documents(
documents=chunks,
embedding=embeddings,
persist_directory="./chroma_db"
)
vectorstore.persist()
print("向量索引构建完成!")
Step 3: 实现检索增强生成
from langchain.chains import RetrievalQA
from langchain_openai import ChatOpenAI
# 初始化LLM
llm = ChatOpenAI(
model="gpt-4o-mini", # 也可替换为DeepSeek、GLM等其他模型
temperature=0.1, # 低温度保证回答的确定性
)
# 创建检索QA链
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
retriever=vectorstore.as_retriever(
search_type="similarity",
search_kwargs={"k": 4} # 检索最相似的4个片段
),
return_source_documents=True,
verbose=True
)
# 测试问答
question = "什么是RAG架构?它的主要优势是什么?"
result = qa_chain.invoke({"query": question})
print(f"回答: {result[result]}\n")
print("参考来源:")
for doc in result["source_documents"]:
print(f" - {doc.metadata.get(source, unknown)}")

RAG系统的高级优化技巧
基础RAG可以工作,但在实际生产环境中往往面临各种挑战。下面介绍一些经过验证的优化策略。
1. 混合检索(Hybrid Search)
纯向量检索在某些场景下效果不佳,比如精确匹配(产品型号、日期)和稀有词检索。混合检索结合了向量相似度检索和关键词检索(BM25),兼顾语义理解和精确匹配。
from langchain.retrievers import BM25Retriever, EnsembleRetriever
# 关键词检索器
bm25_retriever = BM25Retriever.from_documents(chunks)
bm25_retriever.k = 4
# 向量检索器
vector_retriever = vectorstore.as_retriever(
search_kwargs={"k": 4}
)
# 集成检索器(加权合并结果)
ensemble_retriever = EnsembleRetriever(
retrievers=[bm25_retriever, vector_retriever],
weights=[0.3, 0.7] # BM25权重0.3,向量检索权重0.7
)
2. 重排序(Re-ranking)
初步检索返回的Top-K结果中,前面的结果不一定最相关。引入重排序模型对检索结果进行二次排序,可以显著提升最终答案质量。
from langchain.retrievers import ContextualCompressionRetriever
from langchain.retrievers.document_compressors import CrossEncoderReranker
from langchain_community.cross_encoders import HuggingFaceCrossEncoder
# 加载交叉编码器重排序模型
reranker = HuggingFaceCrossEncoder(model_name="BAAI/bge-reranker-v2-m3")
compressor = CrossEncoderReranker(
model=reranker,
top_n=3 # 保留最相关的3个片段
)
compression_retriever = ContextualCompressionRetriever(
base_compressor=compressor,
base_retriever=vectorstore.as_retriever(search_kwargs={"k": 10})
)
3. 查询重写(Query Rewriting)
用户原始查询往往不够精确,直接检索效果差。让LLM将用户问题重写为更适合检索的形式,可以大幅提升召回率。
from langchain.prompts import PromptTemplate
rewrite_prompt = PromptTemplate.from_template(
"""给定用户问题,生成3个不同角度的搜索查询,用于从技术文档库中检索相关信息。
每个查询应该覆盖问题的不同侧面。
用户问题: {question}
搜索查询(每行一个):"""
)
def rewrite_queries(question: str) -> list[str]:
"""将用户问题重写为多个搜索查询"""
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0.3)
result = llm.invoke(rewrite_prompt.format(question=question))
queries = [q.strip() for q in result.content.split("\n") if q.strip()]
return queries[:3]
4. RAPTOR:分层摘要检索
RAPTOR(Recursive Abstractive Processing for Tree-Organized Retrieval)是2024年提出的创新方案。它通过对文档片段进行递归摘要,构建一棵多层次的摘要树。检索时,系统同时搜索底层片段和高层摘要,从而兼顾细节和概览。
这种方法特别适合处理长篇文档或书籍——当用户问”整本书的核心思想是什么”这类宏观问题时,高层摘要能直接提供答案,而不需要拼接多个片段。
常见RAG评估指标与工具
构建RAG系统后,如何评估它的质量?行业常用的评估指标包括:
| 指标 | 说明 | 评估维度 |
|---|---|---|
| Hit Rate | 检索结果中包含正确答案的比例 | 检索质量 |
| MRR | 正确答案在检索结果中的平均排名倒数 | 检索排序 |
| Faithfulness | 生成回答是否忠实于检索到的上下文 | 生成质量 |
| Answer Relevancy | 回答是否与用户问题相关 | 生成质量 |
| Context Precision | 检索结果中相关文档的比例 | 检索质量 |
推荐使用 RAGAS(RAG Assessment)框架来自动化评估过程:
pip install ragas
from ragas import evaluate
from ragas.metrics import (
faithfulness,
answer_relevancy,
context_precision,
context_recall
)
# 准备评估数据集
dataset = {
"question": ["什么是RAG?", "向量数据库有哪些?"],
"answer": [result_1, result_2],
"contexts": [[context_1], [context_2]],
"ground_truth": ["预期答案1", "预期答案2"]
}
scores = evaluate(dataset, metrics=[
faithfulness,
answer_relevancy,
context_precision,
context_recall
])
print(scores)
RAG vs 微调:如何选择?
很多开发者在面对业务需求时经常困惑:该用RAG还是微调(Fine-tuning)?其实二者并非对立关系,而是互补的技术路线。
选择RAG的场景:
- 知识频繁更新:产品文档、新闻资讯、法律法规等
- 需要引用原文:合规审查、学术研究、医疗诊断
- 处理大量私有数据:企业内部知识库、客户聊天记录
- 资源有限:不需要昂贵的GPU进行训练
选择微调的场景:
- 需要模仿特定输出风格:客服话术、代码规范
- 改善模型基础能力:推理能力、数学计算
- 降低延迟:无需额外检索步骤
在实际工程中,RAG + 微调的组合方案往往能取得最佳效果。先用微调让模型掌握特定领域的输出格式和基本知识,再用RAG补充最新的私有信息。这套组合在2024年微软的《AI Transformation Guide》中被强烈推荐。
总结与学习资源
RAG作为大模型落地应用的关键技术,已经成为每位AI工程师必须掌握的技能。本文从基本原理出发,逐步深入到完整的代码实现和高级优化技巧,希望为读者提供一条清晰的学习路径。
如果你想进一步深入学习,以下免费资源非常值得推荐:
- LangChain官方教程:langchain.com/docs — 最完整的RAG框架文档
- LlamaIndex教程:docs.llamaindex.ai — 专注于RAG的高级框架
- DeepLearning.AI RAG专项课程:与LangChain/LlamaIndex作者合作,免费试听
- Pinecone RAG入门指南:免费电子书,含大量代码示例
- Hugging Face NLP课程:huggingface.co/learn — 涵盖嵌入模型和检索技术
记住,构建优秀的RAG系统没有银弹。关键在于理解业务场景、选择合适的组件组合,并通过持续评估迭代优化。希望本文能成为你RAG学习之旅的起点!
汤不热吧