RAG检索增强生成架构设计与向量数据库选型实战

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/

(0)
小编小编
上一篇 6小时前
下一篇 5小时前

相关推荐