跳转至

RAG · 检索增强生成

Explanation · 原理资深

本页是 RAG 范式 canonical (按 ADR-0006)

本页讲 RAG 算法范式 + 演进路线 · 是 RAG 主题的 canonical 入口。

  • 湖仓上的 RAG 工程实践(5 表架构 / 端到端流水线 / 延迟预算)→ scenarios/rag-on-lake
  • RAG 评估方法(RAGAS / BEIR / 离线 + 在线闭环)→ rag-evaluation
  • 公司切面(Databricks / Snowflake / Netflix 各自 RAG 实现)→ 对应 cases/ 深度页

一句话理解

在生成前先检索把"语料库中最相关的片段"作为上下文塞给 LLM。对抗幻觉、让知识可更新、让企业私有数据可问答的最主流范式。2025 年工业 RAG = Hybrid 召回 + Rerank + Contextual 压缩 + LLM + 引用回写

TL;DR

  • 核心命题:LLM 知识截止 + 私有数据 + 实时更新 → 检索 + 生成
  • 为什么不直接微调:私有数据每天变、微调成本高、易忘记
  • 工业管线chunk → embed → Hybrid 检索 → Rerank → Prompt → LLM → 引用
  • 评估必做RAGAS(faithfulness / relevancy / context precision / context recall)
  • 前沿:Contextual Retrieval(Anthropic)· CRAG · Self-RAG · Agentic RAG
  • 不加 Rerank 是 RAG 第一大死因;其次是 chunk 策略

1. 业务痛点 · LLM 为什么不够用

纯 LLM 的三个天花板

局限 症状
知识截止 "我不知道 2024 年后的事"
私有数据盲区 问不了公司内部文档、代码库
幻觉 瞎编事实、引用不存在的论文
不可追溯 "为什么这么回答?"说不清

微调替代不了 RAG

微调(SFT / LoRA) RAG
适合场景 改变风格、语气、格式 事实、知识、数据
成本 GPU / 训练数据 / 时间 向量库 + LLM 调用
更新成本 每次新数据要重训 增量写向量库
可审计 黑盒 可引用
混合使用 都要 都要

结论:微调调"模型说话方式",RAG 解"给模型什么信息"——两者互补不替代

工业典型场景

场景 RAG 价值
企业客服 / 工单 RAG 后答案可用率显著提升(经验值 · 依基线 / 场景 / 评估标准变化大 · [来源未验证] 通用数字不要直接引用)
代码助手 了解私有代码库
合规 / 法务 强制引用、零幻觉
研究辅助 快速翻遍论文库
运维诊断 从历史故障 + 文档找线索

2. 原理深度 · RAG 工作机制

基础管线(Vanilla RAG)

flowchart LR
  q[用户问题] --> qe[Query Encoder]
  qe --> retrieve[向量库 + BM25<br/>TopN 召回]
  retrieve --> rerank[Cross-Encoder Rerank<br/>TopK]
  rerank --> prompt[拼 Prompt<br/>问题 + 片段]
  prompt --> llm[LLM 生成]
  llm --> ans[答案 + 引用]

  docs[(企业文档<br/>持续更新)] -.-> ingest[Ingest + Chunk + Embed]
  ingest -.-> retrieve

三阶段拆解

阶段 1 · 索引(离线)

文档 → 解析 → Chunk → Embedding → 向量库 / 全文索引

阶段 2 · 检索(在线)

Query → Embed / Tokenize → Hybrid 召回 → Rerank → TopK

阶段 3 · 生成(在线)

Prompt 模板 + TopK Chunks + Query → LLM → 引用式答案

为什么"对抗幻觉"

LLM 在给定上下文后的输出分布会被锚定——token 级别概率大幅向 context 中的事实倾斜。

光给 context 不够,还要: - Prompt 强制要求"只基于引用" - 答案里显式带引用编号 - 无引用时拒答("资料中没找到")

这三件都做到 · 在可控 golden set 上测得的幻觉率能显著下降(典型经验 · 依数据分布 / LLM / 评估定义变化大 · 生产必须自测 · 不要直接套用具体百分比)。

3. 关键机制

机制 1 · Chunk 策略

Chunk 决定召回上限:

策略 适合
定长切分 纯文本、快速起步 简单 切断语义
结构感知 Markdown / HTML / 代码 尊重标题层级 实现复杂
语义切分 长散文 / PDF 语义聚合 耗时、需额外模型
Contextual Chunking 每 chunk 加背景描述 Anthropic 新范式 · 显著减少检索失败率(详见下方 §4 · 不直接引用 recall 数字) 需 LLM 预处理

推荐默认:结构感知 + 长度约束(200-800 tokens)+ 10% overlap

机制 2 · Embedding 选型

详见 Embedding 模型横比。实务: - 私有 + 中文 → BGE-large-zh / multilingual - 多语 → E5-multilingual / Cohere embed-multilingual - 快速起步 → OpenAI text-embedding-3 - 代码 → Voyage AI codeCodeBERT

机制 3 · Hybrid 检索

纯向量不够。工业标配 = BM25 + Dense + RRF 融合

详见 Hybrid Search

机制 4 · Rerank

差异化关键。bge-reranker-v2-large / Cohere Rerank v3.5(2024-12 · 100+ 语言 SOTA)/ Jina Reranker v2。

召回 50-100 → Rerank → Top 5-10。NDCG 提升 5-10 个点。

详见 Rerank

机制 5 · Prompt 构造

经典模板:

你是 XXX 的内部助手。请**仅基于下面的参考资料**回答问题。
若资料不足,请回答"资料中没有找到相关信息"。
每个答案必须带引用编号 [n]。

# 参考资料
[1] {chunks[0].title} ({chunks[0].url})
{chunks[0].content}

[2] {chunks[1].title}
{chunks[1].content}

# 问题
{user_query}

# 你的回答(使用引用格式 [n])

关键技巧: - 最相关 chunk 放 prompt 最后("Lost in the Middle"现象) - 压缩 context(LLMLingua / Contextual Compression)省 token - 引用编号在 prompt 里明确,LLM 更愿意写引用

机制 6 · 引用与溯源

产品化上必须做: - 每个答案带引用编号([1], [2]) - 点击引用 → 跳转原文位置 - 便于人工核查,审计场景刚需

4. 工程细节 · 2024-2025 高级范式

稳定路径 vs 演进跟踪 · 别把"值得了解"误读成"应优先采用"

2026 生产默认路径就是 § 3 基础管线:chunk → Hybrid(BM25+Dense)→ Rerank(v2-m3 / Cohere v3.5)→ Prompt → LLM + 引用。这 5 步做扎实 · 加上 评估 闭环 · 已经能覆盖 80%+ 生产场景

以下范式是演进跟踪 · 按顺序选择性采用 · 不要一上来全部: - ✅ Contextual Retrieval(Anthropic 2024)· 效果确证 · 可优先尝试 - 🟡 CRAG / Self-RAG · 实验验证 · 适合复杂检索可用性不稳定的场景 - 🟡 Agentic RAG · 需 Agent 能力成熟 · 成本显著高 - 🟡 GraphRAG · 综合性查询优势 · 但 10-100× 离线构建成本 - 🟡 Multi-Query / HyDE · query 改写 · 多一次 LLM 调用 - 🟡 ColBERT v2 / Late Interaction · 精度高但存储 10-20× - 🟡 LLMLingua 上下文压缩 · 长文档场景省 60-80% token

Contextual Retrieval(Anthropic 2024)

给每个 chunk 前置补充"这个 chunk 在整份文档中的背景描述"(用 LLM 预处理),embed 整体。

原 chunk: "M 参数默认 16"
Contextual Chunk:
"《HNSW 调优指南》的"参数详解"章节:HNSW 算法中的 M 参数默认 16,
 控制图的邻居数。M 参数默认 16。"

效果(Anthropic 2024 Contextual Retrieval 报告原文解读):检索失败率相对降低 35%(5.7% → 3.7%)· 配合 reranker 后失败率相对降 67%(5.7% → 2.9%)。注意原报告讲的是"失败率降幅"· 不是"recall 绝对提升 35 个百分点"——这两个指标容易混淆。

CRAG (Corrective RAG)

检索 → 对检索质量打分
    低质量 → 触发 Web 搜索 / 其他 fallback
    高质量 → 直接用
    中等 → 过滤 + 重检索

Self-RAG

模型自己决定: - 是否需要检索(有些问题不需要) - 检索到的片段是否相关 - 生成的答案是否 grounded

Agentic RAG

  • 把 RAG 当成 Agent 的一个 Tool
  • Agent 可以决定 多轮检索(多 hop reasoning)
  • 结合其他工具(SQL / 代码执行 / API)

详见 Agent Patterns 机制 · Agentic Workflows 场景。

GraphRAG · 知识图谱增强(2024-2026)

Vector RAG 的极限:无法处理"跨多个 chunk 的综合性问题"(如 "介绍我们公司所有主要竞争对手及其核心产品")· 因为 vector 召回是"点对点相关" · 不理解实体之间关系。

GraphRAG 思路(Microsoft 2024-07 开源): 1. 离线:从语料库抽取实体 + 关系 → 构建 知识图谱(Neo4j / 自建 graph) 2. 离线:对图做 社区检测(Louvain / Leiden)· 每个社区生成 summary 3. 在线:Query 时两阶段 - 找相关社区 summary(回答综合性问题) - 找相关实体 + 关系(回答具体细节) 4. 组合 context 给 LLM

用户:"我们团队 2025 年的主要技术挑战"
Vector RAG: 找相关 chunk → 碎片化
GraphRAG:
  1. 相关社区 = [性能优化社区、AI 集成社区、合规社区]
  2. 每个社区的 summary 作为 context
  3. LLM 综合归纳 → 完整回答

代表方案: - Microsoft GraphRAG(2024-07 开源 · 2025 进入 Azure AI Foundry)· 完整工程实现 - LightRAG(2024 · 香港大学)· 更轻量 · dual-level retrieval - LlamaIndex KnowledgeGraphIndex · 嵌入式图谱构建 - Neo4j + LLM · 商业图数据库 + Cypher 查询

成本: - 离线构建:10-100× 于 vector RAG 的 embedding 成本(大量 LLM 调用做实体抽取 + 社区 summary) - 在线查询:和 vector RAG 相当 · 甚至更快(社区 summary 是预算好的 context)

何时用 GraphRAG: - ✅ 综合性 / 主题性查询("主要 / 所有 / 对比") - ✅ 关系复杂的领域(法律 / 学术文献 / 企业组织 / 医药) - ✅ 可接受 10-100× 离线成本换取质量跃升 - ❌ 简单事实问答 · vector RAG 足够 - ❌ 语料频繁变化 · 图谱重建成本高 - ❌ 小规模(< 10k 文档)· 建图 ROI 不划算

2026 状态:采用率快速上升但仍非主流 · Microsoft / 企业 KG 场景领先 · 是 Vector RAG 的补充不是替代。

Query 改写 · Multi-Query / HyDE

Multi-Query:LLM 把原 query 改写成 N 个变体并行检索 · 结果用 RRF 融合。

Query: "怎么提升 RAG 的 recall"
  ↓ LLM 改写
  - "如何优化 RAG 检索的召回率"
  - "Hybrid search 怎么提升 recall"
  - "Rerank 对 RAG 效果的影响"
  ↓ 并行检索 + RRF 融合

HyDE (Hypothetical Document Embeddings · Gao et al. 2022):先让 LLM 生成"假设答案"· 用假设答案的 embedding 检索 · 直觉是假设答案和真实文档分布接近。

评价: - ✅ LlamaIndex / LangChain 原生支持 · 集成成本低 - 🟡 Multi-Query 在 recall 受限场景(query 歧义 / 多角度)有效 · 典型提升 5-8% - 🟡 HyDE 在 factoid 问题上有效 · 探索性 / 开放式问题可能误导(假设答案错会偏 · 实测常 < 5%) - ❌ 两者都多一次 LLM 调用 · 延迟 + 成本上升 · 先测基线是否真缺 recall 再引入

ColBERT v2 · Late Interaction

核心思想:每个 token 保留独立向量 · 检索时 query × doc token 级 MaxSim 聚合 · 不是单向量压成一个。

query tokens × doc tokens → max-sim 矩阵 → 相关性

评价: - ✅ 精度接近 Cross-Encoder Rerank · 延迟显著低于 rerank - ❌ 存储成本 10-20× 于普通 dense · 规模上不去(百万 doc 级别尚可 · 亿级不现实) - 🟡 适合重精度轻规模场景(代码助手 / 文档图像 retrieval 即 ColPali / 领域精搜) - 详细 late-interaction 机制见 retrieval/multimodal-retrieval-patterns Pattern E

Contextual Compression · LLMLingua

用小模型压缩 retrieved contexts · 减少输入给主 LLM 的 token 数:

100 chunk (100k token)
  ↓ Small LLM (LLMLingua / LongLLMLingua)
50 高密度 chunk (30k token)
  ↓ 主 LLM 生成

效果:Token 成本降 60-80% · 质量下降 < 5%(原文报告 · 自家数据需实测)· 长文档场景 ROI 显著。

§4 小结 · 现实检视 · 已验证 vs 仅论文

已在工业规模验证(可上): - Hybrid Search(BM25 + Dense + RRF)· Cross-Encoder Rerank · Contextual Retrieval —— 2025 "新 baseline"

论文好 / 工业复现有限: - CRAG · Self-RAG · Agentic RAG · HyDE —— 自家数据实测再决定

学术信号 / 规模限制: - ColBERT v2 · LLM-as-Reranker · Self-RAG 需 fine-tune —— 特定场景有效

坏信号识别: - 论文报告 NDCG +20% 但没提推理成本 → 警惕 - 只在 Wikipedia / 新闻上验证 → 企业闭域可能失效 - "我们用 XXX 做到 95% 准确率"但不说 baseline → 几乎无信息

5. 性能数字 · 评估指标

离线评估

指标 工具 典型基线
Retrieval Recall@10 BEIR / 自建 0.60-0.80
NDCG@10 BEIR 0.50-0.65
Faithfulness(答案忠于 context) RAGAS / TruLens > 0.90
Answer Relevance RAGAS > 0.85
Context Precision RAGAS > 0.80

在线评估

  • 用户点赞 / 点踩率(生产必收集)
  • Follow-up 率(问了又问 = 没答好)
  • 解决率(客服场景)
  • 平均引用数(太少 = 幻觉风险)

延迟分解

用户输入 → 答案 p95 < 1.5s 的打法:
  50ms  Query embedding
  150ms Hybrid retrieve
  100ms Rerank
  400ms Prompt + LLM 首 token
 1200ms LLM 流式完成
  100ms 日志落表 (async)
  ───────
 1.5s

6. 代码示例

最小 LlamaIndex RAG

from llama_index.core import VectorStoreIndex, SimpleDirectoryReader

docs = SimpleDirectoryReader("data/").load_data()
index = VectorStoreIndex.from_documents(docs)

query_engine = index.as_query_engine(similarity_top_k=10)
response = query_engine.query("HNSW 的 M 参数如何调优?")
print(response)
print(response.source_nodes)  # 引用

LanceDB + BGE Embedding + bge-reranker Hybrid

import lancedb
from FlagEmbedding import FlagModel, FlagReranker

embed_model = FlagModel('BAAI/bge-large-zh')
reranker    = FlagReranker('BAAI/bge-reranker-v2-m3')  # 推 v2 · v1 已被超越

db = lancedb.connect("s3://lake/lancedb")
table = db.open_table("docs")

def rag_answer(query: str) -> str:
    # 1. Hybrid 召回
    q_vec = embed_model.encode(query)
    candidates = (table.search(q_vec, query_type="hybrid")
                       .text(query)
                       .limit(50)
                       .to_list())

    # 2. Rerank
    pairs = [[query, c["content"]] for c in candidates]
    scores = reranker.compute_score(pairs)
    top_k = sorted(zip(candidates, scores), key=lambda x: -x[1])[:10]

    # 3. LLM
    context = "\n\n".join(
        f"[{i+1}] {c['title']} ({c['url']})\n{c['content']}"
        for i, (c, _) in enumerate(top_k)
    )
    prompt = f"""仅基于以下资料回答,每段答案带引用 [n]。
# 资料
{context}
# 问题
{query}
# 答案
"""
    return llm.generate(prompt)

RAGAS 评估

from ragas import evaluate
from ragas.metrics import faithfulness, answer_relevancy, context_precision, context_recall

ds = Dataset.from_dict({
    "question": [...],
    "answer": [...],
    "contexts": [...],
    "ground_truth": [...],
})

result = evaluate(ds, metrics=[faithfulness, answer_relevancy, context_precision, context_recall])
print(result)

7. 陷阱与反模式

  • 不加 Rerank:RAG 效果失败 #1 原因
  • 定长 512 tokens 切分走天下:代码 / 表格 / PDF 效果崩
  • Embedding 和 query 侧不一致:库用 BGE 查用 OpenAI → 分布不同
  • 没做 Evaluation:改一版就上线 → 盲飞;RAGAS 是最低配
  • 幻觉不管:LLM 会编事实 → 强制引用 + 引用不足拒答
  • 权限在 Prompt 里:一定被绕过 → 向量库侧 metadata filter
  • Context 塞满:Token 预算爆、"Lost in the Middle"、成本高
  • 一次检索打天下:复杂问题要多跳检索(Agentic / CRAG / Self-RAG)
  • 没有降级:向量库挂了全站挂 → BM25 / 规则兜底
  • 成本失控:LLM 调用没限流 / 没缓存 → 每月 $ 炸
  • Chunk 不带元信息:丢了 source / url / tag → 无法引用、无法过滤

8. 横向对比 · 延伸阅读

权威阅读

相关