RAG检索增强生成架构通过将外部知识库与大语言模型结合,有效缓解模型幻觉问题并提升回答准确性。RAG架构设计的核心在于检索质量,而检索质量又取决于文本分块策略、Embedding模型选型、向量数据库性能以及重排序机制等多个环节的协同优化。
RAG核心组件与检索增强生成流程拆解
一套完整的RAG系统由文档处理、向量存储、检索召回、重排序、生成回答五个核心模块构成。文档处理阶段负责将原始数据(PDF、HTML、Markdown等)解析为纯文本,再通过分块策略切分为语义连贯的片段。向量存储阶段使用Embedding模型将文本块编码为高维向量,写入向量数据库。检索阶段接收用户查询,生成查询向量后在数据库中进行近似最近邻搜索,召回Top-K候选片段。重排序阶段对候选片段进行二次打分,筛选出与查询最相关的内容。生成阶段将筛选后的上下文与用户问题拼接,送入大语言模型生成最终回答。
整个流程的关键瓶颈通常出现在检索召回环节。如果召回的片段与问题语义不匹配,即使大模型能力再强,也无法生成准确回答。因此,RAG架构设计的重心应放在检索链路的优化上。
文本分块策略与语义完整性保障
文本分块直接影响检索粒度。分块过大,单个向量承载过多语义信息,导致检索精度下降;分块过小,上下文割裂,语义不完整。常见的分块策略包括固定长度分块、按句子分块、按段落分块以及基于语义的分块。
固定长度分块实现简单,但容易截断句子。按句子分块保留语义完整性,但块长度差异较大。实践中常采用滑动窗口分块,设定目标长度和重叠区域,兼顾语义连续性与检索精度。以下是基于LangChain的滑动窗口分块示例:
from langchain.text_splitter import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=512,
chunk_overlap=64,
separators=["\n\n", "\n", "。", "!", "?", ";", " ", ""],
length_function=len
)
chunks = text_splitter.split_text(document_text)
print(f"分块数量: {len(chunks)}")
RecursiveCharacterTextSplitter按分隔符优先级递归切分,优先在段落边界处断开,其次在句子边界处断开,尽可能保持语义完整性。chunk_overlap参数设置重叠区域,确保跨块信息不丢失。
Embedding模型选型对比与中文场景适配
Embedding模型决定了文本向量化的语义表达能力。主流模型包括OpenAI text-embedding-3系列、BGE系列、GTE系列。OpenAI模型在英文场景表现优异,但API调用存在网络延迟和成本问题。BGE系列由智源研究院开源,在MTEB中文榜单表现领先,支持本地部署。GTE系列由达摩院推出,同样支持中文场景。
选型时需综合考虑语言场景、维度大小、推理速度和部署成本。对于中文为主的RAG系统,BGE-large-zh-v1.5是性价比较高的选择,1024维向量在精度和存储之间取得较好平衡。以下是通过HuggingFace加载BGE模型生成向量的代码:
from FlagEmbedding import FlagModel
model = FlagModel('BAAI/bge-large-zh-v1.5',
query_instruction_for_retrieval="为这个句子生成表示用于检索相关文章:")
# 生成文档向量
doc_embeddings = model.encode_documents(documents)
# 生成查询向量
query_embedding = model.encode_queries(["RAG架构如何优化检索精度"])
print(f"向量维度: {query_embedding.shape}")
向量数据库选型与性能对比
向量数据库是RAG系统的存储底座,选型需关注索引算法、召回率、吞吐量、扩展性和运维成本。Milvus采用HNSW和IVF索引,支持十亿级向量规模,适合大型生产环境。Weaviate内置多模态支持,提供模块化的向量化能力。Qdrant用Rust编写,内存占用低,单机性能突出。Chroma轻量级,适合原型验证和小规模应用。
在大规模场景下,Milvus的分布式架构和分片能力具备明显优势。以下对比四款数据库的关键指标:
# 使用Qdrant快速搭建向量检索
from qdrant_client import QdrantClient
from qdrant_client.models import Distance, VectorParams, PointStruct
client = QdrantClient(host="localhost", port=6333)
client.create_collection(
collection_name="rag_docs",
vectors_config=VectorParams(size=1024, distance=Distance.COSINE)
)
# 插入向量
client.upsert(
collection_name="rag_docs",
points=[
PointStruct(id=i, vector=emb, payload={"text": chunk})
for i, (emb, chunk) in enumerate(zip(doc_embeddings, chunks))
]
)
# 检索Top-K
results = client.search(
collection_name="rag_docs",
query_vector=query_embedding[0].tolist(),
limit=5
)
BM25混合检索与向量语义检索融合
纯向量检索擅长捕捉语义相似性,但对精确关键词匹配场景表现不足。BM25基于词频统计,擅长精确匹配,两者融合可显著提升召回率。混合检索的核心思想是并行执行BM25检索和向量检索,对两路结果进行分数融合。
常用的融合算法包括RRF(Reciprocal Rank Fusion)和加权融合。RRF无需归一化分数,实现简单且效果稳定,公式为 score = sum(1/(k + rank_i)),其中k通常取60。以下是基于RankBM25和向量检索的RRF融合示例:
from rank_bm25 import BM25Okapi
import numpy as np
# BM25检索
tokenized_corpus = [doc.split() for doc in chunks]
bm25 = BM25Okapi(tokenized_corpus)
bm25_scores = bm25.get_scores(query.split())
# RRF融合
def rrf_fusion(vector_ranks, bm25_ranks, k=60):
fused_scores = {}
for rank, doc_id in enumerate(vector_ranks):
fused_scores[doc_id] = fused_scores.get(doc_id, 0) + 1 / (k + rank + 1)
for rank, doc_id in enumerate(bm25_ranks):
fused_scores[doc_id] = fused_scores.get(doc_id, 0) + 1 / (k + rank + 1)
return sorted(fused_scores, key=fused_scores.get, reverse=True)
final_rank = rrf_fusion(vector_result_ids, bm25_result_ids)
Reranker重排序模型与精度提升
召回阶段为了保证覆盖率,通常设置较大的Top-K值(如50-100),其中包含大量相关性较低的噪声片段。Reranker对候选片段与查询进行交叉编码打分,筛选出最相关的Top-N片段送入生成阶段。与Embedding模型的双塔结构不同,Reranker采用交叉编码器,将查询和文档拼接后输入Transformer,捕捉细粒度交互特征,精度更高但推理速度较慢。
BGE-reranker-large是中文场景常用模型,以下是通过CrossEncoder加载Reranker的示例:
from sentence_transformers import CrossEncoder
reranker = CrossEncoder('BAAI/bge-reranker-large')
# 对候选片段重排序
pairs = [[query, doc] for doc in candidate_docs]
scores = reranker.predict(pairs)
# 按分数排序取Top-5
ranked_indices = np.argsort(scores)[::-1][:5]
final_context = [candidate_docs[i] for i in ranked_indices]
RAGAS评估指标体系与持续优化
RAG系统上线后需要建立量化评估体系以持续优化。RAGAS是专门针对RAG的评估框架,提供四个核心指标:Faithfulness衡量回答是否忠实于检索上下文,Answer Relevance衡量回答与问题的相关性,Context Precision衡量检索上下文的精确度,Context Recall衡量检索上下文对标准答案的覆盖率。
Faithfulness是最关键的指标,值越低说明模型产生了更多幻觉内容。Context Precision低表明检索阶段引入了过多噪声,需要优化分块策略或重排序模型。Context Recall低表明召回不足,需要调整Embedding模型或增加Top-K值。以下代码展示如何使用RAGAS进行评估:
from ragas import evaluate
from ragas.metrics import (
faithfulness, answer_relevancy,
context_precision, context_recall
)
from datasets import Dataset
eval_data = Dataset.from_dict({
"question": questions,
"answer": generated_answers,
"contexts": retrieved_contexts,
"ground_truth": ground_truths
})
results = evaluate(
eval_data,
metrics=[faithfulness, answer_relevancy,
context_precision, context_recall]
)
print(results)
# {'faithfulness': 0.85, 'answer_relevancy': 0.91,
# 'context_precision': 0.78, 'context_recall': 0.82}
评估结果应作为迭代优化的基线,每次调整分块参数、更换Embedding模型或修改检索策略后,重新运行评估并对比指标变化,确保优化方向正确。对于生产环境,建议建立评估数据集并纳入CI流程,在模型或参数变更时自动触发评估。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/rag-jian-suo-zeng-qiang-sheng-cheng-jia-gou-she-ji-yu-xiang/