RAG 分块、召回、重排与引用
📚 RAG(检索增强生成)让 LLM 基于外部知识回答,核心挑战是:如何把相关内容检索出来并准确引用。
RAG 完整链路
文档 → 分块 → Embedding → 向量库
↓
用户问题 → Embedding → 向量检索 → 重排 → 注入 Prompt → LLM → 带引用的回答
分块策略
固定大小分块
按 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 是经验值
重排(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 |