RAG(检索增强生成)通过将外部知识库与大语言模型结合,有效缓解了模型幻觉和知识时效性问题。在大模型应用落地过程中,RAG系统已成为企业知识问答、智能客服、文档分析等场景的核心技术方案。其工作流程包括文档分块、向量化编码、语义检索、上下文组装和生成回答五个环节,每个环节的工程化实现质量直接决定最终输出效果。
RAG系统架构与核心组件设计
RAG系统的核心架构由知识库构建和检索生成两部分组成。知识库构建负责将原始文档处理成可检索的向量索引,检索生成则根据用户查询从索引中召回相关内容并交给大模型生成回答。完整的数据流包括用户查询向量化、向量数据库检索、Top-K结果召回、结果重排序、Prompt组装和LLM生成六个步骤。
# RAG系统核心数据流
用户Query → Embedding编码 → 向量数据库检索 → Top-K结果召回
→ Cross-Encoder重排序 → Prompt组装 → LLM生成 → 最终回答
技术选型方面,Embedding模型可选OpenAI text-embedding-3-small或本地部署的BGE/E5模型;向量数据库可选用Milvus、Qdrant或Chroma;重排序模型可用bge-reranker。以下是一个基于LangChain和Chroma的基础架构搭建示例:
from langchain_community.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain_community.vectorstores import Chroma
# 文档加载与分块
loader = PyPDFLoader("knowledge_base.pdf")
documents = loader.load()
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=500,
chunk_overlap=50,
separators=["\n\n", "\n", "。", "!", "?"]
)
chunks = text_splitter.split_documents(documents)
# 向量化与入库
embeddings = HuggingFaceEmbeddings(
model_name="BAAI/bge-large-zh-v1.5",
model_kwargs={"device": "cuda"}
)
vectorstore = Chroma.from_documents(
documents=chunks,
embedding=embeddings,
persist_directory="./chroma_db"
)
vectorstore.persist()
向量数据库选型与Embedding模型配置
向量数据库选型需要综合考虑数据规模、查询延迟、部署成本三个维度。Milvus适合亿级向量的大规模场景,Qdrant在百万级数据中查询延迟表现稳定,Chroma则适用于原型验证和中小规模应用。Embedding模型对中英文支持的效果差异较大,BGE-large-zh-v1.5在中文语义检索任务上表现优于多数同级别模型,维度为1024,支持最长512 token的输入。
配置时需注意模型维度与向量数据库的schema保持一致,否则插入数据时会报维度不匹配错误:
from qdrant_client import QdrantClient
from qdrant_client.models import Distance, VectorParams
client = QdrantClient(host="localhost", port=6333)
# 创建集合,维度必须与Embedding模型一致
client.create_collection(
collection_name="rag_knowledge",
vectors_config=VectorParams(
size=1024, # BGE-large维度
distance=Distance.COSINE
)
)
# 批量插入向量数据
client.upsert(
collection_name="rag_knowledge",
points=[
{"id": i, "vector": emb, "payload": {"text": chunk, "source": doc}}
for i, (emb, chunk, doc) in enumerate(embeddings_list)
]
)
文档分块策略与语义检索实现
文档分块是影响RAG检索质量的关键环节。分块过大导致检索精度下降,分块过小则丢失上下文信息。实践中推荐的分块大小为300-500字符,重叠区域设为分块大小的10%-15%。对于结构化文档(如技术手册、API文档),应优先按标题层级分块;对于非结构化文本,递归字符分块器是通用选择。
def retrieve(query, vectorstore, top_k=5):
'''从向量数据库检索Top-K相关文档'''
results = vectorstore.similarity_search_with_score(query, k=top_k)
# 过滤低相似度结果
filtered = [
(doc, score) for doc, score in results
if score > 0.3 # 相似度阈值
]
return filtered
def build_context(retrieved_docs, max_tokens=2000):
'''组装检索结果为LLM上下文'''
context = ""
for doc, score in retrieved_docs:
context += f"[相关度: {score:.2f}]\n{doc.page_content}\n\n"
return context[:max_tokens]
检索结果重排序与Prompt模板组装
向量检索召回的Top-K结果中,排序质量往往不够精准。引入Cross-Encoder重排序模型可以显著提升最终结果的相关性。BGE-reranker-large在中文场景下表现稳定,推理延迟在可接受范围内。Prompt组装需要遵循明确的结构化模板,将检索上下文与用户问题清晰分隔,避免模型混淆检索内容与用户意图。
from sentence_transformers import CrossEncoder
reranker = CrossEncoder("BAAI/bge-reranker-large")
def rerank(query, documents, top_n=3):
'''对检索结果重排序'''
pairs = [(query, doc.page_content) for doc, _ in documents]
scores = reranker.predict(pairs)
ranked = sorted(zip(documents, scores), key=lambda x: x[1], reverse=True)
return ranked[:top_n]
PROMPT_TEMPLATE = """请基于以下检索到的参考资料回答问题。如果资料中没有相关信息,请直接说明。
参考资料:
{context}
问题: {question}
回答:"""
def generate_answer(query, vectorstore, llm):
retrieved = retrieve(query, vectorstore, top_k=10)
reranked = rerank(query, retrieved, top_n=3)
context = build_context(reranked)
prompt = PROMPT_TEMPLATE.format(context=context, question=query)
return llm.generate(prompt)
RAG系统评估指标与混合检索优化
RAG系统评估需要从检索质量和生成质量两个维度量化。检索侧关注召回率(Recall@K)和精确率(Precision@K),生成侧关注答案准确率和幻觉率。常见优化方向包括混合检索(向量检索+关键词BM25检索)、多路召回(不同Embedding模型并行检索后融合)、查询改写(将用户问题扩展为多个子查询)。
from rank_bm25 import BM25Okapi
def hybrid_search(query, vectorstore, bm25_index, top_k=5, alpha=0.5):
"""混合检索,alpha为向量检索权重"""
vec_results = vectorstore.similarity_search_with_score(query, k=top_k * 2)
vec_scores = {doc.page_content: score for doc, score in vec_results}
tokenized_query = query.split()
bm25_scores = bm25_index.get_scores(tokenized_query)
combined = {}
for i, score in enumerate(bm25_scores):
text = documents[i].page_content
vec_score = vec_scores.get(text, 0)
combined[text] = alpha * vec_score + (1 - alpha) * score
ranked = sorted(combined.items(), key=lambda x: x[1], reverse=True)
return ranked[:top_k]
RAG系统的工程化落地是一个持续迭代的过程。初始版本可以快速搭建验证效果,后续通过调整分块大小、更换Embedding模型、引入重排序、实现混合检索等手段逐步优化检索精度和生成质量。评估每个优化措施的效果时,建议构建一个标注好的问答测试集,用定量指标驱动迭代决策,避免凭主观感受调参。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/rag-jian-suo-zeng-qiang-sheng-cheng-xi-tong-da-jian-xiang/