返回AI笔记
AI Day 20

AI Day 20: 生产级RAG(2):检索优化与Reranking — 找到最相关的信息

检索优化与Reranking是生产级RAG系统的"精准定位引擎"——昨天我们解决了"数据怎么准备"(解析+Chunking),今天解决"数据怎么找到"。核心问题是:面对百万级Chunks,如何在毫秒内从中精确找到回答用户问题最需要的那5-10个片段。这不是简单的向量相似度搜索,而是一个多阶段、多策略的信息精炼流程——从Query理解、粗筛召回、精排重排到上下文组装,每一步都有巨大优化空间。

2026-04-21
RetrievalRerankingCross-EncoderHyDEQueryMulti-QuerySelf-RAGCorrectiveColBERTRAPTORNDCGRecall@KContextLost-in-the-Middle

日期:2026-04-21 阶段:第二阶段 — 工程实践 (Day 16-30) 标签Retrieval Optimization Reranking Cross-Encoder HyDE Query Rewriting Multi-Query Self-RAG Corrective RAG ColBERT RAPTOR NDCG Recall@K Context Assembly Lost-in-the-Middle


学习路径树

AI/LLM 深度技术学习 50天计划
├── 第一阶段:模型基础 (Day 1-15) ✅
│   ├── Day 1:  Transformer架构与LLM基础 ✅
│   ├── Day 2:  模型量化与本地部署 ✅
│   ├── Day 3:  训练过程深度:Pre-training / SFT / RLHF / DPO ✅
│   ├── Day 4:  Prompt Engineering与上下文学习(ICL)原理 ✅
│   ├── Day 5:  RAG架构:检索增强生成全链路 ✅
│   ├── Day 6:  向量数据库与Embedding模型 ✅
│   ├── Day 7:  Fine-tuning实战:LoRA / QLoRA / Adapter ✅
│   ├── Day 8:  推理优化:vLLM / TensorRT-LLM / SGLang ✅
│   ├── Day 9:  长上下文技术:RoPE扩展 / Ring Attention ✅
│   ├── Day 10: 多模态模型:Vision-Language架构 ✅
│   ├── Day 11: Reasoning模型:CoT / o1 / R1 / Extended Thinking ✅
│   ├── Day 12: Agent框架:ReAct / Tool Use / Planning ✅
│   ├── Day 13: MCP协议与Tool生态 ✅
│   ├── Day 14: 模型评估:Benchmark / Arena / 安全评估 ✅
│   └── Day 15: 阶段复习与架构总结 ✅
│
├── 第二阶段:工程实践 (Day 16-30)
│   ├── Day 16: LLM应用架构设计 — API Gateway/路由/缓存 ✅
│   ├── Day 17: LLM安全与Guardrails — 生产环境防护体系 ✅
│   ├── Day 18: LLM可观测性 — 日志/Tracing/指标/告警 ✅
│   ├── Day 19: 生产级RAG(1) — 文档解析与Chunking工程 ✅
│   ├── Day 20: 生产级RAG(2) — Retrieval优化与Reranking ← 你在这里
│   ├── Day 21: 生产级RAG(3) — 评估框架与持续迭代
│   ├── Day 22-25: Agent系统工程化(状态管理/错误恢复/成本控制)
│   └── Day 26-30: 多模型编排/部署策略/端到端项目
│
├── 第三阶段:金融零售AI应用 (Day 31-42)
│   ├── Day 31-35: 金融AI(风控模型/智能投顾/合规/反欺诈)
│   ├── Day 36-40: 零售AI(推荐系统/智能客服/供应链预测/营销)
│   └── Day 41-42: CeFi x DeFi x AI融合架构
│
└── 第四阶段:面试冲刺 (Day 43-50)
    ├── Day 43-46: 系统设计面试(LLM平台/RAG/Agent/推荐)
    ├── Day 47-49: 产品/架构面试模拟
    └── Day 50: 总结与作品集

核心概念

一句话定义

检索优化与Reranking是生产级RAG系统的"精准定位引擎"——昨天我们解决了"数据怎么准备"(解析+Chunking),今天解决"数据怎么找到"。核心问题是:面对百万级Chunks,如何在毫秒内从中精确找到回答用户问题最需要的那5-10个片段。这不是简单的向量相似度搜索,而是一个多阶段、多策略的信息精炼流程——从Query理解、粗筛召回、精排重排到上下文组装,每一步都有巨大优化空间。

金融类比

检索优化 = 投研分析师的信息筛选能力 —— 不是读更多报告,而是更快找到关键段落

投研分析师工作流:                            RAG检索Pipeline:
├── 理解问题                                 ├── Query理解与转换
│   ├── 基金经理问"看好新能源吗?"           │   ├── 用户问"ETH质押收益怎样?"
│   ├── 分析师解读: 要看政策+产能+估值        │   ├── Query Rewriting: 拆解成多个子问题
│   ├── 扩展关键词: 光伏/锂电/风电/储能       │   ├── Multi-Query: ETH staking APY + 验证者收益 + LST对比
│   └── 明确范围: 2025年Q3、A股+港股          │   └── 明确检索范围: 最新数据 + 技术文档 + 市场分析
│                                            │
├── 粗筛(Retrieval)                          ├── 初始检索(Recall Stage)
│   ├── 先筛行业报告库: 100份相关报告         │   ├── 向量搜索 + BM25混合: 召回100个Chunks
│   ├── 按标题/关键词快速过滤                  │   ├── 按相似度分数初步排序
│   └── 形成"待精读"清单                      │   └── 形成"候选集"
│                                            │
├── 精排(Reranking)                          ├── Reranking(精排)
│   ├── 逐篇快速浏览: 看摘要、看结论          │   ├── Cross-Encoder逐对打分
│   ├── 按相关性重新排序                       │   ├── 按Query-Chunk对的相关性精确排序
│   ├── 丢掉明显离题的(新能源车→电动自行车)    │   ├── 过滤掉低于阈值的Chunks
│   └── 精选10篇核心报告                      │   └── 精选Top-10最相关Chunks
│                                            │
├── 组装(Context Assembly)                   ├── 上下文组装
│   ├── 提取关键数据点: 估值、产能、政策       │   ├── 按逻辑排序、去重
│   ├── 按逻辑组织: 政策→供需→估值→结论       │   ├── 压缩冗余信息
│   ├── 控制篇幅: 基金经理没耐心看50页         │   ├── 控制Token预算: LLM上下文窗口有限
│   └── 标注出处: 每个数据的来源               │   └── 保留出处: 每个Chunk的来源信息
│                                            │
└── 核心: 好分析师不是读最多报告的            └── 核心: 好检索不是召回最多的
    而是最快找到关键信息的                        而是最精准找到相关信息的
    → 信息过载反而降低决策质量                    → 塞太多无关Context反而干扰生成
    → 100份报告中找到5个关键段落 >> 读完100份     → 100个Chunks中精选5个 >> 把100个都塞给LLM

连接Day 19

Day 19学的Day 20补充的
文档解析:把PDF/Word变成干净文本Query理解:把用户问题变成好的检索请求
Chunking:把文本切成语义片段Retrieval:从百万Chunks中召回候选集
质量门控:确保Chunk可用Reranking:对候选集精确排序
索引入库:存进向量数据库Context Assembly:组装最终上下文

Day 19决定了RAG的上限(数据质量),Day 20决定了能接近这个上限的程度(检索精度)。两者缺一不可。


知识点1: 检索Pipeline完整设计

端到端检索流程

用户原始Query
    │
    ▼
┌─────────────────┐
│  Query理解与转换  │  ← Step 1: 把"模糊的人话"变成"精确的检索意图"
│  (Query Understanding)
│  ├── Intent分类
│  ├── Query Rewriting
│  ├── Query Expansion
│  └── Query Decomposition
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│  多路召回        │  ← Step 2: "广撒网"——宁可多召回,不可漏掉
│  (Multi-path Retrieval)
│  ├── Dense Retrieval (向量搜索)
│  ├── Sparse Retrieval (BM25/TF-IDF)
│  ├── Structured Search (Metadata过滤)
│  └── Knowledge Graph (实体关联)
└────────┬────────┘
         │  候选集: 50-200 Chunks
         ▼
┌─────────────────┐
│  Reranking精排   │  ← Step 3: "精准狙击"——从候选中找最相关的
│  ├── Cross-Encoder打分
│  ├── 分数阈值过滤
│  └── 多样性控制 (MMR)
└────────┬────────┘
         │  精排结果: 5-15 Chunks
         ▼
┌─────────────────┐
│  Context组装     │  ← Step 4: "装弹"——把精选Chunks组织成LLM友好的上下文
│  ├── 去重合并
│  ├── 逻辑排序
│  ├── Token预算分配
│  └── 压缩(可选)
└────────┬────────┘
         │  结构化上下文
         ▼
┌─────────────────┐
│  LLM生成        │  ← Step 5: "开枪"——基于精准上下文生成回答
│  ├── System Prompt + Context + Query
│  ├── Citation生成
│  └── 置信度评估
└─────────────────┘

每一步的优化杠杆

步骤常见问题优化方向效果量级
Query理解用户问题模糊/歧义HyDE/Multi-Query/Decomposition+15-30% Recall
多路召回向量搜索遗漏关键词匹配Hybrid Search (Dense+Sparse)+10-20% Recall
Reranking召回的Top-K不是真正最相关的Cross-Encoder重排序+10-25% Precision
Context组装无关信息干扰/重复/超长压缩+去重+Token预算管理+5-15% Answer Quality
LLM生成幻觉/不引用来源更好的Prompt/Citation约束+5-10% Faithfulness

经验法则:优化顺序

如果你的RAG效果不好,按这个顺序排查(投入产出比从高到低):

1. 检查Chunking质量 (Day 19)     → 数据本身有问题?修数据
2. 改进Query理解                   → 用户问题没被正确理解?做Query转换
3. 加Reranking                    → 召回的不够相关?加Cross-Encoder
4. 上Hybrid Search                → 关键词匹配漏了?加BM25
5. 优化Context Assembly            → 上下文太冗余?做压缩/去重
6. 调整LLM Prompt                 → 生成格式不对?改Prompt模板

80%的RAG问题出在前3步。
别一上来就换大模型——那是最后的手段。

知识点2: Query理解与转换

为什么原始Query往往不适合直接检索

用户实际提问:                         检索系统的困境:
"ETH最近怎么样?"                     → "怎么样"是什么意思?价格?技术?生态?
"DeFi借贷安全吗?"                    → "安全"指合约安全?资金安全?监管风险?
"帮我对比一下L2"                      → 对比什么维度?哪些L2?哪个时间段?
"上次那个攻击事件后果如何?"            → "上次"是什么时候?"那个"是哪个?

核心矛盾:
  用户用自然语言提问(模糊、简略、有上下文依赖)
  检索系统需要精确的语义匹配(明确、具体、自包含)

五大Query转换策略

策略1: Query Rewriting (查询改写)

原理: 用LLM把用户的口语化/模糊查询改写成更适合检索的形式

原始Query: "ETH质押划算吗"
改写后:    "以太坊ETH Staking质押收益率APY与风险分析"

原始Query: "那个被黑的桥"
改写后:    "跨链桥安全事件黑客攻击案例"

实现:
  System: "你是一个搜索查询优化助手。将用户的口语化问题改写为
           更适合在知识库中检索的查询。保持原意,增加相关术语,
           去除口语化表达。只输出改写后的查询,不要解释。"
  User:   "{original_query}"

金融场景示例:
  原始: "理财产品靠谱吗"
  改写: "银行理财产品风险等级评估收益率对比安全性分析"

成本: 1次LLM调用 (约$0.001-0.01)
延迟: +200-500ms
效果: Recall提升10-20%,尤其对口语化查询效果显著

策略2: HyDE (Hypothetical Document Embeddings)

原理: 让LLM先生成一个"假设性的理想答案",然后用这个答案去做向量检索
      (不是用Query去搜,而是用"理想答案"去搜,因为答案和文档更相似)

为什么有效?
  Query: "什么是无常损失"        ← 短、抽象
  文档:  "无常损失(Impermanent  ← 长、详细、包含解释
         Loss)是指当LP提供流动
         性时,由于价格波动导致
         的价值损失..."

  Query和文档的语义"距离"很远
  但如果我们先生成一个假设答案,它和文档的语义就很近

流程:
  Step 1: LLM生成假设答案
    Query: "什么是无常损失"
    HyDE:  "无常损失是去中心化交易所(DEX)中流动性提供者(LP)
            面临的一种风险。当LP存入代币对到AMM池中后,如果
            代币价格发生变化,LP取出时的资产价值可能低于
            直接持有。这种损失称为无常损失,因为如果价格
            恢复,损失会消失..."

  Step 2: 用HyDE假设答案做Embedding检索
    → 比用原始Query检索,Recall提升15-30%

注意:
  - HyDE增加了一次LLM调用(延迟+成本)
  - 如果LLM对该领域完全不了解,假设答案可能误导检索
  - 最适合: 知识密集型、LLM有基础认知的领域(金融/法律/医疗)
  - 不适合: 实时数据查询、LLM完全不了解的私有知识

策略3: Multi-Query (多查询扩展)

原理: 从不同角度重述用户问题,每个角度各做一次检索,合并结果

Query: "DeFi借贷风险有哪些?"
扩展为:
  Q1: "DeFi借贷协议智能合约安全漏洞风险"     → 技术风险角度
  Q2: "DeFi超额抵押借贷清算机制与系统性风险"   → 金融风险角度
  Q3: "Aave Compound借贷协议预言机操纵攻击"   → 具体案例角度

每个Q分别检索Top-20 → 合并去重 → 得到更全面的候选集

实现(LangChain MultiQueryRetriever):
  # LLM生成3-5个变体查询
  # 每个变体做独立检索
  # 合并+去重候选Chunks
  # 送入Reranker精排

优势: 显著提高Recall(从不同角度覆盖)
劣势: 3-5倍的检索延迟和成本
适用: 复杂问题、研究性查询、允许更高延迟的场景

策略4: Step-Back Prompting (后退一步提问)

原理: 先问一个更抽象/更高层的问题,用其结果补充上下文

Query: "Uniswap V3的集中流动性LP无常损失比V2大还是小?"
       → 这是一个非常具体的问题,直接检索可能找不到精确答案

Step-Back: "Uniswap V3集中流动性机制原理是什么?"
           → 更通用的问题,更容易检索到相关文档

流程:
  1. LLM生成Step-Back问题
  2. 检索Step-Back问题的结果(提供背景知识)
  3. 检索原始问题的结果(提供具体信息)
  4. 合并两个检索结果作为Context
  5. LLM基于完整上下文回答原始问题

金融场景:
  原始: "2025年Q3巴塞尔III最终规则对中小银行资本充足率影响多大?"
  Step-Back: "巴塞尔III最终规则(Basel III Endgame)主要变化有哪些?"
  → 先理解框架,再回答具体问题

策略5: Query Decomposition (子问题分解)

原理: 把复杂问题拆解成多个简单子问题,分别检索后综合回答

Query: "对比Aave和Compound的利率模型、治理机制和安全记录"

分解为:
  Sub-Q1: "Aave的利率模型如何运作?"
  Sub-Q2: "Compound的利率模型如何运作?"
  Sub-Q3: "Aave的DAO治理机制设计"
  Sub-Q4: "Compound的治理机制设计"
  Sub-Q5: "Aave历史安全事件与审计记录"
  Sub-Q6: "Compound历史安全事件与审计记录"

每个子问题独立检索 → 分别获取最相关Chunks → 合并组装

优势:
  - 复杂问题分而治之,每个子问题检索更精准
  - 最终回答更结构化、更全面
  - 适合对比类、多维度分析类问题

劣势:
  - 延迟显著增加(N个子问题 = N次检索)
  - 需要LLM分解问题(可能分解不当)

最佳实践:
  - 只对复杂问题使用(简单问题别过度分解)
  - 限制子问题数量(3-6个)
  - 分解后做合并去重,避免重复Chunks

Query转换策略选择决策树

用户Query进入
    │
    ├── 问题是否模糊/口语化?
    │   └── 是 → Query Rewriting (低成本高回报)
    │
    ├── 问题是否需要深度知识检索?
    │   └── 是 → HyDE (用假设答案增强语义匹配)
    │
    ├── 问题是否有多个角度/维度?
    │   └── 是 → Multi-Query (多角度覆盖)
    │
    ├── 问题是否过于具体/专业?
    │   └── 是 → Step-Back (先获取背景知识)
    │
    └── 问题是否包含多个子问题?
        └── 是 → Query Decomposition (分而治之)

注意: 策略可以组合使用
  例: Query Rewriting → Multi-Query → Hybrid Search → Reranking
  但每增加一步都增加延迟和成本,需要在质量和性能间权衡

知识点3: Reranking深度

为什么需要Reranking

向量检索(Bi-Encoder)的局限:

原理: Query和Document分别编码为向量,用余弦相似度匹配
  Query  → Encoder → q_vec ─┐
                              ├── cosine_sim(q_vec, d_vec) = score
  Doc    → Encoder → d_vec ─┘

问题:
  1. 信息压缩损失: 一段500字文本压缩到768维向量,必然丢失细节
  2. 独立编码: Query和Doc分别编码,没有交叉注意力(Cross-Attention)
  3. 语义近≠问答相关: "以太坊Gas费为什么高"和"以太坊Gas费降低方案"
     语义相似但一个是问原因一个是讲解决方案

Reranker(Cross-Encoder)的优势:

原理: Query和Document拼接后一起送入模型,有完整的交叉注意力
  [CLS] Query [SEP] Document [SEP] → Cross-Encoder → relevance_score

  Query和Document的每个token可以互相attention
  → 能理解"Query问的是X,Document回答的恰好是X"
  → 比向量点积精确得多

代价:
  - 不能预计算(每次都要Query+Doc一起过模型)
  - 速度慢: 1M文档全部Rerank需要数小时
  - 所以只能在粗筛后对Top-50~200做Rerank

Bi-Encoder vs Cross-Encoder 详细对比

维度Bi-Encoder (向量检索)Cross-Encoder (Reranker)
编码方式Query和Doc分别编码Query+Doc拼接后联合编码
交互方式无交互,仅向量点积/余弦完整Cross-Attention交互
精度中等(压缩损失)高(保留完整语义交互)
速度极快(毫秒级,ANN索引)慢(每对需要单独推理)
可扩展性百万/亿级文档仅适合Top-50~200
预计算可以(Document向量提前算好)不可以(依赖Query)
适合阶段粗筛(Recall)精排(Precision)
模型大小通常110M-330M参数通常110M-560M参数

主流Reranker对比 (2025-2026)

Reranker类型大小特点适用场景
Cohere Rerank 3.5API服务闭源最高精度、多语言支持、简单易用预算充足的生产环境
BGE-Reranker-v2-m3开源Cross-Encoder568MBAAI开源、多语言、中文优秀自部署、中文场景、隐私敏感
Jina Reranker v2API+开源137M/278M轻量高效、多语言、长文档支持8K需要长文档Rerank
FlashRank开源轻量20-60M极小极快、CPU可运行、适合边缘低延迟要求、资源受限
ColBERT v2Late Interaction110MToken级交互、可预计算、精度高需要速度和精度平衡
RankLLM/RankGPTLLM-as-Reranker7B-70B用LLM做Rerank、零样本泛化强冷启动、无训练数据
MixedBread mxbai-rerank开源Cross-Encoder330M2025新锐、英文性能强英文为主场景

金融场景Reranker选型建议

场景1: 银行内部知识库(合规要求,不能出云)
  → BGE-Reranker-v2-m3 自部署
  → 理由: 中文效果好、开源可审计、数据不出内网

场景2: DeFi分析助手(面向用户,需要低延迟)
  → Cohere Rerank API + 本地缓存
  → 理由: 精度最高、延迟可接受(50-100ms)、多语言
  → 备选: Jina Reranker(更便宜)

场景3: 嵌入式钱包安全检测(端侧运行)
  → FlashRank
  → 理由: 20MB模型、CPU运行、延迟<10ms

场景4: 冷启动/无训练数据的新领域
  → RankGPT (GPT-4o做Rerank)
  → 理由: 零样本泛化能力最强,无需训练数据
  → 注意: 成本高、延迟大,适合验证阶段而非生产

两阶段检索:粗筛 → 精排

经典的两阶段检索架构(工业界标准):

           百万级文档库
                │
    ┌───────────┼───────────┐
    │    Stage 1: 粗筛召回    │
    │    (Recall Stage)      │
    │                        │
    │  方法: Hybrid Search   │
    │  ├── Dense: ANN向量搜索 │    ← 毫秒级,从1M中找Top-100
    │  ├── Sparse: BM25      │    ← 毫秒级,关键词匹配Top-100
    │  └── 合并去重          │
    │                        │
    │  输出: 50-200候选Chunks │
    └───────────┬───────────┘
                │
    ┌───────────┼───────────┐
    │    Stage 2: 精排重排    │
    │    (Ranking Stage)     │
    │                        │
    │  方法: Cross-Encoder   │
    │  ├── 逐对打分          │    ← 每对~5ms,200对≈1秒
    │  ├── 按分数排序        │
    │  ├── 分数阈值过滤      │
    │  └── 多样性控制(MMR)   │
    │                        │
    │  输出: 5-15精选Chunks  │
    └───────────┬───────────┘
                │
                ▼
           Context Assembly → LLM

粗筛数量选择经验:
  文档库 < 10K   →  粗筛 Top-30  → 精排 Top-5~8
  文档库 10K-100K →  粗筛 Top-50  → 精排 Top-8~12
  文档库 > 100K  →  粗筛 Top-100 → 精排 Top-10~15

为什么不直接对所有文档做Cross-Encoder?
  1M文档 × 5ms/对 = 5000秒 ≈ 83分钟 → 完全不可接受
  所以必须先用快速方法(ANN/BM25)缩小候选集

Hybrid Search: Dense + Sparse融合

为什么混合搜索比纯向量搜索好:

向量搜索擅长:                        BM25擅长:
  ✅ 语义相似("汽车" ≈ "车辆")        ✅ 精确关键词匹配("ERC-4337")
  ✅ 同义词/释义("借贷" ≈ "放贷")     ✅ 专有名词("Uniswap V3")
  ✅ 多语言语义("staking" ≈ "质押")   ✅ 数字/代码("0x1234...")
  ❌ 精确术语匹配弱                    ❌ 语义理解弱
  ❌ 稀有词/新词embedding差            ❌ 同义词无法匹配

混合策略(Reciprocal Rank Fusion - RRF):
  dense_results = vector_search(query, top_k=100)
  sparse_results = bm25_search(query, top_k=100)

  # RRF融合公式
  for doc in all_results:
      score = 0
      if doc in dense_results:
          score += 1 / (k + dense_rank(doc))    # k通常=60
      if doc in sparse_results:
          score += 1 / (k + sparse_rank(doc))
      final_score[doc] = score

  # 按final_score排序
  → 两个列表中都靠前的文档分数最高
  → 只在一个列表中靠前的也有机会

典型效果提升:
  纯Dense Recall@10 ≈ 0.72
  纯Sparse Recall@10 ≈ 0.65
  Hybrid (RRF) Recall@10 ≈ 0.82    ← 显著提升

知识点4: 上下文组装策略

Context Window预算分配

LLM的上下文窗口是有限且昂贵的资源,必须精打细算:

假设模型窗口: 128K tokens (GPT-4o / Claude Sonnet)
实际可用分配:

┌──────────────────────────────────────────┐
│  System Prompt          ~500 tokens      │  ← 角色、规则、格式要求
│  Retrieved Context    ~4000 tokens       │  ← 检索到的Chunks(核心)
│  Chat History         ~2000 tokens       │  ← 多轮对话历史
│  User Query            ~200 tokens       │  ← 当前问题
│  Output Budget        ~2000 tokens       │  ← 预留给模型回答
│──────────────────────────────────────────│
│  Total              ~8700 tokens         │
└──────────────────────────────────────────┘

为什么不把128K都塞满Context?
  1. 成本: GPT-4o $2.50/1M input tokens → 128K = $0.32/次 → 日均1万次 = $3200/天
  2. 延迟: 输入越长,TTFT(首Token时间)越慢
  3. Lost-in-the-Middle: 研究表明模型对中间位置的信息关注度低
  4. 噪声干扰: 无关信息越多,生成质量越差

金融类比:
  Context Window = 信贷审批的一页纸报告
  → 不是把客户所有交易记录都打印出来
  → 而是提炼关键信息: 收入、负债、还款记录、风险评分
  → 一页纸要能让审批人快速做出准确判断

Lost-in-the-Middle问题与应对

2023年斯坦福研究发现:
  当Context很长时,LLM对"开头"和"结尾"的信息关注度高,
  对"中间"的信息关注度显著下降。

  ┌─────────────────────────────────────┐
  │ 关注度                               │
  │ ▓▓▓▓▓▓                              │  ← 开头: 高关注
  │     ▓▓▓▓                            │
  │         ▓▓                           │
  │           ▓   ← 中间: 低关注         │
  │         ▓▓                           │
  │       ▓▓▓▓                           │
  │     ▓▓▓▓▓▓▓                         │  ← 结尾: 高关注
  └─────────────────────────────────────┘
   位置:  开头      中间        结尾

应对策略:

1. 关键信息放首尾
   → 最相关的Chunk放在Context开头
   → 次相关的放结尾
   → 背景信息/补充信息放中间

2. 控制Context长度
   → 宁可少而精,不要多而杂
   → 5个高相关Chunk > 20个中相关Chunk

3. 结构化标记
   → 给每个Chunk加编号和标题
   → "[来源1] xxx" "[来源2] yyy"
   → 帮助模型定位和引用

4. 2025年进展:
   → Claude 3.5/4.x 和 GPT-4o 已显著改善此问题
   → 但在超长Context(>50K tokens)下仍需注意
   → 最佳实践: 即使模型改善了,也保持精简Context的习惯

去重、排序与压缩

去重策略:
├── 精确去重: 相同Chunk ID去重(Multi-Query返回的重复结果)
├── 语义去重: 两个Chunk语义相似度>0.95,只保留分数更高的
├── 来源去重: 同一文档的多个Chunks,优先保留分数最高的2-3个
└── 段落去重: 因为Chunk重叠(overlap)导致的内容重复

排序策略:
├── 按相关性排序: Reranker分数从高到低(最常用)
├── 按时间排序: 最新的信息优先(适合时效性问题)
├── 按逻辑排序: 背景→原因→分析→结论(适合分析类问题)
└── 按来源排序: 同一来源的Chunks放一起(保持上下文连贯)

压缩策略:
├── LLM Summarization: 让LLM压缩每个Chunk保留关键信息
│   → 500 tokens → 150 tokens,保留核心事实
│   → 额外延迟+成本,但能显著减少Context长度
├── Extractive: 从Chunk中提取与Query最相关的句子
│   → 不需要LLM,速度快
│   → 可能丢失上下文关系
└── LongLLMLingua: 微软的Prompt压缩框架
    → 自动识别并移除不重要的tokens
    → 压缩率2-5x,信息保留率>90%

动态Top-K选择

固定Top-K的问题:
  - Top-5: 简单问题可能够了,复杂问题信息不足
  - Top-20: 复杂问题够了,简单问题引入噪声

动态Top-K策略:

方法1: 分数阈值截断
  retrieved = rerank(query, candidates)
  context = [c for c in retrieved if c.score > 0.5]  # 只取分数>阈值的
  # 自然地:高相关性多则多取,低相关性多则少取

方法2: 分数Gap检测
  scores = [0.92, 0.88, 0.85, 0.72, 0.45, 0.42, 0.38, ...]
  # 检测分数下降最大的Gap: 0.85→0.72(Gap=0.13)或0.72→0.45(Gap=0.27)
  # 在最大Gap处截断 → 取前4个

方法3: Token预算约束
  budget = 4000  # tokens
  context_chunks = []
  used_tokens = 0
  for chunk in ranked_chunks:
      if used_tokens + len(chunk.tokens) > budget:
          break
      context_chunks.append(chunk)
      used_tokens += len(chunk.tokens)

方法4: LLM自适应判断
  让LLM判断"是否还需要更多信息来回答这个问题"
  → 如果够了就停止检索
  → Self-RAG的核心思想(见知识点5)

知识点5: 高级检索模式

Self-RAG: 自适应检索

论文: "Self-RAG: Learning to Retrieve, Generate, and Critique" (2023)

核心思想: 让模型自己决定"要不要检索"、"检索到的有没有用"、"生成的对不对"

传统RAG: 无论什么问题,一律先检索再生成(有时候不需要检索)
Self-RAG: 模型在生成过程中插入"反思Token"来自我监督

流程:
  Query进入
    │
    ├── 模型判断: 需要检索吗?
    │   ├── [Retrieve=Yes] → 执行检索
    │   └── [Retrieve=No]  → 直接生成(简单事实/模型已知的知识)
    │
    ├── 检索后判断: 检索到的信息有用吗?
    │   ├── [IsRelevant=Yes] → 使用该Chunk
    │   └── [IsRelevant=No]  → 丢弃该Chunk,可能再检索
    │
    ├── 生成后判断: 生成的内容有事实依据吗?
    │   ├── [IsSupported=Fully] → 保留
    │   ├── [IsSupported=Partially] → 标注不确定部分
    │   └── [IsSupported=No] → 重新生成
    │
    └── 最终判断: 回答整体质量如何?
        ├── [Utility=5] → 输出
        └── [Utility<3] → 尝试不同的检索策略

优势: 减少不必要的检索(节省成本)、降低幻觉(自我验证)
劣势: 需要特殊训练、推理更复杂

Corrective RAG (CRAG): 带纠错的检索

论文: "Corrective Retrieval Augmented Generation" (2024)

核心思想: 对检索结果做质量评估,如果质量不够就"纠正"

流程:
  Query → 检索Top-K
    │
    ├── 评估每个Chunk的相关性(轻量级分类器)
    │   ├── Correct: 高度相关 → 直接使用
    │   ├── Ambiguous: 可能相关 → 提取关键信息后使用
    │   └── Incorrect: 不相关 → 丢弃
    │
    ├── 如果大部分Chunks都是Incorrect:
    │   └── 触发Web Search作为补充(外部知识补救)
    │
    └── 用精炼后的Chunks生成回答

金融场景:
  Query: "2025年Q4以太坊质押APY是多少?"
  检索结果: [2023年的旧数据Chunk, 2024年的数据, 不相关的NFT文章]
  CRAG评估: 全部Incorrect(过时+不相关)
  纠正动作: 触发实时API调用获取最新数据

实现思路(LangGraph):
  1. 检索节点 → 2. 评估节点(Grader) → 3a. 质量OK→生成
                                       → 3b. 质量差→Web Search→生成

Adaptive RAG: 智能路由

核心思想: 根据问题复杂度,选择不同的检索策略

问题分类:
├── 简单事实查询 → 直接RAG(单次检索+生成)
│   "USDC的发行方是谁?"
│
├── 多步推理 → 迭代RAG(检索→推理→再检索→最终回答)
│   "对比Aave和Compound的清算机制,哪个对借款人更友好?"
│
├── 实时数据 → 跳过RAG,直接调API
│   "ETH现在的价格是多少?"
│
└── 模型已知 → 跳过检索,直接生成
    "什么是区块链?"

路由逻辑(可用LLM或分类器实现):
  Input Query → Router
    ├── "no_retrieval" → LLM直接回答
    ├── "single_retrieval" → 标准RAG流程
    ├── "iterative_retrieval" → 多轮迭代RAG
    └── "api_call" → 调用外部API

效果: 简单问题更快(跳过不必要的检索),复杂问题更准(多轮迭代)

RAPTOR: 树状递归检索

论文: "RAPTOR: Recursive Abstractive Processing for Tree-Organized Retrieval" (2024)

核心思想: 不只检索原始Chunks,而是构建一棵"摘要树"

构建过程:
  Level 0 (叶子): 原始Chunks
    [C1] [C2] [C3] [C4] [C5] [C6] [C7] [C8] ...
      \   /     \   /     \   /     \   /
  Level 1 (摘要): 相邻Chunks聚类后LLM生成摘要
    [S1=summary(C1,C2)]  [S2=summary(C3,C4)]  [S3=...]
           \              /                  /
  Level 2 (高层摘要): 进一步聚合
    [SS1=summary(S1,S2,S3)]
           ...
  Level N (根): 全文档摘要

检索时:
  ├── 宏观问题("这篇论文的核心贡献是什么?")
  │   → 在高层(Level 2-N)检索 → 返回摘要
  │
  └── 细节问题("Table 3中的F1值是多少?")
      → 在底层(Level 0)检索 → 返回原始Chunks

优势: 同时支持宏观和微观问题,不像传统RAG只能检索局部Chunks
劣势: 索引构建成本高(需要大量LLM调用生成摘要)、存储量翻倍
适用: 长文档(100+页)、需要同时回答概述和细节问题的场景

ColBERT: Late Interaction (晚期交互)

ColBERT = Contextualized Late Interaction over BERT

定位: 在Bi-Encoder(快但不精)和Cross-Encoder(精但慢)之间的折中

原理:
  Bi-Encoder:  Query → [q_vec]      Doc → [d_vec]        → 1个score
               (整体压缩成1个向量)

  ColBERT:     Query → [q1,q2,...qN]  Doc → [d1,d2,...dM]  → MaxSim
               (每个token保留独立向量)

  Cross-Encoder: [CLS] Query [SEP] Doc [SEP] → Transformer → score
                 (完整交叉注意力)

ColBERT的MaxSim计算:
  对Query中的每个token qi:
    找Document中与qi最相似的token dj → max_sim_i = max(sim(qi, dj))
  最终分数 = sum(max_sim_i for all i)

  → Token级别的精确匹配,但Document向量可以预计算
  → 速度比Cross-Encoder快100x,精度比Bi-Encoder高10-15%

ColBERT v2 (2025更新):
  - 残差压缩: 每个token向量从128维压缩到2字节,存储减少10x
  - PLAID引擎: 优化的检索算法,速度提升3x
  - 可以直接替代Bi-Encoder做第一阶段召回

知识点6: 检索质量评估

核心指标体系

检索评估 = 组件评估 + 端到端评估

组件评估(检索模块本身的质量):
├── Recall@K: Top-K结果中包含了多少真正相关文档
├── Precision@K: Top-K结果中有多少是真正相关的
├── MRR: 第一个相关结果出现在什么位置
├── NDCG: 考虑相关性等级的排序质量
└── MAP: 多个Query的平均精度

端到端评估(RAG系统最终回答的质量):
├── Answer Correctness: 答案是否正确
├── Faithfulness: 答案是否基于检索到的Context
├── Answer Relevancy: 答案是否回答了问题
└── Context Relevancy: 检索到的Context是否与问题相关

详解每个指标

1. Recall@K (召回率)
   定义: 在Top-K个检索结果中,真正相关文档被找到的比例
   公式: Recall@K = |Top-K ∩ 真正相关| / |真正相关|

   例子:
     真正相关文档: {A, B, C, D, E}  (共5个)
     Top-10检索结果: {A, X, B, Y, Z, C, W, V, U, T}
     Recall@10 = |{A,B,C}| / |{A,B,C,D,E}| = 3/5 = 0.60

   解读: 越高越好。Recall@10=0.80是生产级RAG的基本要求。
   金融类比: 信贷审批时,是否把所有该查的征信记录都调出来了

2. MRR (Mean Reciprocal Rank, 平均倒数排名)
   定义: 第一个正确结果排在第几位的倒数,多个Query取平均
   公式: MRR = (1/N) × Σ(1/rank_i)

   例子:
     Query1: 第一个相关在第1位 → 1/1 = 1.00
     Query2: 第一个相关在第3位 → 1/3 = 0.33
     Query3: 第一个相关在第2位 → 1/2 = 0.50
     MRR = (1.00 + 0.33 + 0.50) / 3 = 0.61

   解读: 越高越好。MRR关注"第一个正确结果出现多快"。
   金融类比: 客服系统中,用户第一眼看到的答案是否正确

3. NDCG@K (Normalized Discounted Cumulative Gain)
   定义: 考虑文档相关性等级和位置的综合排序质量指标
   关键: 不是简单的"相关/不相关",而是"多相关"(3=高度,2=一般,1=略相关,0=无关)

   例子:
     理想排序: [3, 3, 2, 2, 1, 0, 0, ...]
     实际排序: [3, 1, 2, 0, 3, 2, 0, ...]
     DCG = Σ(relevance_i / log2(i+1))   → 位置越靠后,折扣越大
     NDCG = DCG / IDCG (除以理想DCG归一化到0-1)

   解读: NDCG@10 ≥ 0.75 是好的检索系统。
   金融类比: 投研报告推荐排序——最有投资价值的报告是否排在最前面

4. MAP (Mean Average Precision)
   定义: 在每个相关文档出现的位置计算Precision,取平均
   适合: 需要找到多个相关文档的场景

   例子:
     排序: [R, X, R, X, X, R]  (R=相关, X=无关)
     P@1 = 1/1, P@3 = 2/3, P@6 = 3/6
     AP = (1 + 0.67 + 0.50) / 3 = 0.72

组件评估 vs 端到端评估

为什么两种评估都要做:

只做组件评估的问题:
  检索Recall@10 = 0.95(很好!)
  但最终回答质量很差
  → 可能是Context Assembly或LLM Prompt有问题

只做端到端评估的问题:
  最终回答质量好
  但不知道哪个环节贡献最大
  → 改进时无从下手

最佳实践: 分层评估

Layer 1: 检索质量     → Recall@K, MRR, NDCG
Layer 2: Rerank质量   → NDCG@K (Rerank前 vs 后)
Layer 3: Context质量  → Context Relevancy, Context Recall
Layer 4: 生成质量     → Faithfulness, Correctness, Relevancy

金融类比:
  风控系统评估不能只看"坏账率":
  ├── 模型层: AUC/KS (模型区分力)
  ├── 策略层: 通过率/拒绝率 (策略合理性)
  ├── 业务层: 坏账率/利润率 (业务结果)
  └── 每层独立评估 + 端到端贯通

构建评估数据集(Golden Set)

Golden Set = 标注好的 {Query, 正确Answer, 相关Chunks} 三元组

构建方法:

方法1: 人工标注(金标准)
  - 业务专家对100-300个Query标注正确答案和相关来源
  - 成本高但最准确
  - 金融场景建议: 至少让2位分析师交叉验证

方法2: LLM辅助生成(经济方案)
  - 给LLM一段文档,让它生成"可以用这段文档回答的问题"
  - 人工审核筛选
  - 成本低但可能有偏差(LLM倾向生成简单问题)

方法3: 用户日志挖掘(实战方案)
  - 从生产环境收集真实Query
  - 人工标注哪些回答是正确的
  - 最贴近真实分布

推荐: 方法2生成初始集 + 方法3持续补充 + 方法1审核

数量建议:
  开发阶段: 50-100个Golden Queries
  上线前:   200-300个Golden Queries
  持续运营: 每月新增20-50个(覆盖新场景)

A/B测试框架

RAG系统的A/B测试比Web A/B测试更复杂:

测试维度:
├── 检索策略A/B: Hybrid Search vs 纯Dense Search
├── Reranker A/B: Cohere vs BGE-Reranker
├── Chunking策略A/B: 512 vs 1024 tokens
├── Prompt模板A/B: 不同的System Prompt
└── 端到端A/B: 完整Pipeline A vs Pipeline B

指标采集:
├── 自动化指标: Recall@K, NDCG, Faithfulness(RAGAS自动评估)
├── 人工评估: 正确性、有用性(1-5分人工打分)
└── 用户行为: 点赞/点踩、追问率、会话长度

实施注意:
  1. 同一个Query在A/B两组都要跑(Paired test)
  2. 至少200个不同Query才有统计显著性
  3. 区分"检索变好了"和"碰巧测试集简单了"
  4. 金融场景: 错误答案的代价不对称(投资建议错了比不回答更糟)
     → 除了平均分,还要关注"严重错误率"

今日思考

思考1: 检索优化的ROI问题

问题: 团队资源有限,应该在检索Pipeline的哪个环节投入最多?

我的思考:
  从投入产出比(ROI)角度排序:
  1. 加Reranker(低投入,高回报): 一行代码加Cohere Rerank API,Precision提升15-25%
  2. Hybrid Search(中投入,稳定回报): 需要维护BM25索引,但Recall提升10-20%
  3. Query Rewriting(低投入,场景化回报): 对口语化Query效果显著,对已经很清晰的Query提升小
  4. 高级模式(高投入,长期回报): Self-RAG/CRAG需要更多工程投入,但能解决长尾问题

  金融类比: 就像银行做风控优化——
  → 先上规则引擎(快速见效) → 再加模型评分(中期提升) → 最后做实时特征工程(长期竞争力)
  → 不要一上来就追求最复杂的方案

思考2: 检索精度 vs 检索召回的取舍

问题: Precision和Recall不可兼得时,RAG应该偏向哪个?

我的思考:
  取决于场景的"错误成本":

  高Recall优先(宁可多不可少):
    → 金融合规查询: 漏掉一条监管规定可能导致处罚
    → 医疗问答: 漏掉一个禁忌症可能危及生命
    → 策略: 粗筛阶段设宽松阈值,Reranking阶段再精筛

  高Precision优先(宁可少不可错):
    → 客服自动回复: 推送错误信息损害品牌(不如说"我不确定")
    → 投资建议: 给出错误的数据可能导致亏损
    → 策略: 设高阈值,低于阈值就不检索/不回答

  RAG场景的特殊性:
    传统搜索: 用户可以自己从结果列表中筛选(Precision要求低)
    RAG: LLM直接基于检索结果生成答案(Precision要求高——垃圾进垃圾出)
    → 所以RAG通常更强调Precision,这也是Reranking如此重要的原因

思考3: 未来趋势判断

问题: 2025-2026年,RAG检索技术的演进方向?

我的判断:
  1. 长上下文会取代简单RAG吗?
     → 不会完全取代。Gemini 2.0 10M tokens很强,但:
       a) 成本: 把100万Chunks全塞进去太贵
       b) 精度: 长上下文中找信息不如专门的检索系统精准
       c) 实时性: 向量索引可以秒级更新,重跑10M context不行
     → 趋势: 长上下文 + RAG混合(小知识库直接塞,大知识库走RAG)

  2. Agentic RAG将成为主流
     → 从"一次检索就生成"进化到"多轮检索-推理-反思"
     → Self-RAG/CRAG是早期形态,Agent+RAG是终极形态
     → LLM自主决定何时检索、检索什么、是否足够

  3. 端到端学习的检索(Learned Retrieval)
     → 不是分别优化Embedding、Reranker、LLM
     → 而是端到端训练:让LLM的反馈信号传导到Retriever
     → Google的RETRO/Atlas已经探索这个方向

  4. 多模态检索
     → 不只检索文本Chunks,还检索图表、代码、结构化数据
     → Vision-Language模型让图表检索成为可能

面试表达模板

问题: "你们的RAG检索效果怎么优化的?"

框架回答 (2分钟版):

"我们的RAG检索优化分四个阶段推进:

第一,Query理解层。用户的原始问题往往模糊或口语化,我们做了Query Rewriting,
用LLM把口语化查询改写成检索友好的形式。对于复杂问题,还做了Query Decomposition,
拆解成子问题分别检索。这一步把Recall提升了约15-20%。

第二,多路召回。不是只用向量搜索,而是Dense + BM25的Hybrid Search。
向量搜索擅长语义匹配,BM25擅长精确关键词匹配(比如专有名词、合约地址)。
用RRF融合两路结果,Recall又提升了10%左右。

第三,两阶段Reranking。粗筛阶段召回Top-100,然后用Cross-Encoder Reranker
对这100个候选精确打分,取Top-10。Reranker能做Query和Document的深度语义交互,
比纯向量相似度精确得多。这一步Precision提升了约20%。

第四,Context Assembly。对精排后的Chunks做去重、逻辑排序、Token预算控制。
最相关的放开头(应对Lost-in-the-Middle),控制总长度在4000 tokens以内。

整个Pipeline用RAGAS框架做评估,Recall@10从基线的0.65提升到0.85,
Faithfulness从0.72提升到0.91。"

问题: "为什么需要Reranker?直接用更好的Embedding模型不行吗?"

回答:

"这是个好问题。更好的Embedding确实能提升检索质量,但Reranker解决的是
Embedding从根本上无法解决的问题。

Embedding模型(Bi-Encoder)的工作方式是把Query和Document分别压缩成一个固定长度的
向量,然后算相似度。这个过程有信息损失——一段500字的文档压缩成768维向量,
细节必然丢失。而且Query和Document是独立编码的,没有交叉注意力。

Reranker(Cross-Encoder)是把Query和Document拼在一起送入模型,每个token之间
都有完整的Attention交互。它能理解'Query问的是A,Document恰好回答了A'这种
精确的问答对应关系。

但Cross-Encoder不能预计算,对100万文档全部做Rerank需要几十分钟,不可接受。
所以工业界的标准做法是两阶段:先用Embedding快速召回Top-100(毫秒级),
再用Reranker精排到Top-10(约1秒)。这样兼顾了速度和精度。

用数字说话:我们实测,只换更好的Embedding(从BGE-small到BGE-large),
NDCG@10提升了约5%。加上Reranker后,NDCG@10额外提升了15%。
两者不是替代关系,而是互补。"

问题: "Self-RAG和CRAG是什么?你在生产环境用过吗?"

回答:

"Self-RAG和CRAG都是2023-2024年提出的高级RAG范式,核心思想都是
给RAG加上'自我反思'能力。

Self-RAG让模型自己判断三件事:是否需要检索、检索到的是否有用、生成的是否可靠。
通过在训练时加入特殊的反思Token来实现。好处是减少了不必要的检索(节省成本),
也降低了幻觉(自我纠错)。

CRAG更实用一些——它对检索结果做质量评估,如果判断检索到的信息不够好,
会触发补充检索(比如Web Search)来纠正。

在生产环境,我们没有直接用原论文的Self-RAG(需要特殊训练),但借鉴了它的思想:
用LangGraph实现了一个Corrective流程——检索后加一个轻量级的相关性评估节点,
如果评估分低于阈值,就触发二次检索(换个Query策略或扩大检索范围)。
这个方案实现简单但效果显著,把长尾Query的回答质量提升了约25%。"

实操练习建议

1. 实现两阶段检索Pipeline:
   → 用LlamaIndex或LangChain搭建: BM25 + Dense Hybrid Search
   → 加上Cohere Rerank或BGE-Reranker
   → 对比加Reranker前后的Recall@10和NDCG@10

2. 测试Query转换策略:
   → 对同一批测试Query,分别用原始Query/Rewritten/HyDE/Multi-Query检索
   → 对比Recall差异
   → 找到你的数据集上效果最好的策略组合

3. 用LangGraph实现Corrective RAG:
   → 检索 → 评估(LLM给相关性打分) → 分支(合格→生成 / 不合格→Web搜索→生成)
   → 测试几个故意用过时信息的Query

4. 搭建评估Pipeline:
   → 构建50个Golden Query (Q+A+相关Chunks)
   → 用RAGAS评估Recall/Faithfulness/Relevancy
   → 建立Baseline,为后续优化提供对比基准

资源推荐

资源说明链接
Self-RAG论文自适应检索+反思生成arxiv.org/abs/2310.11511
CRAG论文纠错式检索增强生成arxiv.org/abs/2401.15884
RAPTOR论文树状递归检索arxiv.org/abs/2401.18059
ColBERT v2Late Interaction检索github.com/stanford-futuredata/ColBERT
Lost-in-the-Middle论文LLM对长上下文中间部分注意力下降arxiv.org/abs/2307.03172
LangChain Retrieval文档Query转换/Hybrid Search/Reranking实现python.langchain.com/docs/how_to/#retrievers
LlamaIndex Reranking指南Reranker集成与对比docs.llamaindex.ai
RAGAS文档RAG评估框架docs.ragas.io
Cohere Rerank API商业Reranker(效果最佳之一)docs.cohere.com/docs/reranking
BGE-RerankerBAAI开源Reranker(中文最佳)huggingface.co/BAAI/bge-reranker-v2-m3

明日预告

Day 21: 生产级RAG(3) — 评估框架与持续迭代

预习问题:
1. RAGAS框架的四个核心指标(Faithfulness/Relevancy/Correctness/Context)如何计算?
2. "Vibe评估" vs 系统化评估有什么区别?为什么直觉不可靠?
3. RAG系统上线后,如何建立持续迭代的飞轮?

连接点:
  Day 19(解析+Chunking) → Day 20(检索+Reranking) → Day 21(评估+迭代)
  → Day 19确定数据质量上限
  → Day 20确定检索精度
  → Day 21回答"怎么知道做得好不好"和"怎么持续变好"
  → 三天合起来 = 一套完整的生产级RAG工程方法论