RAG(检索增强生成)是当前AIGC应用落地的核心技术方案,通过将外部知识库与大模型结合,有效解决大模型幻觉问题和知识时效性限制。本文以实战角度拆解RAG系统搭建的完整流程,涵盖向量数据库选型、文档分块策略、Embedding模型配置、检索排序优化及大模型部署等关键环节。
RAG系统架构设计与核心组件选型
一套完整的RAG系统包含四个核心层:文档处理层、向量存储层、检索排序层、生成推理层。文档处理层负责将PDF、Word、HTML等异构文档解析为结构化文本;向量存储层使用Embedding模型将文本转为向量并存储;检索排序层根据用户查询召回相关文档片段;生成推理层将检索结果作为上下文输入大模型生成最终回答。
向量数据库选型需考虑数据规模和查询性能。Milvus适合亿级向量场景,支持IVF_FLAT、HNSW等多种索引;Chroma轻量级方案,适合中小规模知识库;Weaviate内置多模态检索能力。以下以Milvus + bge-large-zh模型为例演示部署配置:
# docker-compose.yml 部署Milvus
version: '3.5'
services:
etcd:
image: quay.io/coreos/etcd:v3.5.5
environment:
- ETCD_AUTO_COMPACTION_MODE=revision
- ETCD_AUTO_COMPACTION_RETENTION=1000
volumes:
- etcd_data:/etcd
minio:
image: minio/minio:RELEASE.2023-03-24T21-41-23Z
environment:
MINIO_ACCESS_KEY: minioadmin
MINIO_SECRET_KEY: minioadmin
command: minio server /minio_data
milvus:
image: milvusdb/milvus:v2.4.0
command: ["milvus", "run", "standalone"]
environment:
ETCD_ENDPOINTS: etcd:2379
MINIO_ADDRESS: minio:9000
ports:
- "19530:19530"
depends_on:
- etcd
- minio
文档分块策略与Embedding配置
文档分块直接影响检索精度。固定长度分块(如512 token)实现简单但可能截断语义;按段落分块保留语义完整性但块大小不均匀;递归分块结合语义边界和长度限制是生产环境推荐方案。LangChain提供的RecursiveCharacterTextSplitter支持多级分隔符递归切分:
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.embeddings import HuggingFaceEmbeddings
from pymilvus import connections, FieldSchema, CollectionSchema, Collection, DataType
# 递归分块配置
splitter = RecursiveCharacterTextSplitter(
chunk_size=500,
chunk_overlap=50,
separators=["\n\n", "\n", "。", ";", ",", " ", ""]
)
chunks = splitter.split_text(document_text)
# 加载bge-large-zh Embedding模型
embedding_model = HuggingFaceEmbeddings(
model_name="BAAI/bge-large-zh-v1.5",
model_kwargs={"device": "cuda"}
)
# Milvus集合创建
connections.connect(host="localhost", port="19530")
fields = [
FieldSchema(name="id", dtype=DataType.INT64, is_primary=True, auto_id=True),
FieldSchema(name="embedding", dtype=DataType.FLOAT_VECTOR, dim=1024),
FieldSchema(name="text", dtype=DataType.VARCHAR, max_length=2000),
FieldSchema(name="source", dtype=DataType.VARCHAR, max_length=500)
]
schema = CollectionSchema(fields, "RAG knowledge base")
collection = Collection("rag_docs", schema)
collection.create_index("embedding", {
"index_type": "HNSW",
"metric_type": "IP",
"params": {"M": 16, "efConstruction": 256}
})
检索排序优化:混合检索与重排序
纯向量检索在专有名词、缩写等场景表现不佳,混合检索(Hybrid Search)结合BM25关键词检索和向量检索能显著提升召回率。使用Reciprocal Rank Fusion(RRF)算法融合两路检索结果,再通过Cross-Encoder重排序模型精排Top-K结果:
from rank_bm25 import BM25Okapi
import numpy as np
def hybrid_search(query, collection, embedding_model, top_k=10):
# 向量检索
query_vec = embedding_model.embed_query(query)
vec_results = collection.search(
data=[query_vec], anns_field="embedding",
param={"metric_type": "IP", "params": {"ef": 64}},
limit=top_k * 3, output_fields=["text", "source"]
)
# BM25检索
all_docs = collection.query(expr="id >= 0", output_fields=["text"])
tokenized_corpus = [doc["text"][:200].split() for doc in all_docs]
bm25 = BM25Okapi(tokenized_corpus)
bm25_scores = bm25.get_scores(query.split())
# RRF融合
rrf_scores = {}
for rank, hit in enumerate(vec_results[0]):
doc_id = hit.id
rrf_scores[doc_id] = rrf_scores.get(doc_id, 0) + 1.0 / (rank + 60)
bm25_ranked = np.argsort(bm25_scores)[::-1][:top_k * 3]
for rank, idx in enumerate(bm25_ranked):
doc_id = all_docs[idx]["id"] if "id" in all_docs[idx] else idx
rrf_scores[doc_id] = rrf_scores.get(doc_id, 0) + 1.0 / (rank + 60)
return sorted(rrf_scores.items(), key=lambda x: x[1], reverse=True)[:top_k]
大模型部署与Prompt工程
检索到相关文档后,需要将上下文组装为Prompt输入大模型。vLLM是当前主流的大模型推理框架,支持PagedAttention显存管理和连续批处理,相比HuggingFace Transformers提升2-4倍吞吐量。部署Qwen2.5-14B模型示例:
# vLLM服务启动
python -m vllm.entrypoints.openai.api_server \
--model Qwen/Qwen2.5-14B-Instruct \
--tensor-parallel-size 2 \
--max-model-len 8192 \
--gpu-memory-utilization 0.9 \
--port 8000
# RAG生成Prompt模板
from openai import OpenAI
client = OpenAI(base_url="http://localhost:8000/v1", api_key="empty")
def generate_answer(query, retrieved_docs):
context = "\n\n".join([doc["text"] for doc in retrieved_docs])
prompt = f"请根据以下参考资料回答问题。如果资料中没有相关信息,请说明无法回答。\n\n参考资料:\n{context}\n\n问题:{query}\n\n回答:"
response = client.chat.completions.create(
model="Qwen/Qwen2.5-14B-Instruct",
messages=[{"role": "user", "content": prompt}],
temperature=0.3,
max_tokens=1024
)
return response.choices[0].message.content
常见问题诊断与性能调优
RAG系统上线后常见三类问题:检索结果不相关、生成回答出现幻觉、响应延迟过高。检索不相关通常由分块粒度过粗或Embedding模型与领域不匹配导致,可通过调整chunk_size到300-500区间、更换领域微调Embedding模型解决。幻觉问题的根源在于上下文窗口截断关键信息,需控制检索文档数量在3-5篇并优化重排序。延迟问题可通过vLLM连续批处理、Milvus HNSW索引ef参数调优、Embedding模型量化(如ONNX FP16)系统性优化。
监控层面建议采集检索命中率(Recall@K)、上下文利用率、生成置信度三个核心指标。检索命中率低于70%说明知识库覆盖不足或分块策略需要调整;上下文利用率反映大模型实际引用的检索内容占比,低于30%需检查Prompt模板设计;生成置信度可通过大模型logprobs输出监控,持续低置信度回答需触发人工审核流程。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/rag-jian-suo-zeng-qiang-sheng-cheng-xi-tong-da-jian-shi/