RAG 优化(Retrieval-Augmented Generation 检索增强生成)

RAG 是让大模型先检索、再回答的范式:用用户问题去知识库里召回相关片段,拼进上下文让模型基于”查到的证据”作答,从而缓解幻觉、注入私域/时效知识。RAG 优化就是系统性提升”召回准不准、拼得对不对、答得实不实”。

一句话类比:RAG 像开卷考试——你不让模型凭记忆硬答,而是先翻书(检索)找到对应页(相关片段),把书页摊在眼前(拼进 context)再写答案。优化 RAG,就是优化”翻书快不快、翻得准不准、摊开的那页是不是真相关”。

关联:检索靠 Embedding(把文本变成可比较的向量),见 embedding_model.md;长文档要先切成块再索引,切块逻辑见 token.md 的 Text Splitter。RAG 是”给模型灌知识”的推荐方式,优于用 SFT 硬塞,见 sft.md

1. 为什么需要它:模型记不住、也会编

基座/Instruct 模型的知识停在训练 cutoff,且易幻觉(编出看似合理但错误的内容)。直接把全部知识塞进模型(SFT)既不经济又易忘。RAG 把”知识”放在外部知识库,推理时按需检索,模型只负责”基于证据作答”——知识可更新、可溯源、成本低。

用户问题
   │
   ▼ Query 编码(同款 Embedding)
知识库(切块 + 向量化建索引)
   │ 相似度检索
   ▼ 召回 Top-K 相关片段
拼进 Prompt: [问题 + 检索到的证据]
   │
   ▼ 模型基于证据生成答案(带引用更佳)

2. 核心优化杠杆

杠杆在哪一环解决什么
切块策略 (Chunking)索引前块太大噪声多、太小丢上下文;按语义/标题/重叠滑动窗口切
Embedding 质量检索向量好坏直接决定召回上限;领域数据可微调 embedding
混合检索 (Hybrid)检索稠密向量漏掉关键词 → BM25 稀疏检索补,二者融合
重排 (Rerank)检索后用 cross-encoder 对候选精排,把最相关顶到前面
Query 改写/扩展检索前用户问法口语化 → 改写/拆子问题,提升命中
元数据过滤检索先按时间/来源/权限筛,再向量检索,缩小范围
上下文压缩拼装冗余片段挤占窗口 → 摘要/裁剪后再拼

3. 关键技巧详解

  • 混合检索(BM25 + 向量):向量检索擅长语义近义(“怎么让模型不乱说” ↔ “降低幻觉”),但漏精确关键词(型号/专有名词);BM25 补关键词命中。融合常用 RRF(Reciprocal Rank Fusion) 把两套排序合并。
  • 重排(Reranker):第一步用便宜的向量检索召回 2050 个,第二步用更大的 cross-encoder 对这少量候选逐对打分重排,取 Top-35 进上下文。性价比最高的”召回→精排”两段式。
  • Query 改写:把”它和上个比咋样”改写成含实体名的完整问句;多跳问题拆成子问题分别检索(见 agent.md 的多步推理)。
  • Chunk 重叠:相邻块留 10~20% 重叠,避免一句话被切断导致检索不到。

4. 基本用法(两段式检索 + 重排示意)

# 伪代码:Hybrid 召回 + Rerank 的骨架
query_vec = embed(query)                     # 同款 embedding
 
# ① 稠密:向量库 ANN 检索(见 embedding_model.md 的 ANN)
dense_hits = vector_db.search(query_vec, top_k=30)
# ② 稀疏:BM25 关键词检索
sparse_hits = bm25.search(query, top_k=30)
# ③ 融合(RRF)
merged = reciprocal_rank_fusion(dense_hits, sparse_hits, k=60)
 
# ④ 重排:用 cross-encoder 对候选精排
reranked = cross_encoder.rerank(query, merged[:30])   # 只重排少量候选,省算力
top_chunks = reranked[:5]
 
# ⑤ 拼进 prompt 交给模型
prompt = f"根据以下资料回答问题:\n{top_chunks}\n\n问题:{query}"
answer = llm(prompt)

评测不能只看”答案像不像”,要用 检索指标(Recall@K、MRR) + 生成指标( faithfulness 忠实度、答案正确性) 分开看,定位是”没召回到”还是”召回到但没用好”。

5. 典型工作流

  1. 文档清洗 → 切块(带重叠、带元数据)→ 向量化建索引。
  2. 检索:混合检索召回 → Reranker 精排 → 元数据/权限过滤。
  3. 拼装:把 Top 片段 + 问题 + 指令(“只基于资料、注明出处”)组成 prompt。
  4. 生成 + 评测;迭代切块大小、embedding、重排模型、query 改写。

6. 常见误区

  • ❌ “embedding 一选就完事” → 检索上限由 embedding 决定;领域性强时要换/微调 embedding,否则后面再怎么重排都救不回烂召回。
  • ❌ “块切得越小越准” → 太小丢失上下文、语义断裂;太大噪声多。要按文档结构(段落/标题)切并留重叠。
  • ❌ “只靠向量检索够了” → 专有名词/型号靠 BM25 才稳,混合检索几乎是标配。
  • ❌ “召回越多越好” → 塞太多无关片段会污染上下文、挤占窗口、诱发幻觉;重排 + 截断到真正相关的少数几段更关键。
  • ❌ “RAG 能根治幻觉” → RAG 大幅降低幻觉,但若检索不到/拼错,模型仍可能编;要加”无证据就拒答”的指令与引用机制。

7. 延伸阅读 / 关联概念

  • Embedding 模型 — 检索的向量基础、ANN、幻觉对照;见 embedding_model.md
  • Token / Text Splitter — 切块即索引前预处理;见 token.md
  • SFT — “灌知识靠 RAG 而非微调”的对照;见 sft.md
  • Agent / 多步推理 — 多跳检索可交给 Agent 拆解子问题;见 agent.md
  • 上下文工程 — 召回片段如何排列压缩进上下文;见 context_engineering.md