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 年主流向量数据库对比:
| 特性 | Pinecone | Weaviate | Chroma |
|---|---|---|---|
| 部署方式 | 全托管 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_size | overlap | 推荐策略 |
|---|---|---|---|
| 技术文档 | 512-1024 | 50-100 | Markdown 标题切分 |
| 法律合同 | 1024-2048 | 200 | 按段落 + 递归 |
| 对话记录 | 256-512 | 50 | 按轮次切分 |
| 代码文件 | 512 | 50 | 按函数/类切分 |
Embedding 模型选择
2026 年推荐的 Embedding 模型:
| 模型 | 维度 | MTEB 均分 | 价格 | 推荐场景 |
|---|---|---|---|---|
| text-embedding-3-large | 3072 | 65.1 | $0.13/1M tokens | 高精度需求 |
| bge-m3 (BAAI) | 1024 | 64.8 | 免费(本地) | 多语言 + 本地部署 |
| gte-Qwen2-7B-instruct | 3584 | 67.2 | 免费(本地) | 最高精度 |
| voyage-3-large | 1024 | 66.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 年的定位已经明显分化:
| 维度 | LangChain | LlamaIndex |
|---|---|---|
| 核心定位 | 通用 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) | 2800ms | 4200ms | - |
| + 向量库换 Pinecone | 1200ms | 1800ms | 57% ↓ |
| + 检索结果缓存 | 350ms | 800ms | 87% ↓ |
| + 异步 LLM 流式 | 280ms | 450ms | 90% ↓ |
| + 量化 Embedding | 200ms | 320ms | 93% ↓ |
实际应用场景
场景 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 系统的关键决策点:
- 向量数据库:原型用 Chroma,生产用 Pinecone/Weaviate
- 切分策略:语义切分 > 固定大小,chunk_size 需 A/B 测试
- Embedding 模型:中文首选 bge-m3,英文首选 text-embedding-3-large
- 框架选择:纯 RAG 用 LlamaIndex,RAG+Agent 用 LangChain
- 性能优化:混合搜索 + Reranker + 缓存,可将延迟从 3s 降到 200ms
RAG 不是银弹,但它是让 LLM 安全、可控地使用私有数据的最成熟方案。2026 年,随着多模态 RAG 和 Agentic RAG 的成熟,它的应用场景还在持续扩大。