RAG 分块、召回、重排与引用
📚 RAG(检索增强生成)让 LLM 基于外部知识回答,核心挑战是:如何把相关内容检索出来并准确引用。
RAG 不是“接一个向量库”,而是两个系统
离线索引链路
文档采集 → 解析/OCR → 清洗去重 → 分块 → metadata → 稀疏/稠密索引 → 版本发布
在线回答链路
问题理解 → 查询改写/过滤 → 多路召回 → 融合去重 → 重排 → 上下文组装 → 生成 → 引用校验
任何一层都可能成为瓶颈。生成答案错误时,先判断:
- 检索失败:正确证据没有进入 Top-K。
- 排序失败:证据被召回但排名太低。
- 组装失败:证据进入候选但被截断、压缩或覆盖。
- 生成失败:证据充分,模型仍误读或无依据扩写。
只有先分型,调 chunk size、Prompt 或模型才有意义。
分块策略
固定大小分块
按 token 数切分(如每块 512 tokens,重叠 64 tokens):
- 优点:简单,均匀
- 缺点:可能切断语义单元
语义分块
按段落、标题、句子边界切分:
- 优点:语义完整
- 缺点:块大小不均
递归字符分块(LangChain 默认)
按 \n\n → \n → 句号 → 空格 优先级递归切分,保留语义结构。
分块设计要点
| 参数 | 建议 | 说明 |
|---|---|---|
| chunk_size | 256-512 tokens | 太大检索精度低,太小语义不完整 |
| chunk_overlap | 10-15% | 避免答案跨块丢失 |
| metadata | 必须保留 | 来源、页码、标题用于引用 |
召回策略
向量检索(稠密检索)
用 Embedding 相似度召回:擅长语义理解,弱于关键词精确匹配。
BM25(稀疏检索)
基于词频的关键词匹配:擅长专有名词、代码、版本号等精确匹配。
混合检索(Hybrid Search)
结合两者,用 RRF(Reciprocal Rank Fusion)融合排名:
# RRF 融合
rrf_score = sum(1 / (k + rank_i) for rank_i in ranks)
# k=60 是经验值
高级召回策略
Query Rewrite
把口语问题改写为更适合检索的表达,也可生成多个子查询覆盖不同角度。必须保留原始实体、数字、版本号和否定条件,避免改写漂移。
Metadata Filtering
先按租户、权限、时间、文档类型过滤,再做相似度检索。ACL 必须由系统执行,不能依赖模型过滤无权内容。
Parent-Child Retrieval
小 chunk 用于精确匹配,召回后扩展到父段落提供完整上下文。这能兼顾检索精度与阅读完整性。
Multi-Query 与 Fusion
多个查询分别召回后用 RRF 融合;适合问题有同义表达或多个子问题的情况,但会增加延迟和重复候选。
HyDE
先生成一段“假设答案”再用其向量检索,可能改善抽象问题;但在专有名词和事实敏感场景中可能引入漂移,需通过评测决定是否启用。
重排(Reranking)
向量检索召回 Top-K(如 20 个),用 Cross-Encoder 对每对 (query, doc) 精确打分,取 Top-N(如 5 个):
| 模型 | 特点 |
|---|---|
| Cohere Rerank | API,效果好,有延迟 |
| BGE-Reranker | 开源,中文友好 |
| Cross-Encoder | 通用框架,需自部署 |
权衡:重排提升精度,但增加 50-200ms 延迟。
引用与溯源
Chunk 元数据设计
{
"content": "...",
"metadata": {
"source": "document.pdf",
"page": 3,
"section": "第二章",
"chunk_id": "doc-p3-001"
}
}
引用生成策略
- 直接引用:在 Prompt 中告知模型引用 chunk_id
- 后处理匹配:模型生成答案后,将句子与 chunk 做相似度匹配
- Structured Output:模型返回 JSON,包含 answer + cited_chunk_ids
效果评估指标
| 指标 | 测量内容 |
|---|---|
| Recall@K | Top-K 结果中包含正确答案的比例 |
| MRR | 第一个正确结果的排名倒数均值 |
| Faithfulness | 答案是否仅基于检索内容 |
| Answer Relevance | 答案与问题的相关性 |
| Context Precision | 召回内容中真正有用的比例 |
常见问题排查
| 问题 | 可能原因 | 解决 |
|---|---|---|
| 召回率低 | 分块太细或 Embedding 模型弱 | 增大 chunk,换更好的 Embedding |
| 答案不准 | 召回了噪音内容 | 加重排,提升 Context Precision |
| 引用错误 | 元数据不完整 | 分块时保留完整 metadata |
| 延迟高 | 重排或 Embedding 慢 | 缓存热门 query,批量 Embedding |