概述
Retrieval-Augmented Generation (RAG) 已成为大语言模型应用的核心架构范式。 它通过将外部知识检索与 LLM 生成能力相结合,有效解决了纯 LLM 的知识时效性、 hallucination 以及缺乏垂直领域知识等问题。本文将从资深架构师视角, 系统性地解析 RAG 系统从数据处理到最终输出的完整技术链条。
RAG 的本质是 Context Augmentation——通过在推理时动态注入 相关上下文,让 LLM 能够在「看到」最新、最准确信息的前提下生成回答。
系统架构总览
一个完整的 RAG Pipeline 包含两个核心阶段:
Indexing Pipeline(索引阶段)
负责将原始文档转化为可检索的知识库。这一阶段的质量直接决定了 后续检索阶段的上限。关键步骤包括:文档解析、文本分块 (Chunking)、 向量化 (Embedding) 以及向量存储。
Query Pipeline(查询阶段)
负责将用户问题转化为精准的答案。这一阶段涉及:Query 理解、 向量检索、Hybrid Search(混合检索)、Reranking(重排序)以及 最终的 LLM 生成。
许多团队将大量精力投入在 LLM 调优上,却忽视了索引阶段的质量。 实际上,GIGO (Garbage In, Garbage Out) 在 RAG 系统中 表现得尤为明显——糟糕的分块策略和低质量的 Embedding 会导致 即使最先进的 LLM 也无法给出准确的答案。
Chunk 策略
Chunk 策略是 RAG 系统设计中最基础也最关键的决策之一。 它直接影响:检索精度(Chunk 太小导致语义不完整)、上下文利用率 (Chunk 太大导致关键信息被淹没)以及检索延迟与存储成本。
主流分块方法
固定大小分块
- 实现简单,一致性强
- 无法考虑语义边界
- 适合结构化程度低的文本
chunk_size = 512
chunk_overlap = 50
语义分块
- 基于句子/段落边界切分
- 保留完整语义单元
- 需要 NLP 预处理支持
递归字符分块
- LangChain 默认策略
- 递归尝试不同分隔符
- 平衡效果与实现复杂度
领域感知分块
- 针对代码、表格、公式优化
- 需要领域知识介入
- 效果最优但实现成本高
Chunk Size 选择
Chunk Size 的选择需要综合考虑以下因素:
- Embedding 模型上下文窗口:现代 Embedding 模型(如 Cohere embed-v3、text-embedding-3-large)支持 8K-16K tokens 的上下文, 但实际检索精度随长度增加而下降
- 平均 query 长度:用户 query 通常较短(50-200 tokens), Chunk 需要足够长以提供完整语义
- 文档结构特征:技术文档适合 300-500 tokens 块, 而长篇小说可能需要 1000+ tokens 才能保留情节完整性
- LLM 上下文窗口:最终送入 LLM 的上下文总量 需在模型限制内(通常 4K-128K tokens)
| 应用场景 | 推荐 Chunk Size | Overlap | 说明 |
|---|---|---|---|
| 通用文档问答 | 512 tokens | 50 tokens | 平衡语义完整性与检索精度 |
| 代码库问答 | 256-512 tokens | 50-100 tokens | 保持函数/类的完整性 |
| 长文档摘要 | 1000+ tokens | 100 tokens | 保留更多上下文用于生成 |
| 表格密集型文档 | 按表格结构切分 | 0 | 表格需整体保留 |
| 多语言文档 | 句子级别 | 依赖语言特性 | 不同语言断句规则不同 |
高级分块策略
父子块分块 (Parent Document Retrieval)
采用两层分块结构:子块(Small Chunk)用于精确检索,父块(Large Chunk) 用于最终上下文注入。检索时先找到相关子块,再召回其所属的父块。
Small Chunk → 精确匹配 → Parent Chunk → 上下文注入
语义分块 (Semantic Chunking)
通过计算相邻句子之间的语义相似度,动态决定断点。当相似度低于阈值时, 触发新的 Chunk。这种方法产生的块大小不均匀,但语义更加连贯。
结构感知分块
利用文档结构信息(Markdown 标题层级、XML 标签、PDF 目录等)指导分块:
- 同一标题下的内容尽可能保持在同一 Chunk
- 代码块、表格作为独立 Chunk 整体保留
- 标题元信息作为 Chunk 的 metadata 存储
Embedding 模型
Embedding 模型是 RAG 系统的核心组件,负责将文本转化为稠密向量。 它的选择直接影响检索质量和最终回答的准确性。
主流 Embedding 模型对比
| 模型 | 维度 | 上下文 | 特点 | 场景 |
|---|---|---|---|---|
| text-embedding-3-large | 3072/256-3072 | 8K | OpenAI 最新,性能优异 | 通用场景 |
| Cohere embed-v3 | 1024/384/256 | 16K | 多语言支持优秀,支持 MATRYOSHKA | 多语言、企业 |
| text-embedding-3-small | 1536/256-1536 | 8K | 性价比高 | 成本敏感场景 |
| BGE-M3 | 1024 | 8K | 开源、多语言能力强 | 开源部署 |
| GTE-large | 1024 | 8K | 开源、中文优化 | 中文场景 |
| E5-Mistral | 1024 | 4K | 高效、微调友好 | 垂直领域 |
维度选择与 MATRYOSHKA 表示
传统观点认为更高的Embedding维度能保留更多信息,但对于实际检索任务, 1024 维度通常已足够。Cohere 提出的 MATRYOSHKA 表示法 允许在不同维度下进行检索(如 1024 → 768 → 512 → 256), 大幅降低存储和计算成本,同时保持可接受的精度。
# 使用 MATRYOSHKA 表示降维示例
original_dim = 1024
target_dim = 256 # 75% 存储节省
# 截断前 256 维即可,无需重新计算
embedding = full_embedding[:target_dim]
Embedding 优化策略
批次处理与向量化加速
批量调用 Embedding API 可大幅提升吞吐量。生产环境中, 建议批次大小设置为 100-500,并发请求数根据 API 限流配置。
Query 预处理
- 去除噪音:移除特殊字符、HTML 标签等
- Query 扩展:对短 query 进行同义词扩展或 HyDE(假设性文档嵌入)
- Query 改写:通过小模型将用户口语化表达转化为检索友好型表述
领域微调
通用 Embedding 在垂直领域(如医疗、法律、工程)表现可能不佳。 通过对比学习微调领域语料,可以显著提升检索精度。 典型微调数据格式:
{
"query": "糖尿病的诊断标准是什么?",
"positive": "根据 WHO 标准,空腹血糖≥7.0mmol/L...",
"negative": "高血糖的饮食注意事项包括..."
}
对于中文 RAG 系统,推荐优先尝试 BGE-M3(开源)或 Cohere embed-v3(商业),两者在中文场景下表现优异。 若有大量英文文档,text-embedding-3-large 是更稳妥的选择。
向量检索
向量检索是 RAG 系统的核心引擎,负责在高维向量空间中快速找到与 Query 最相似的 Top-K 文档。向量数据库的选择需要综合考虑精度、性能、成本和运维复杂度。
向量数据库选型
| 数据库 | 索引算法 | 精度 | QPS (100万向量) | 部署方式 | 适用场景 |
|---|---|---|---|---|---|
| Pinecone | SOTA 专利算法 | 极高 | 1000+ | 全托管 | 企业级 SaaS |
| Milvus | HNSW, IVF, DISKANN | 高 | 500-1000 | 自托管/云 | 大规模自部署 |
| Weaviate | HNSW | 高 | 500-800 | 自托管/云 | GraphQL 生态 |
| Qdrant | HNSW, SCAN | 高 | 600-1000 | 自托管/云 | 高性能需求 |
| pgvector | IVFFlat, HNSW | 中高 | 100-300 | 自托管 | PG 已有团队 |
| Chroma | HNSW | 中 | 50-100 | 嵌入式 | 原型/POC |
索引算法深度解析
HNSW (Hierarchical Navigable Small World)
目前最流行的向量索引算法,采用多层图结构实现近似最近邻搜索:
- 构建阶段:自底向上构建多层结构,上层稀疏下层稠密
- 搜索阶段:从最上层开始贪心搜索,逐层细化
- 复杂度:构建 O(n log n),搜索 O(log n)
- 关键参数:
ef_construction(精度/构建速度)、m(内存/精度权衡)
# HNSW 参数配置示例
{
"ef_construction": 200, # 范围: 100-400, 越大越精确越慢
"M": 16, # 范围: 4-64, 边数,影响内存和精度
"ef_search": 100 # 搜索时动态参数,可调
}
IVF (Inverted File Index)
基于聚类的索引方法,将向量空间划分为 K 个聚类中心,搜索时只扫描 最相关的几个聚类。适合内存受限场景。
DISKANN
微软提出的全内存替代方案,基于图索引设计但优化了磁盘访问模式, 适合 billion 级别向量的单机部署。
向量检索质量指标
- Recall@K:召回率,Top-K 结果中包含真实最近邻的比例
- Latency:P99 延迟,通常需要 < 50ms 以保证用户体验
- Throughput:QPS,取决于硬件和索引配置
- Memory Footprint:索引内存占用,影响部署成本
Top-K 与召回率的平衡
实际生产中,通常设置 top_k 为 50-100,然后在重排阶段
缩减至 5-20 条最终上下文。早期召回更多候选项能显著提升最终精度。
不要将检索的 Top-K 直接送入 LLM。推荐流程: 检索 Top-100 → 重排 → Top-10 → LLM。 重排阶段可以利用更复杂的交互特征,大幅提升最终相关性。
Hybrid Search
纯向量检索在某些场景下存在明显局限:难以处理精确关键词匹配(如人名、 型号代码)、数值范围查询、以及结构化查询条件。Hybrid Search(混合检索) 通过融合向量检索与关键词检索,实现优势互补。
混合检索架构
User Query
│
├──→ Sparse Retrieval (BM25) ──→ Score₁ (0.0-1.0)
│
└──→ Dense Retrieval (Vector) ──→ Score₂ (0.0-1.0)
│
↓
┌───────────────────────┐
│ Score Fusion (RRF) │ ← Reciprocal Rank Fusion
└───────────────────────┘
│
↓
Unified Ranking
稀疏检索:BM25 详解
BM25 (Best Matching 25) 是经典的信息检索算法,基于词频和逆文档频率:
BM25 Score = Σ IDF(t) · (tf(t,d) · (k₁ + 1)) / (tf(t,d) + k₁ · (1 - b + b · |d|/avgdl))
参数:
- k₁: 词频饱和参数 (通常 1.2-2.0)
- b: 文档长度归一化 (通常 0.75)
- IDF: 逆文档频率
- tf: 词频
- |d|: 文档长度
- avgdl: 平均文档长度
分数融合策略
RRF (Reciprocal Rank Fusion)
最常用的融合方法,对不同检索来源的结果按排名进行加权:
RRF(d) = Σ 1 / (k + rank_i(d))
其中 k 通常为 60,rank_i(d) 为文档 d 在第 i 个检索结果中的排名
Score-based 融合
当两个检索来源的分数分布差异较大时,需要先做归一化再融合:
Final Score = α · normalize(BM25_score) + (1-α) · normalize(Vector_score)
α 通常设置为 0.3-0.5,可通过离线评估优化
BM25 与向量的平衡
| 场景 | 推荐权重 | 说明 |
|---|---|---|
| 通用问答 | BM25 30%, Vector 70% | 向量主导,BM25 补充精确匹配 |
| 代码搜索 | BM25 50%, Vector 50% | API 名称、函数名精确匹配很重要 |
| 产品检索 | BM25 40%, Vector 60% | 型号、规格需要精确匹配 |
| 学术论文 | BM25 20%, Vector 80% | 概念语义理解为主 |
实现方案
主流向量数据库均已支持 Hybrid Search:
- Pinecone:内置 Hybrid Search 支持,alpha 参数控制权重
- Weaviate:BM25 + HNSW 原生融合
- Milvus:通过 Hybrid Search 插件实现
- Qdrant:支持 PRECISE 操作符配合向量检索
# Weaviate Hybrid Search 示例
{
"query": "RAG system architecture",
"vectorizer": "text2vec-transformers",
"hybrid": {
"alpha": 0.5, # 0=纯关键词, 1=纯向量, 0.5=平衡
"fusionType": "relativeScoreFusion"
}
}
重排 (Reranking)
Reranking 是 RAG Pipeline 中提升最终效果的关键步骤。 在向量检索(或混合检索)得到候选文档列表后,Reranker 通过更复杂的 交互式语义模型对候选文档与 Query 的相关性进行更精准的排序。
为什么需要 Reranking?
- 向量检索的局限性:双塔模型(Bi-Encoder)预先计算文档向量, 无法捕捉 Query-Document 的交互特征
- Top-K 精度需求:向量检索召回 Top-50 后,Reranker 精筛至 Top-5
- 跨编码器能力:Cross-Encoder 能直接计算 Query 与 Document 的联合语义相似度
Reranker 模型
| 模型 | 类型 | 特点 | 延迟 |
|---|---|---|---|
| Cross-Encoder (BERT-based) | Cross-Encoder | 精度最高,需实时计算 | 高 (50-200ms) |
| Cohere Rerank | 商业 API | 易用,效果好 | 中 (API) |
| Sentence-transformers | Bi-Encoder | 轻量,可本地部署 | 低 |
| monoBERT | Cross-Encoder | 专为排序任务优化 | 高 |
| LLM-as-Reranker | LLM | 精度高,成本高 | 很高 |
Cross-Encoder vs Bi-Encoder
Bi-Encoder(双塔)
- Query 和 Document 独立编码
- 向量预计算,检索快
- 无法建模交互特征
- 适合首次粗筛
Cross-Encoder(交联)
- Query-Document 联合编码
- 实时计算,精度高
- 延迟较高,适合精排
- 适合 Reranking
典型 Reranking Pipeline
Query ──┬──→ Vector Search (Top-100) ──┐
│ │
└──→ BM25 Search (Top-100) ────────┼──→ RRF Fusion (Top-50) ──→ Cross-Encoder Rerank ──→ Top-10 ──→ LLM
│ (精排)
└──→ Vector Search (不同 index) ──┘
Reranking 优化技巧
上下文窗口选择
Reranker 输入通常限制在 512 tokens。若 Chunk 超过此长度, 需要策略性截取:
- 头部截取:取 Chunk 开头部分(通常信息密度最高)
- 尾部截取:取 Chunk 结尾部分(结论性内容)
- 滑动窗口:分段 Rerank 后聚合分数
DocBERT 风格交互
将 Query 作为 Document 的特殊段落插入,利用 BERT 的 [CLS] token 输出做排序分数:
[CLS] + Query + [SEP] + Document + [SEP]
↓
BERT Forward
↓
[CLS] Token Output → Sigmoid → Relevance Score
多样性重排 (MMR-style)
除相关性外,还需考虑结果多样性。通过 Max Marginal Relevance 在相关性与多样性间取得平衡:
MMR Score = α · Relevance(Q, D) - (1-α) · max_{D'∈Selected} Similarity(D, D')
Cross-Encoder 需要对每个 Query-Document Pair 独立前向传播, N 个候选文档意味着 N 次 GPU/CPU 计算。务必控制候选集大小 (通常 50-100),避免 P99 延迟失控。
RAG 评估
RAG 系统的评估是迭代优化的基础。与传统 ML 不同,RAG 评估需要 同时考量 检索质量 与 生成质量 两个维度。
检索评估指标
| 指标 | 定义 | 说明 |
|---|---|---|
| Precision@K | Top-K 中相关文档的比例 | 高 Precision 意味着少噪音 |
| Recall@K | 所有相关文档中被召回的比例 | 高 Recall 意味着少遗漏 |
| MRR | 第一个相关文档的排名倒数均值 | 关注最优结果位置 |
| NDCG@K | 归一化折损累计增益 | 综合考虑排名和相关性权重 |
| Hit Rate | Top-K 包含任意相关文档的比例 | 快速判断系统可用性 |
生成评估指标
RAGAS 框架
RAGAS (Retrieval-Augmented Generation Assessment) 是当前最流行的 RAG 评估框架,从三个维度评估生成质量:
- Faithfulness(忠实度):生成答案与检索上下文的一致程度, 衡量 hallucination 风险
- Answer Relevance(答案相关性):生成答案与原始问题的相关程度
- Context Precision(上下文精确度):检索上下文与问题的相关程度
# RAGAS 评估指标计算
from ragas import evaluate
from ragas.metrics import faithfulness, answer_relevancy, context_precision
result = evaluate(
dataset=test_dataset,
metrics=[faithfulness, answer_relevancy, context_precision]
)
LLM-as-Judge
使用强 LLM(如 GPT-4、Claude-3)对回答质量进行评分。 相比人工评估,成本更低、速度更快,适合迭代测试。
评估 Prompt 示例:
"请评估以下问答对中,AI 助手的回答质量。
考虑因素:
1. 回答是否准确回答了问题
2. 回答是否基于提供的上下文
3. 回答是否完整、无遗漏
评分范围:1-5 分,5 分为最优。
问题:{question}
上下文:{context}
回答:{answer}
评分理由:"
其他生成指标
- BLEU / ROUGE:与参考答案的 n-gram 重叠度, 但不适合开放式生成评估
- BERTScore:基于语义嵌入的评估,更灵活
- Task-Specific Metrics:如问答准确率、摘要质量评分等
端到端评估数据集
| 数据集 | 规模 | 特点 | 适用场景 |
|---|---|---|---|
| NQ (Natural Questions) | 3.6K | Google 真实搜索查询 | 通用 QA |
| TriviaQA | 95K | 百科知识问答 | 事实性问答 |
| PopQA | 14K | 长尾知识问答 | 知识覆盖评估 |
| HotpotQA | 113K | 多跳推理问答 | 推理能力 |
| 2WikiMultiHopQA | 227K | 多跳维基百科问答 | 复杂推理 |
评估最佳实践
1. 分层评估:先评估检索(Recall@K > 0.9),再评估生成
2. Case Analysis:定期抽样式人工审查 Bad Cases
3. A/B Testing:生产环境持续对比不同策略效果
4. 回归测试:每次 Pipeline 修改后运行完整评估套件
生产级实践
企业级 RAG 架构
┌─────────────────────────────────────────────────────────┐
│ RAG System Architecture │
├─────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────────────────┐ │
│ │ Ingest │──▶│ Chunk │──▶│ Embedding Service │ │
│ │ Service │ │ Service │ │ (Batch/Stream) │ │
│ └──────────┘ └──────────┘ └──────────┬───────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ Vector DB │ │
│ │ + Metadata │ │
│ └──────┬───────┘ │
│ │ │
│ ┌────────────────────────────────────────┼────────────┐ │
│ │ Query Pipeline │ │ │
│ │ ┌─────────┐ ┌──────────┐ ┌────────▼───────┐ │ │
│ │ │ Query │──▶│ Router │──▶│ Hybrid Search │ │ │
│ │ │Parsing │ │(Intent) │ │ BM25 + Vector │ │ │
│ │ └─────────┘ └──────────┘ └────────┬────────┘ │ │
│ │ │ │ │
│ │ ┌────────▼────────┐ │ │
│ │ │ Reranker │ │ │
│ │ │(Cross-Encoder) │ │ │
│ │ └────────┬────────┘ │ │
│ │ │ │ │
│ │ ┌────────▼────────┐ │ │
│ │ │ Context │ │ │
│ │ │ Assembly │ │ │
│ │ └────────┬────────┘ │ │
│ └───────────────────────────────────────┼───────────────┘ │
│ │ │
│ ┌──────────▼──────────┐ │
│ │ LLM Gateway │ │
│ │ (Cache/Rate Limit) │ │
│ └──────────┬──────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ Response │ │
│ │ Streaming │ │
│ └──────────────┘ │
└─────────────────────────────────────────────────────────┘
关键工程实践
缓存策略
- Query 缓存:相同/相似 Query 直接返回历史结果
- Embedding 缓存:热门文档的向量预计算并持久化
- LLM 响应缓存:基于 Prompt Hash 的精确缓存
延迟优化
RAG 系统的端到端延迟通常由以下因素决定:
- 向量检索:5-30ms(索引优化、EF 参数调优)
- Reranking:50-200ms(候选集大小、模型选择)
- LLM 生成:500ms-5s(模型、流式输出)
LLM 生成延迟是用户感知最强的环节。务必启用 Streaming 模式, 即使总时间不变,用户感知到的「首字延迟」也会大幅降低。
容错与降级
- 向量检索超时 → 回退至纯 BM25 检索
- Reranking 服务不可用 → 直接使用向量检索 Top-K
- LLM 服务不可用 → 返回预设回复或「当前服务繁忙」
监控与告警
生产环境必须监控的指标:
- 检索召回率(离线评估,定期跑)
- 端到端 P50/P95/P99 延迟
- LLM Token 消耗与成本
- 向量数据库存储增长趋势
- Reranking 质量评分(LLM-as-Judge)
多模态 RAG 扩展
当文档包含图片、表格、PDF 扫描件时,需要额外的处理流程:
- 文档解析:OCR + 布局识别(如 Surya、DocParser)
- 表格处理:表格检测 + 结构化解析(如 TableFormer)
- 图片描述:多模态 LLM 生成图片摘要(如 GPT-4V、Claude)
- 跨模态检索:CLIP 实现图片-文本统一向量空间
总结
RAG 系统架构设计的核心在于对每个环节的深入理解和系统性优化:
Chunk 策略
- 根据文档结构和领域特性选择分块方法
- Chunk Size 需要在语义完整性和检索精度间平衡
- 父子块策略可兼顾精确性和上下文完整性
Embedding
- 选择支持长上下文的现代 Embedding 模型
- 领域微调可显著提升垂直场景效果
- MATRYOSHKA 表示可有效降低存储成本
向量检索
- HNSW 是当前最优的近似最近邻索引
- Top-K 设置要兼顾召回率和后续处理成本
- 向量数据库选型需考虑规模、性能和运维成本
Hybrid Search
- BM25 + Vector 融合可处理精确匹配和语义理解
- RRF 是鲁棒的分数融合方法
- 权重参数需根据场景调优
Reranking
- Cross-Encoder 可显著提升最终相关性排序
- 候选集大小需在精度和延迟间平衡
- 多样化重排可提升结果覆盖率
评估
- 分层评估:先检索后生成
- RAGAS + LLM-as-Judge 是实用的评估组合
- 持续评估是系统迭代优化的基础
RAG 不是一个静态的系统,而是一个需要持续优化的数据 Pipeline。 从 Chunk 策略到最终的用户体验,每个环节都有大量的调优空间。 建议从最小可用系统开始,通过数据驱动的方式逐步迭代,最终构建 满足业务需求的 RAG 系统。
Agentic RAG:让 RAG 系统具备自主规划、工具调用和迭代反思能力
Graph RAG:利用知识图谱增强关系推理和全局理解能力
Self-RAG:通过自适应检索和自我评估提升生成质量