RAG(Retrieval-Augmented Generation)检索增强生成已成为大模型应用落地中最核心的架构模式。通过将外部知识库与大语言模型结合,RAG有效解决了模型知识时效性不足、领域知识缺失以及幻觉问题。在企业级RAG系统搭建中,向量数据库选型和文档切分策略直接决定了检索质量和最终生成效果。本文围绕这两个关键环节展开实战配置,给出完整的代码示例和优化方案。
RAG架构基本原理与工作流程
RAG系统的核心思路是”先检索、后生成”。用户提问后,系统先从知识库中检索相关文档片段,再将检索结果作为上下文拼接到Prompt中,交由大语言模型生成回答。完整工作流包含五个阶段:文档加载、文档切分、向量化存储、语义检索、答案生成。
from langchain_community.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings
from langchain_community.vectorstores import Milvus
from langchain_openai import ChatOpenAI
from langchain.chains import RetrievalQA
# 1. 文档加载
loader = PyPDFLoader("knowledge_base.pdf")
documents = loader.load()
# 2. 文档切分
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=500,
chunk_overlap=50,
separators=["\n\n", "\n", "。", ",", " "]
)
chunks = text_splitter.split_documents(documents)
# 3. 向量化存储
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
vector_store = Milvus.from_documents(
chunks,
embeddings,
connection_args={"host": "127.0.0.1", "port": "19530"},
collection_name="rag_knowledge_base"
)
# 4. 语义检索 + 5. 答案生成
llm = ChatOpenAI(model="gpt-4o", temperature=0)
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff",
retriever=vector_store.as_retriever(search_kwargs={"k": 5})
)
result = qa_chain.invoke({"query": "什么是RAG架构?"})
print(result["result"])
向量数据库选型对比:Milvus与Qdrant与Chroma
向量数据库是RAG系统的存储核心,选型时需要综合考虑性能、扩展性、易用性和生态成熟度。三款主流方案的对比如下:
Milvus:专为大规模向量检索设计,支持百亿级向量存储,提供IVF、HNSW等多种索引类型。分布式架构支持水平扩展,适合企业级生产环境。缺点是部署较重,依赖etcd、MinIO等组件。
Qdrant:用Rust编写,性能出色且资源占用低。支持payload过滤,API设计简洁。单机模式即可满足中小规模场景,也支持分布式部署。适合快速原型开发和中等规模生产使用。
Chroma:轻量级方案,纯Python调用,适合开发测试阶段。数据量超过百万级后性能下降明显,不适合大规模生产环境。
选型建议:开发和原型阶段用Chroma快速验证,中小规模生产环境用Qdrant,大规模企业级部署用Milvus。
文档切分策略对检索质量的影响
文档切分是RAG系统中对最终效果影响最大的环节。切分粒度过粗,检索到的片段包含过多无关信息,干扰模型生成;切分粒度过细,语义完整性被破坏,检索结果缺乏上下文。
RecursiveCharacterTextSplitter是LangChain提供的递归切分器,按 separators 列表依次尝试分割,在保持语义完整性的同时控制片段大小。关键参数配置:
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=500, # 每个片段最大字符数
chunk_overlap=50, # 相邻片段重叠字符数,保证上下文连贯
separators=[
"\n\n", # 优先按段落分割
"\n", # 其次按行分割
"。", # 中文句号
"!", # 感叹号
"?", # 问号
";", # 分号
" " # 空格兜底
],
length_function=len
)
chunk_overlap的设置不可忽视。设为0会导致切分边界处的语义丢失,建议设置为chunk_size的10%左右。对于技术文档,按标题层级切分效果更好:
from langchain.text_splitter import MarkdownHeaderTextSplitter
headers_to_split_on = [
("#", "Header 1"),
("##", "Header 2"),
("###", "Header 3"),
]
md_splitter = MarkdownHeaderTextSplitter(headers_to_split_on=headers_to_split_on)
md_chunks = md_splitter.split_text(markdown_text)
# 再对每个章节内容做字符级切分
final_chunks = text_splitter.split_documents(md_chunks)
Embedding模型选择与向量化流程
Embedding模型决定了文本向量化的质量,直接影响检索召回率。中文场景下,bge-large-zh-v1.5和m3e-base是两个表现优秀的开源模型。使用HuggingFace加载本地Embedding模型:
from langchain_huggingface import HuggingFaceEmbeddings
embeddings = HuggingFaceEmbeddings(
model_name="BAAI/bge-large-zh-v1.5",
model_kwargs={"device": "cuda"},
encode_kwargs={"normalize_embeddings": True}
)
normalize_embeddings设为True会对向量做L2归一化,使得内积运算等价于余弦相似度,可以提高检索精度。对于bge系列模型,查询时需要添加特定前缀以获得最佳效果:
query = "Represent this sentence for searching relevant passages: " + user_question
RAG优化进阶:重排序与混合检索
初始检索阶段使用向量相似度快速召回Top-K候选文档后,通过重排序模型对候选结果做精排,可以显著提升最终检索质量。Cohere Rerank和BGE-Reranker是常用的重排序模型:
from langchain.retrievers import ContextualCompressionRetriever
from langchain_cohere import CohereRerank
compressor = CohereRerank(top_n=3)
compression_retriever = ContextualCompressionRetriever(
base_compressor=compressor,
base_retriever=vector_store.as_retriever(search_kwargs={"k": 20})
)
# 先向量检索召回20条,再重排序取Top3
docs = compression_retriever.invoke(user_question)
混合检索(Hybrid Search)结合了向量语义检索和BM25关键词检索的优势。向量检索擅长语义匹配,但对专有名词、型号等精确匹配场景表现不佳;BM25正好互补。两者结果通过RRF(Reciprocal Rank Fusion)算法融合:
from langchain.retrievers import EnsembleRetriever
from langchain_community.retrievers import BM25Retriever
bm25_retriever = BM25Retriever.from_documents(chunks)
bm25_retriever.k = 10
vector_retriever = vector_store.as_retriever(search_kwargs={"k": 10})
ensemble_retriever = EnsembleRetriever(
retrievers=[bm25_retriever, vector_retriever],
weights=[0.3, 0.7] # BM25权重0.3, 向量检索权重0.7
)
docs = ensemble_retriever.invoke(user_question)
权重分配需要根据实际数据特点调整。通用知识类内容向量检索权重可以更高,术语密集型场景需要提高BM25权重。线上环境建议对不同权重组合做A/B测试,根据用户反馈和人工标注数据选择最优配置。
RAG系统的优化是一个持续迭代的过程。从文档切分粒度、Embedding模型选择、检索策略到重排序配置,每个环节都对最终效果有可观影响。建议建立标准化的评测数据集,对每个环节的改动做量化评估,避免凭感觉调参。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/rag-jian-suo-zeng-qiang-sheng-cheng-jia-gou-shi-zhan-xiang/