/ RAG  检索增强生成  向量数据库  LangChain  ChromaDB  混合检索  AI应用  大语言模型 

生产级 RAG 系统构建实战:从文档切片到混合检索全链路解析


封面

什么是 RAG?为什么它如此重要

大语言模型(LLM)拥有强大的推理和生成能力,但存在两个致命缺陷:知识截止日期和幻觉问题。RAG(Retrieval-Augmented Generation,检索增强生成)通过在推理时动态检索外部知识库,将实时信息注入到模型的上下文窗口中,从根本上解决了这两大痛点。

与其说 RAG 是一种技术,不如说它是一种架构范式。它将"检索"与"生成"解耦,让 LLM 专注于理解和推理,而将知识存储的职责交给专用的向量数据库。这种分工使得企业可以随时更新知识库,而无需重新训练模型——这对于企业级应用来说至关重要。

  • 知识时效性:知识库可以实时更新,LLM 永远读取最新信息

  • 减少幻觉:模型回答有据可查,可溯源到原始文档

  • 成本可控:无需微调或重训练,仅需维护知识库

  • 隐私安全:敏感数据存储在私有环境,不上传到第三方

RAG 核心架构与数据流

一个完整的 RAG 系统由四个核心模块组成:文档处理管道、向量化引擎、检索器和生成器。理解这四个模块之间的数据流是构建高质量 RAG 系统的基础。

数据流分为两条路径:离线索引路径(文档 → 切片 → 向量化 → 入库)和在线查询路径(用户问题 → 向量化 → 检索 → 构建 Prompt → LLM 生成 → 返回答案)。

from langchain.document_loaders import DirectoryLoader, PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.vectorstores import Chroma
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain.chains import RetrievalQA

# 1. 文档加载
loader = DirectoryLoader("./docs", glob="**/*.pdf", loader_cls=PyPDFLoader)
documents = loader.load()
print(f"加载文档数: {len(documents)}")

# 2. 文本切片
splitter = RecursiveCharacterTextSplitter(
    chunk_size=512,
    chunk_overlap=64,
    separators=["\n\n", "\n", "。", "!", "?", " ", ""]
)
chunks = splitter.split_documents(documents)
print(f"切片数量: {len(chunks)}")

# 3. 向量化并存入 ChromaDB
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
vectorstore = Chroma.from_documents(
    documents=chunks,
    embedding=embeddings,
    persist_directory="./chroma_db"
)
vectorstore.persist()
print("向量库构建完成")

文档切片策略:影响 RAG 质量的关键因素

切片(Chunking)策略是 RAG 系统中最容易被忽视但影响最大的环节。切片太小会导致语义不完整,切片太大则会引入噪声、稀释关键信息,还会消耗更多的 Token。

在实践中,有几种常见的切片策略,适用于不同场景:

  • 固定大小切片:最简单,适合格式规范的文本,推荐 chunk_size=512,overlap=64

  • 语义切片(Semantic Chunking):基于句子嵌入的相似度动态切分,保留语义完整性,效果更好但计算开销较大

  • 结构化切片:按 Markdown 标题、PDF 段落等文档结构切分,适合有明确层级的技术文档

  • 父子切片(Parent-Child):检索时用小切片保证精度,返回时扩展到父级大切片保证上下文,兼顾两者优点

from langchain_experimental.text_splitter import SemanticChunker
from langchain_openai import OpenAIEmbeddings

# 语义切片 - 根据嵌入相似度自动分割
semantic_splitter = SemanticChunker(
    OpenAIEmbeddings(),
    breakpoint_threshold_type="percentile",  # 按百分位数确定断点
    breakpoint_threshold_amount=95           # 相似度低于 95 分位时切割
)

# 父子切片策略
from langchain.retrievers import ParentDocumentRetriever
from langchain.storage import InMemoryStore

parent_splitter = RecursiveCharacterTextSplitter(chunk_size=2000)
child_splitter = RecursiveCharacterTextSplitter(chunk_size=400)
store = InMemoryStore()

retriever = ParentDocumentRetriever(
    vectorstore=vectorstore,
    docstore=store,
    child_splitter=child_splitter,
    parent_splitter=parent_splitter
)
retriever.add_documents(documents)

混合检索:超越纯向量搜索

纯向量检索擅长处理语义相似的查询,但在精确匹配(如产品型号、人名、代码片段)上往往不如传统的关键词检索。生产级 RAG 系统通常采用混合检索(Hybrid Search)策略,结合向量检索和 BM25 全文检索,通过 RRF(倒数排名融合)算法合并结果。

from langchain.retrievers import BM25Retriever, EnsembleRetriever

# BM25 关键词检索器
bm25_retriever = BM25Retriever.from_documents(chunks)
bm25_retriever.k = 5

# 向量检索器
vector_retriever = vectorstore.as_retriever(search_kwargs={"k": 5})

# 混合检索:60% 向量 + 40% BM25
ensemble_retriever = EnsembleRetriever(
    retrievers=[vector_retriever, bm25_retriever],
    weights=[0.6, 0.4]
)

# 查询测试
results = ensemble_retriever.invoke("如何配置 Redis 集群?")
for i, doc in enumerate(results):
    print(f"[{i+1}] {doc.page_content[:100]}...")

除了混合检索,还可以引入查询改写(Query Rewriting)技术,让 LLM 先将用户问题分解或重写为多个子查询,分别检索后再合并结果,显著提升复杂问题的召回率。

构建生产级 RAG 系统的工程实践

从 Demo 到生产,RAG 系统还需要解决一系列工程问题。以下是几个关键的最佳实践:

  • 异步并发:使用 asyncio 并发处理多个文档的向量化,将批处理时间缩短 5-10 倍

  • 增量更新:通过文档内容哈希值判断是否需要重新向量化,避免全量重建

  • 元数据过滤:在检索时附加元数据条件(如文档来源、时间范围),精确缩小检索范围

  • Reranker 重排序:使用 Cross-Encoder 模型对初步检索结果重排序,提升 Top-K 精度

  • 答案评估:使用 RAGAS 框架自动评估 faithfulness(忠实度)和 answer_relevancy(相关性)

from ragas import evaluate
from ragas.metrics import faithfulness, answer_relevancy, context_recall
from datasets import Dataset

# 构建评估数据集
eval_data = {
    "question": ["RAG 是什么?", "如何优化检索质量?"],
    "answer": [generated_answers[0], generated_answers[1]],
    "contexts": [retrieved_contexts[0], retrieved_contexts[1]],
    "ground_truth": ["RAG 是检索增强生成技术...", "可通过混合检索和重排序..."]
}

dataset = Dataset.from_dict(eval_data)
result = evaluate(
    dataset,
    metrics=[faithfulness, answer_relevancy, context_recall]
)
print(result.to_pandas())

通过持续的评估和迭代,一个成熟的 RAG 系统在企业私有知识库场景中可以达到 80% 以上的回答准确率。结合完善的日志监控和用户反馈机制,RAG 系统将成为企业 AI 转型的核心基础设施。

发布评论

热门评论区: