RAG 进阶——HyDE、Self-RAG、CRAG 三种增强检索实战
基础 RAG 准确率 70% 出头。HyDE、Self-RAG、CRAG 三种增强检索,能把准确率推到 90%+。
基础 RAG 的局限
经典 RAG 流程:
- 用户问题 → 向量化
- 向量数据库检索 Top-K
- 拼接 Prompt(检索内容 + 问题)
- LLM 生成回答
问题:
- 用户问题简短(“年假几天?”)
- 检索时语义匹配不准——问题太短,embedding 信息不够
- 容易召回不相关文档
实测:基础 RAG 在企业知识库上,准确率 65-75%。
进阶方案 1:HyDE(Hypothetical Document Embeddings)
核心思想
先让 LLM 生成”假想答案”,再用假想答案去检索。
1 2 3 4 5 6 7 8
| 问题: "年假几天?"
传统 RAG: embedding("年假几天?") → 检索
HyDE: LLM("假设你是 HR,请回答:年假几天?") → "员工每年享有 7 天年假..." embedding("员工每年享有 7 天年假...") → 检索
|
假想答案比”问题”信息密度高——embedding 检索更准。
实现
1 2 3 4 5 6 7 8 9 10
| def hyde_retrieve(question, llm, vector_db, top_k=5): hypothetical = llm( f"请根据你的知识,回答以下问题:\n{question}\n" f"回答要详细具体,像真实文档一样。" ) results = vector_db.search(hypothetical, top_k=top_k) return results
|
效果
准确率提升 10-15%——特别适合”问题简短、文档丰富”的场景。
代价:多一次 LLM 调用,Token 消耗 +50%。
适用场景
✅ 短问题(“怎么报销?”)
✅ 专业领域(模型有基础知识)
❌ 不适合:模型不熟悉的话题(假想答案会错)
进阶方案 2:Self-RAG
核心思想
让 LLM 自己判断”检索到的内容是否相关”。
1 2 3 4 5 6 7
| 传统 RAG: 问题 → 检索 Top-K → 拼给 LLM → 回答
Self-RAG: 问题 → 检索 Top-K → LLM 判断每条是否相关 [Special Token: RELEVANT] → 只用相关的拼 Prompt → 回答
|
Self-RAG 引入了 4 个特殊 token:
[Retrieve]:是否需要检索
[IsRel]:检索结果是否相关
[IsSup]:回答是否被检索结果支持
[IsUse]:回答是否有用
实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| def self_rag(question, llm, vector_db): docs = vector_db.search(question, top_k=10) relevant_docs = [] for doc in docs: prompt = f""" 问题:{question} 文档:{doc.content} 请判断该文档是否与问题相关。 如果相关,回答 [IsRel] Yes,然后说明理由。 如果不相关,回答 [IsRel] No。 """ response = llm(prompt) if "[IsRel] Yes" in response: relevant_docs.append(doc) if not relevant_docs: return "未找到相关信息" context = "\n".join([d.content for d in relevant_docs]) answer = llm(f"基于以下信息回答问题:\n{context}\n问题:{question}") return answer
|
效果
准确率提升 15-20%——过滤掉”看似相关实则无关”的文档。
适用场景
✅ 文档质量参差不齐
✅ 检索召回率高但准确率低
✅ 业务对准确率要求极高
进阶方案 3:CRAG(Corrective RAG)
核心思想
Self-RAG 的进化版——不仅判断相关性,还自动采取修正动作。
1 2 3 4
| 检索结果分类: Correct(正确) → 直接用 Incorrect(错误) → 触发 Web 搜索补充 Ambiguous(模糊) → 混合原始 + Web 结果
|
实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| def crag(question, llm, vector_db, web_search): docs = vector_db.search(question, top_k=5) confidence = evaluate_retrieval(question, docs, llm) if confidence > 0.7: context = "\n".join([d.content for d in docs]) return llm(f"基于:\n{context}\n回答:{question}") elif confidence > 0.3: web_results = web_search(question, top_k=3) context = "\n".join([d.content for d in docs] + web_results) return llm(f"基于:\n{context}\n回答:{question}") else: web_results = web_search(question, top_k=5) context = "\n".join(web_results) return llm(f"基于:\n{context}\n回答:{question}")
|
置信度评估
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| def evaluate_retrieval(question, docs, llm): prompt = f""" 问题:{question} 检索到的文档:{[d.content[:200] for d in docs]} 请评估这些文档是否能回答问题,返回 0-1 的置信度: - 1.0: 完全能回答 - 0.5: 部分相关,需要补充 - 0.0: 完全无关 """ response = llm(prompt) match = re.search(r'(\d+\.\d+)', response) return float(match.group(1)) if match else 0.5
|
效果
准确率提升 20-25%——自动修正检索错误。
代价:每条问题多 2-3 次 LLM 调用,Token 消耗 +200%。
适用场景
✅ 内部知识库不完整(部分问题文档没覆盖)
✅ 需要结合外部信息
✅ 业务对准确率要求极高
三种方案对比
| 维度 |
HyDE |
Self-RAG |
CRAG |
| 准确率提升 |
+10-15% |
+15-20% |
+20-25% |
| Token 成本 |
+50% |
+100% |
+200% |
| 实现复杂度 |
简单 |
中等 |
复杂 |
| 适用场景 |
短问题 |
文档质量参差 |
知识库不全 |
实战组合方案
实际项目中,三种方案可以组合使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| def advanced_rag(question, llm, vector_db, web_search): hypothetical = llm(f"请详细回答:{question}") docs = vector_db.search(hypothetical, top_k=10) relevant = filter_relevant(question, docs, llm) if len(relevant) < 3: web_results = web_search(question, top_k=5) relevant.extend(web_results) context = "\n".join([d.content for d in relevant]) return llm(f"基于:\n{context}\n回答:{question}")
|
这套组合拳:
- HyDE 提升召回率
- Self-RAG 提升准确率
- CRAG 保证完整性
我的项目实战数据
我做了 A/B 测试——
对照组:基础 RAG,准确率 68%
实验组:HyDE + Self-RAG + CRAG 组合,准确率 89%
绝对提升 21 个百分点——业务上的体感是”完全可用 → 接近人工水平”。
成本对比:
- 对照组:$0.002 / 查询
- 实验组:$0.012 / 查询(6 倍成本)
值不值?看业务——客服场景,$0.012 / 次换一个 89% 准确的回答,完全值。
几个关键经验
1. 不要过度优化
如果基础 RAG 已经达到 80%+ 准确率——别上 HyDE、Self-RAG。
边际收益递减——从 80% 推到 89% 成本 6 倍,从 60% 推到 89% 成本也 6 倍。
2. 评估是基础
没有评估指标,所有优化都是盲改。
1 2 3 4 5 6 7 8 9 10 11 12 13
| test_questions = [...] results = []
for q in test_questions: answer = rag(q) expected = q.expected_answer is_correct = llm(f"问题:{q.question}\n回答:{answer}\n标准:{expected}\n回答对吗?") results.append(is_correct)
accuracy = sum(results) / len(results)
|
3. 优化检索比重排序更有效
很多时候问题不是 RAG 架构,是检索质量。
优化检索:
- 更好的 embedding 模型
- 更好的文档分段
- 混合检索(BM25 + 向量)
- Query 改写
这些比 HyDE/Self-RAG 更基础、更有效。
4. 监控 + 持续优化
RAG 系统需要持续优化——
1 2 3 4 5
| for qa in user_conversations: if qa.user_feedback == "不准确": save_to_review_queue(qa)
|
写在最后
RAG 进阶方案,核心是**”提升检索质量 + 修正错误”**。
但记住:架构不是万能药——基础 RAG 80% 准确率时,先优化文档分段和 embedding 模型,再考虑架构升级。
RAG 工程的本质,是”用工程手段弥补 LLM 的不足”——HyDE/Self-RAG/CRAG 是工具,不是答案。