迪图
发布于 2026-10-20 / 9 阅读
0
0

生产级 RAG 完全指南:分块、混合检索、重排序与评估

生产级 RAG 完全指南:分块、混合检索、重排序与评估

把文档丢进向量库然后调用一下就完成了——这样的 RAG demo 下午能做完,能上线要一个季度。差距几乎全在检索质量上。

开篇:RAG 的天花板是检索

一个更强的生成模型救不了糟糕的检索。

这句话值得反复强调。团队最常犯的错误是: obsess 哪个 LLM 更好,同时把检索当成已经解决的黑盒。

生产环境里 RAG 的失败很少是戏剧性的,通常是慢性病:检索质量缓慢劣化,幻觉随之增加,用户开始抱怨,团队排查后发现系统从一开始就没在检索正确的文档。

一、分块:最被低估的杠杆

糟糕的分块会毁掉检索,无论你的 embedding 和 reranker 多强。

三条基本规则

规则一:按语义单元切,不按字符数切

一段是一个单元。一节是一个单元。一个 1000 字符的窗口在句子中间切断——这不是。

规则二:重叠 10-20%

跨越边界的信息不会因为切分而消失。

规则三:同时存储父块

检索命中时,返回给 LLM 的可以是父级章节,而不是孤立的 chunk。这样既有精确匹配的粒度,又有完整的上下文。

不同文档的切分策略

策略

适用文档

参数

固定长度

日志、转录、均匀文本

256–512 token,10% 重叠

语义分块

文章、手册、代码

按标题/段落切

层次分块

书籍、wiki、嵌套内容

父块 + 子块

句子窗口

密集文本问答

3–5 句,滑动窗口

结构感知

代码仓库、医疗记录

按函数/就诊/工单切

固定长度分块(512 或 1024 token)很方便但具有破坏性——它在概念中间切断,把相关信息打散,并强加与数据结构不对齐的任意边界。

三种更好的做法:

1. 语义分块:用 embedding 测量相邻句子的距离,超过阈值就切。保持相关的信息在一起,代价是预处理开销

2. 结构感知分块:边界对齐你的领域。代码按函数,医疗记录按就诊,支持工单按问题线程,技术文档按章节和代码块

3. 层次分块:多个抽象层级。短块用于细粒度检索,长摘要块用于上下文

元数据:每个 chunk 都该带

{
  "content": "chunk 文本",
  "metadata": {
    "source_url": "https://...",
    "section_title": "2.3 环境要求",
    "page": 12,
    "doc_type": "manual",
    "updated_at": "2026-08-15",
    "department": "运维"
  }
}

元数据有两个用途:过滤检索(只从当前生效文档里找)和让模型判断来源相关性。

把元数据做成可检索字段,在向量检索之前先缩小候选集——这是零成本的延迟优化。

二、混合检索:纯向量搜索不够

向量搜索擅长概念,但对精确术语很弱——产品型号、规范编号、函数名、错误码。

检索方式

擅长

弱项

稠密向量

语义、改写、同义表达

精确术语、专有名词

BM25 稀疏

关键词、名称、编码

同义表达、概念

混合检索并行跑两者再融合结果。融合算法通常是 RRF(Reciprocal Rank Fusion)——它只依赖排名,绕开了两套系统分数不可比的问题。

具体收益:一个查 "错误码 ORA-12514" 的请求,纯向量检索效果很差,BM25 精准命中。

2026 年 Q1 有报告称企业混合检索采用率翻了三倍,驱动力正是生产团队发现纯向量搜索在精度敏感场景不够用。

RRF 的实现

def reciprocal_rank_fusion(rankings, k=60):
    """rankings: [(doc_id, rank), ...] 的列表,每个检索系统一个"""
    scores = {}
    for ranking in rankings:
        for doc_id, rank in ranking:
            scores[doc_id] = scores.get(doc_id, 0) + 1.0 / (k + rank)
    return sorted(scores.items(), key=lambda x: -x[1])

k=60 是常用默认值。含义是排第 1 的贡献远大于第 50 的,但不会让前几名完全支配结果。

三、重排序:投入产出比最高的一层

这是性价比最高的单点优化。

标准向量搜索按余弦相似度返回 top-K,这是粗筛。reranker(Cohere Rerank、BGE-Reranker 或微调的小模型)拿这 K 个候选,基于与查询的真实语义相关性重新排序。

成本是一次额外的 API 调用,收益常常是"demo 能用"和"用户敢信"的差别。

量化收益

  • 交叉编码器重排序带来 +33–40% 准确率提升,平均只增加 约 120ms 延迟

  • 某金融问答基准上,重排序把 MRR@3 提升了 39%

  • 跳过重排序,质量下降约 20%

两阶段架构

用户问题
   │
   ├─ [阶段一:召回] bi-encoder 向量 + BM25 → top 50 候选
   │                (快,但有损——把语义压成单个向量)
   │
   ├─ [阶段二:精排] cross-encoder 逐对打分 → top 5
   │                (慢,但准——query 和 chunk 一起看)
   │
   └─ [生成] 送入 LLM

为什么 bi-encoder 不够:embedding 把语义压缩成单个向量,两个语义相近的 chunk 未必是对特定查询最相关的那个。cross-encoder 能同时看到 query 和 chunk,判断准确得多。

2026 年主流 reranker:Cohere Rerank、Voyage rerank、BGE reranker-v2、Jina Reranker v2,多数是一个 HTTP 调用。

四、查询改写:弥合词汇鸿沟

用户用自己的话提问,文档用作者的话写。

廉价版本:检索前让 LLM 把查询改写成 2-3 个替代表述,把结果取并集。

昂贵版本:在你的领域数据上微调一个小改写模型。

HyDE:反直觉但有效

Hypothetical Document Embeddings:让 LLM 先生成一个"理想答案",然后把这个假想文档去 embedding 做检索,而不是用原始查询。

直觉上很奇怪,实际往往带来 10-15% 的召回提升。原因是:查询和文档的分布本来就不同,生成的假想文档更接近文档的分布。

五、上下文长度:抵抗的冲动

现代模型有 100K+ 的上下文窗口。克制住全部塞进去的冲动。

大多数问答任务在 3000-5000 token 之后收益就递减了。更多 token 意味着更高的延迟和成本,而质量提升微乎其微。

一句结构良好的 4000 token,胜过无结构的 8000 token。

这个判断要在你自己的评估集上验证,不要照搬。

六、评估:不测就是盲飞

RAGAS 是标准评估框架,四个核心指标:

指标

含义

合格线

低分意味着

Faithfulness(忠实度)

回答是否基于检索到的上下文

≥ 0.90

幻觉

Answer Relevancy(答案相关性)

回答是否切题

≥ 0.85

生成质量差

Context Precision(上下文精度)

检索到的内容有多少有用

≥ 0.80

检索质量差

Context Recall(上下文召回)

必要内容是否都被检索到

≥ 0.80

漏了文档

建一个 50-200 条问题 + 期望答案的黄金集,在 CI 里对每次 prompt 或检索改动跑一遍。 数字涨了你知道,数字跌了你也知道是哪次改动导致的。

排查链路

出问题时按这个顺序查:

召回对不对? →  记录 rerank 前后的 top-K
                ↓
embedding 一致吗? → 索引和查询用同一模型吗
                ↓
chunk 质量如何? → 语义连贯吗?有句子中间切断吗
                ↓
模型在无视上下文吗? → 加 grounding 指令
                ↓
哪一阶段最慢? → 延迟分解

先过滤,后变换:永远先用 geom 这类裸列做索引过滤,再做投影和几何计算,否则索引完全失效。

七、向量量化:规模上来后的成本杠杆

当语料超过几百万 chunk,全精度 float32 向量成为主要成本。

级别

做法

体积

召回损失

标量量化

每维存 int8

4× 更小

约 1%

二值量化

每维 1 bit

32× 更小

用作初筛,再全精度重排

乘积量化(PQ)

分子向量 + 码本

极大压缩

FAISS 等库内置

几乎总是值得做 int8。Pinecone、Weaviate、Qdrant、pgvector(HNSW)都开箱支持。

八、什么时候不该用 RAG

这是被跳过最多的一步。先做判断,再决定是否投入检索基础设施。

情况

更适合的方案

数据高质量且量大,要固化领域知识

微调

任务定义明确,基础模型知识够用

Prompt 工程

结构化数据抽取

直接调用即可

文档总量就几千

长上下文全量塞入

用 200K 上下文窗口把文档全塞进去,有时比构建检索基础设施更快也更便宜。

这不意味着 RAG 没用,而是要先算清成本收益账。

九、推荐的 2026 默认流水线

1. 摄取     按结构分块(256-512 token,15% 重叠)
2. 嵌入     现代 embedding 模型 + 丰富元数据
3. 索引     HNSW + int8 量化(成本-召回平衡点)
4. 召回     混合检索(向量 + BM25),元数据过滤,取 top 50
5. 精排     cross-encoder 重排到 top 5
6. 生成     传入 chunk + 来源 URL 用于引用
7. 校验     忠实度检查(LLM-as-judge),不达标则回退到"不知道"

每一层都在复利。 跳过重排序,质量掉 20%;跳过忠实度检查,你就把幻觉送上线了。

十、上线前检查清单

  • [ ] 黄金集 50-200 条,每次改动跑 CI

  • [ ] 混合检索已启用(不只是纯向量)

  • [ ] 重排序已接入

  • [ ] 元数据过滤可用

  • [ ] 提示词要求"仅基于提供的文档回答"

  • [ ] 允许模型说"资料不足"

  • [ ] 引用来源可追溯

  • [ ] 延迟 p95 与成本已记录

  • [ ] int8 量化已评估

参考资料

  • RAGAS 官方文档 — https://docs.ragas.io/

  • Pinecone Chunking Guide — https://www.pinecone.io/learn/chunking-strategies/

  • Cohere Rerank — https://docs.cohere.com/docs/rerank-overview

  • BGE Reranker — https://huggingface.co/BAAI/bge-reranker-v2-m3

  • Anthropic, *Introducing Contextual Retrieval* — https://www.anthropic.com/news/contextual-retrieval


评论