RAG 系统完整构建指南:从原理到实战

RAG 系统完整构建指南:从原理到实战

RAG 系统完整构建指南:从原理到实战

让大模型拥有「私有记忆」的最优解,不是微调,而是 RAG。

什么是 RAG?为什么 2026 年它仍然是首选方案?

RAG(Retrieval-Augmented Generation,检索增强生成)的核心思想极其简洁:先从知识库中检索相关文档片段,再将这些片段作为上下文注入 LLM 的 prompt 中,让模型基于真实数据生成回答。

相比微调(Fine-tuning),RAG 有三大不可替代的优势:

维度RAG微调
知识更新秒级生效,改文档即可需重新训练,耗时数小时
成本仅推理费用GPU 训练 + 存储
可溯源可返回原文出处黑盒生成
数据量要求几十篇文档即可启动通常需要数千条样本

这也是为什么在 AI Agent 工程化落地指南 中,RAG 被列为 Agent 获取领域知识的首选机制。

RAG 系统架构全景

一个生产级 RAG 系统包含 5 个核心模块:

┌─────────────────────────────────────────────────────────────┐
│                    RAG 系统架构                              │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ┌──────────┐    ┌──────────┐    ┌──────────────────┐      │
│  │ 文档输入  │───▶│ 文档切分  │───▶│ Embedding 模型   │      │
│  │ PDF/Word │    │ Chunking │    │ text-embedding-3 │      │
│  │ HTML/API │    │          │    │ bge-m3 / gte     │      │
│  └──────────┘    └──────────┘    └────────┬─────────┘      │
│                                           │                  │
│                                           ▼                  │
│                                  ┌──────────────────┐       │
│                                  │   向量数据库      │       │
│                                  │ Pinecone/Chroma  │       │
│                                  │ Weaviate/Qdrant  │       │
│                                  └────────┬─────────┘       │
│                                           │                  │
│  ┌──────────┐    ┌──────────┐            │                  │
│  │  LLM     │◀───│ 检索+重排 │◀───────────┘                  │
│  │ GPT-4o  │    │ Reranker │                               │
│  │ Claude  │    │          │                               │
│  │ Qwen3   │    └──────────┘                               │
│  └────┬─────┘                                               │
│       │                                                      │
│       ▼                                                      │
│  ┌──────────┐                                                │
│  │ 最终回答  │                                                │
│  │ + 引用来源│                                                │
│  └──────────┘                                                │
└─────────────────────────────────────────────────────────────┘

向量数据库选型:Pinecone vs Weaviate vs Chroma

2026 年主流向量数据库对比:

特性PineconeWeaviateChroma
部署方式全托管 SaaS自托管/云嵌入式/单机
免费额度100K 向量开源免费开源免费
最大规模10B+ 向量10B+ 向量~100K(单机)
混合搜索✅ 原生支持✅ BM25+向量⚠️ 需扩展
多租户✅ 原生✅ namespace⚠️ 手动
延迟(P99)~20ms~30ms~10ms(本地)
适用场景企业级生产复杂查询原型/小规模

选型建议:

  • 原型验证 / 本地开发 → Chroma(零配置,pip install 即用)
  • 中小规模生产(< 100 万向量) → Weaviate(混合搜索强)
  • 企业级 / 超大规模 → Pinecone(免运维,自动扩缩容)

文档切分策略:决定 RAG 质量的关键

文档切分(Chunking)是 RAG 中最容易被忽视、却对最终效果影响最大的环节。

4 种主流切分策略

from langchain.text_splitter import (
    RecursiveCharacterTextSplitter,
    MarkdownHeaderTextSplitter,
    TokenTextSplitter
)

# 1. 固定大小切分(最基础)
splitter = RecursiveCharacterTextSplitter(
    chunk_size=512,
    chunk_overlap=50,
    separators=["\n\n", "\n", "。", " ", ""]
)

# 2. 按 Markdown 标题切分(适合技术文档)
md_splitter = MarkdownHeaderTextSplitter(
    headers_to_split_on=[
        ("#", "H1"), ("##", "H2"), ("###", "H3")
    ]
)

# 3. 语义切分(按句子边界)
from langchain_experimental.text_splitter import SemanticChunker
semantic_splitter = SemanticChunker(
    embedding_function=embeddings,
    breakpoint_threshold_type="percentile",
    breakpoint_threshold_amount=95
)

# 4. 递归切分 + 元数据保留(推荐)
def smart_chunk(document):
    """根据文档类型选择切分策略"""
    if document.metadata["source"].endswith(".md"):
        return md_splitter.split_text(document.page_content)
    elif len(document.page_content) > 2000:
        return splitter.split_text(document.page_content)
    else:
        return [document.page_content]

切分参数黄金值

文档类型chunk_sizeoverlap推荐策略
技术文档512-102450-100Markdown 标题切分
法律合同1024-2048200按段落 + 递归
对话记录256-51250按轮次切分
代码文件51250按函数/类切分

Embedding 模型选择

2026 年推荐的 Embedding 模型:

模型维度MTEB 均分价格推荐场景
text-embedding-3-large307265.1$0.13/1M tokens高精度需求
bge-m3 (BAAI)102464.8免费(本地)多语言 + 本地部署
gte-Qwen2-7B-instruct358467.2免费(本地)最高精度
voyage-3-large102466.5$0.12/1M tokens代码+文本混合
# OpenAI Embedding
from langchain_openai import OpenAIEmbeddings
embeddings = OpenAIEmbeddings(model="text-embedding-3-large")

# 本地 BGE-M3(推荐中文场景)
from sentence_transformers import SentenceTransformer
model = SentenceTransformer("BAAI/bge-m3")
vectors = model.encode(["文档内容"], normalize_embeddings=True)

LangChain vs LlamaIndex:框架选型

这两个框架在 2026 年的定位已经明显分化:

维度LangChainLlamaIndex
核心定位通用 LLM 应用框架专注数据索引与检索
RAG 能力基础链式调用内置 20+ 高级 RAG 模式
Agent 支持✅ LangGraph 强⚠️ 基础
学习曲线中等较低(RAG 场景)
生产就绪✅✅
社区生态更大更专注

选型建议:

  • 纯 RAG 应用 → LlamaIndex(开箱即用的 RAG 模式更多)
  • RAG + Agent 混合 → LangChain + LangGraph(参考 AI Agent 工具全景评测)
  • 快速原型 → 两者皆可,LlamaIndex 代码更少

完整代码示例:构建生产级 RAG

以下是一个可直接运行的完整 RAG 系统,使用 LlamaIndex + Chroma:

"""
生产级 RAG 系统完整实现
依赖:pip install llama-index chromadb llama-index-embeddings-openai
"""
import os
from llama_index.core import (
    VectorStoreIndex,
    StorageContext,
    Settings,
    SimpleDirectoryReader
)
from llama_index.vector_stores.chroma import ChromaVectorStore
from llama_index.embeddings.openai import OpenAIEmbedding
from llama_index.core.node_parser import SemanticSplitterNodeParser
from llama_index.core.postprocessor import SentenceTransformerRerank
import chromadb

# 1. 配置
os.environ["OPENAI_API_KEY"] = "your-key-here"
Settings.embed_model = OpenAIEmbedding(model="text-embedding-3-large")
Settings.llm = None  # 可替换为本地模型
Settings.chunk_size = 512
Settings.chunk_overlap = 50

# 2. 初始化 Chroma 向量库
chroma_client = chromadb.PersistentClient(path="./chroma_db")
chroma_collection = chroma_client.get_or_create_collection("rag_docs")
vector_store = ChromaVectorStore(chroma_collection=chroma_collection)

# 3. 加载并切分文档
reader = SimpleDirectoryReader("./docs")
documents = reader.load_data()

# 语义切分(比固定大小效果更好)
splitter = SemanticSplitterNodeParser(
    buffer_size=1,
    breakpoint_percentile_threshold=95,
    embed_model=Settings.embed_model
)
nodes = splitter.get_nodes_from_documents(documents)

# 4. 构建索引
storage_context = StorageContext.from_defaults(vector_store=vector_store)
index = VectorStoreIndex(nodes, storage_context=storage_context)

# 5. 创建查询引擎(带重排序)
reranker = SentenceTransformerRerank(
    model="BAAI/bge-reranker-v2-m3",
    top_n=5
)
query_engine = index.as_query_engine(
    similarity_top_k=20,  # 先检索 20 条
    node_postprocessors=[reranker],  # 再重排取 top 5
)

# 6. 查询
response = query_engine.query("RAG 系统如何选择合适的 chunk_size?")
print(f"回答:{response}")
print(f"\n引用来源:")
for node in response.source_nodes:
    print(f"  - {node.metadata.get('file_name', 'unknown')} (相似度: {node.score:.3f})")

性能优化:从 3 秒到 200 毫秒

检索层优化

# 1. 混合搜索(向量 + BM25 关键词)
from llama_index.core import QueryFusionRetriever

retriever = QueryFusionRetriever(
    [
        index.as_retriever(similarity_top_k=10),  # 向量检索
        bm25_retriever,                             # 关键词检索
    ],
    mode="reciprocal_rerank",  # 融合排序
    similarity_top_k=15,
)

# 2. 查询改写(提升召回率)
from llama_index.core.query_engine import RetrieverQueryEngine
from llama_index.core.postprocessor import MetadataReplacementPostProcessor

# 3. 缓存热门查询
from cachetools import TTLCache
query_cache = TTLCache(maxsize=1000, ttl=3600)

延迟优化实测数据

优化手段延迟(P50)延迟(P99)提升幅度
基线(朴素 RAG)2800ms4200ms-
+ 向量库换 Pinecone1200ms1800ms57% ↓
+ 检索结果缓存350ms800ms87% ↓
+ 异步 LLM 流式280ms450ms90% ↓
+ 量化 Embedding200ms320ms93% ↓

实际应用场景

场景 1:企业内部知识库

# 接入企业文档:Confluence、飞书、Notion
from llama_index.readers.confluence import ConfluenceReader
from llama_index.readers.notion import NotionPageReader

# 权限控制:按部门隔离
def query_with_acl(user_dept, question):
    filters = MetadataFilters(filters=[
        ExactMatchFilter(key="department", value=user_dept)
    ])
    return query_engine.query(question, filters=filters)

场景 2:代码仓库问答

# 索引 GitHub 仓库,回答代码问题
from llama_index.readers.github import GithubRepositoryReader

reader = GithubRepositoryReader(
    github_token=os.environ["GITHUB_TOKEN"],
    owner="microsoft",
    repo="vscode",
    filter_directories=(["src"], GithubRepositoryReader.FilterType.INCLUDE),
)
docs = reader.load_data(branch="main")
# 构建索引后可回答:"vscode 的插件系统如何加载扩展?"

场景 3:多模态 RAG(图表 + 文本)

# 用 GPT-4o 提取图表描述,再与文本一起索引
from llama_index.multi_modal_llms.generic import GenericMultiModalLLM

# 图表 → 文字描述 → 与原文一起切分索引
# 适合财报、技术白皮书等含大量图表的场景

更多 Agent + RAG 结合的场景,参考 MCP 工作流编排指南 和 Dify 平台完整指南。

常见问题(FAQ)

Q1: RAG 的 chunk_size 应该设多大?

A: 没有万能值。技术文档推荐 512-1024 tokens,法律合同推荐 1024-2048 tokens。核心原则是:每个 chunk 应该包含一个完整的语义单元(一段话、一个段落、一个函数)。建议用 A/B 测试在你的数据集上找最优值。

Q2: 向量数据库需要自己部署吗?

A: 取决于规模。原型阶段用 Chroma(嵌入式,无需部署);生产环境如果向量数 < 100 万,可以用 Weaviate Cloud 或 Qdrant Cloud;超大规模或合规要求高的场景,建议自托管。

Q3: RAG 检索到了错误文档怎么办?

A: 三层防线:① 用混合搜索(向量+BM25)提升召回;② 加 Reranker 模型(如 bge-reranker)精排;③ 在 prompt 中加指令:“如果提供的上下文不相关,请说’我不确定’“。

Q4: LangChain 和 LlamaIndex 可以一起用吗?

A: 完全可以。常见模式是:LlamaIndex 负责数据索引和检索,LangChain 负责 Agent 编排和工具调用。两者通过 LlamaIndex 的 RetrieverTool 无缝集成。

Q5: 中文 RAG 用什么 Embedding 模型最好?

A: 2026 年中文场景首选 bge-m3(BAAI 开源,本地部署免费)或 text-embedding-3-large(OpenAI,精度最高)。如果数据量大且预算有限,gte-Qwen2 系列是性价比之选。

Q6: RAG 系统的评估指标有哪些?

A: 核心指标有三个:① 检索准确率(Hit Rate@K)—— 前 K 条结果中包含正确答案的比例;② 回答忠实度(Faithfulness)—— 回答是否基于检索到的内容;③ 回答相关性(Relevancy)—— 回答是否切题。推荐用 RAGAS 框架自动化评估。


总结

构建一个生产级 RAG 系统的关键决策点:

  1. 向量数据库:原型用 Chroma,生产用 Pinecone/Weaviate
  2. 切分策略:语义切分 > 固定大小,chunk_size 需 A/B 测试
  3. Embedding 模型:中文首选 bge-m3,英文首选 text-embedding-3-large
  4. 框架选择:纯 RAG 用 LlamaIndex,RAG+Agent 用 LangChain
  5. 性能优化:混合搜索 + Reranker + 缓存,可将延迟从 3s 降到 200ms

RAG 不是银弹,但它是让 LLM 安全、可控地使用私有数据的最成熟方案。2026 年,随着多模态 RAG 和 Agentic RAG 的成熟,它的应用场景还在持续扩大。