RAG 效果优化
问题
RAG 系统上线后发现回答质量不高,如何排查和优化?
答案
一、RAG 质量瓶颈定位
二、分阶段诊断
| 阶段 | 诊断方法 | 好的标准 |
|---|---|---|
| 检索 | 查看 Top5 结果是否包含答案 | Context Recall > 0.8 |
| 生成 | 检查模型是否忠实于上下文 | Faithfulness > 0.9 |
| 端到端 | 最终回答是否正确完整 | Answer Relevancy > 0.8 |
三、核心优化手段
1. 分块策略优化
| 策略 | 适用场景 | 注意事项 |
|---|---|---|
| 固定大小 (500~1000 字符) | 通用文档 | 可能切断语义 |
| 语义分块 | 文章/报告 | 更贴合自然段落 |
| 递归分块 | 层次化文档 | 按标题层级拆分 |
| 表格/代码专项 | 结构化内容 | 不能按字数切割 |
分块核心原则
- 每个 Chunk 应该能独立理解
- 添加上下文前缀(标题、章节信息)
- Chunk 之间适当重叠(10~20%)
2. 混合检索
async function hybridSearch(query: string) {
// 向量检索 — 语义匹配
const vectorResults = await vectorStore.search(query, { topK: 10 })
// 关键词检索 — 精确匹配
const bm25Results = await bm25Index.search(query, { topK: 10 })
// RRF 融合排序
const fused = reciprocalRankFusion([vectorResults, bm25Results])
// Reranker 重排序
const reranked = await reranker.rerank(query, fused.slice(0, 20))
return reranked.slice(0, 5)
}
3. Query 改写
| 技术 | 做法 |
|---|---|
| HyDE | 先让 LLM 生成假设性答案,用答案检索 |
| Multi-Query | 将原始问题改写成多个变体分别检索 |
| Step-back | 将具体问题泛化为更通用的问题 |
常见面试问题
Q1: Embedding 模型怎么选?
答案:
| 模型 | 维度 | 中文效果 | 推荐场景 |
|---|---|---|---|
| text-embedding-3-large | 3072 | 好 | 通用 |
| BGE-M3 | 1024 | 优秀 | 中文优先 |
| text-embedding-3-small | 1536 | 中 | 低成本 |
选型原则:在 MTEB Leaderboard 上找适合自己语言和任务的模型。
Q2: Chunk 大小怎么确定?
答案:
没有万能的大小,需要实验确定。一般建议:
- 通用文档:500~1000 字符
- 技术文档:按标题/章节分块
- FAQ:每个 Q&A 作为一个 Chunk
- 可先用小测试集对比不同大小的效果
Q3: 如何持续维护 RAG 知识库?
答案:
- 定期更新:文档变更时重新处理和索引
- 质量监控:收集 Bad Case,定位是否因知识缺失
- 去重去噪:清理过时/重复/低质量文档
- 增量索引:只更新变化部分,避免全量重建