系列导航
📍 第 1 篇:CRAG 架构与置信度路由(本文)
📄 第 2 篇:RRF 混合检索 + BGE 重排序
📄 第 3 篇:语义切片 + Ragas 评估体系
📄 第 4 篇:生产环境部署与优化
摘要
传统 RAG 系统的致命缺陷在于"盲目自信"——无法判断检索质量,即使返回的文档完全不相关也会硬着头皮生成答案。本文介绍 CRAG(Corrective RAG)架构,通过"置信度评估→动态路由"机制让 RAG 具备自我反思能力,在 Agentic RAG 知识库专家系统中实现 Context Recall +26%(0.62→0.78)、Faithfulness 0.85 的效果提升。
环境依赖:Python 3.11+, LangGraph 0.2.0+, OpenAI SDK 1.12.0+, Qdrant Client 1.7.0+
引言:一个让所有 RAG 开发者头疼的场景
你花了两周时间搭建 RAG 系统:精心调优 Embedding 模型、配置向量数据库、设计 Prompt 模板。上线第一天,用户问了一个问题:"公司的远程办公政策是什么?"
检索模块返回了 5 个文档:
- 文档 1:2019 年的考勤制度(已过期)
- 文档 2:会议室预订流程(完全无关)
- 文档 3:2023 年远程办公政策(相关!)
- 文档 4:某个员工的请假申请(噪音)
- 文档 5:IT 设备借用规定(弱相关)
传统 RAG 会怎么做?把这 5 个文档全部塞进 Prompt,让 LLM 生成答案。结果?模型被噪音文档误导,输出了一个看似专业但实际错误的答案——混合了过期政策和无关信息。
这不是个例。在实际生产环境中,检索质量问题是 RAG 系统失败的主要原因之一。问题的本质在于:传统 RAG 缺少"评估"环节,无法判断检索结果是否可信,更无法采取补救措施。
如何让 RAG 系统"知道它不知道"?这是本文要解决的核心问题。
传统 RAG 的"盲目自信"困境
传统 RAG 的工作流程是一条固定流水线:
用户提问 → 向量检索 → 拼接上下文 → LLM 生成答案
这个流程有三个致命缺陷:
1. 无质量评估
检索模块返回 Top-K 文档后,系统不会判断这些文档是否真的相关。即使相似度分数很低(比如 0.3),也会被当作"有效上下文"送入 LLM。
2. 无反馈机制
当检索失败时(比如知识库中根本没有相关文档),系统不会尝试其他策略,而是直接让 LLM 基于空洞的上下文"硬编"答案。
3. 无动态路由
所有问题都走同一条路径,无论是简单的事实查询("公司地址是什么?")还是复杂的推理问题("如何优化跨部门协作流程?"),都用相同的检索策略处理。
用架构图表示:
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
│ 用户提问 │ ──→ │ 向量检索 │ ──→ │ 拼接上下文│ ──→ │ LLM 生成 │
└─────────┘ └─────────┘ └─────────┘ └─────────┘
↓
返回答案
这是一条单向直线,没有分支、没有回退、没有自我修正。
量化这个问题:在我的测试数据集上,传统向量检索的 Context Recall 只有 0.62——意味着 38% 的相关信息根本没被检索到。更糟糕的是,Faithfulness(答案忠实度)只有 0.72,说明生成的答案经常偏离事实。
CRAG 登场:给 RAG 装上"自我反思"模块
CRAG(Corrective RAG)由 Shi-Qi Yan 等人在 2024 年提出(arXiv:2401.15884),核心思想只有一句话:
在检索和生成之间插入一个"相关性评估"节点,根据评估结果动态选择后续路径。
这个简单的改动带来了本质变化:RAG 从"流水线"变成了"状态机"。
CRAG 的完整流程:
┌─────────────┐
│ 用户提问 │
└──────┬──────┘
↓
┌─────────────┐
│ 向量检索 │
└──────┬──────┘
↓
┌─────────────┐
│ 置信度评估 │ ← 核心创新
└──────┬──────┘
↓
┌────────────┼────────────┐
↓ ↓ ↓
置信度≥7 3≤置信度<7 置信度<3
↓ ↓ ↓
┌─────────┐ ┌─────────┐ ┌─────────┐
│直接生成 │ │查询重写 │ │Web搜索 │
└─────────┘ └────┬────┘ └────┬────┘
↓ ↓
┌─────────┐ ┌─────────┐
│二次检索 │ │外部知识 │
└────┬────┘ └────┬────┘
↓ ↓
┌─────────────────┐
│ LLM 生成答案 │
└─────────────────┘
对比传统 RAG,CRAG 的本质变化是:
| 维度 | 传统 RAG | CRAG |
|---|---|---|
| 架构模式 | 固定流水线 | 动态状态机 |
| 质量评估 | 无 | 置信度打分(0-10) |
| 失败处理 | 硬着头皮生成 | 查询重写 / Web 回退 |
| 路由策略 | 单一路径 | 3 条分支(高/中/低置信度) |
| 自我修正 | 不支持 | 支持(最多 2 次重试) |
这就是"自我反思"的含义:系统能够评估自己的检索结果,并根据评估结果调整行为。
置信度路由:3/7 阈值是怎么来的?
CRAG 的核心是"置信度评估器"。但如何设计这个评估器?阈值怎么定?
评估器设计
我使用 gpt-4o-mini 作为评估器(而不是 gpt-4o),原因有三:
- 分类任务足够:判断文档相关性是分类问题,不需要强推理能力
- 延迟降低 10-20 倍:gpt-4o-mini 平均延迟 200ms,gpt-4o 需要 2-3s
- 成本降低 50 倍:评估器会被频繁调用,成本敏感
评估器的输入是"用户问题 + 检索到的文档",输出是:
- 置信度分数(0-10):文档与问题的相关性
- 推理理由:为什么给这个分数(用于调试)
代码实现:
from openai import OpenAI
from typing import List, Dict
client = OpenAI()
def evaluate_relevance(query: str, documents: List[str]) -> Dict:
"""
评估检索文档与查询的相关性
Args:
query: 用户查询
documents: 检索到的文档列表
Returns:
{
"confidence": float, # 0-10 的置信度分数
"reasoning": str # 评估理由
}
"""
# 构建评估 prompt
docs_text = "\n\n".join([f"文档 {i+1}:\n{doc}" for i, doc in enumerate(documents)])
prompt = f"""你是一个文档相关性评估专家。请评估以下检索文档与用户查询的相关性。
用户查询:{query}
检索到的文档:
{docs_text}
请按以下格式输出:
1. 置信度分数(0-10):
- 0-3: 文档完全不相关或严重偏离主题
- 4-6: 文档部分相关但信息不完整
- 7-10: 文档高度相关且包含足够信息
2. 评估理由:简要说明为什么给出这个分数
输出格式:
分数: [0-10的数字]
理由: [你的评估理由]"""
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": prompt}],
temperature=0 # 降低随机性,保证评估稳定
)
# 解析输出
content = response.choices[0].message.content
lines = content.strip().split('\n')
confidence = 5.0 # 默认值
reasoning = ""
for line in lines:
if line.startswith("分数:"):
try:
confidence = float(line.split(":")[1].strip())
except:
pass
elif line.startswith("理由:"):
reasoning = line.split(":", 1)[1].strip()
return {
"confidence": confidence,
"reasoning": reasoning
}
# 使用示例
query = "Transformer 的注意力机制是什么?"
documents = [
"Transformer 使用自注意力机制来处理序列数据...",
"CNN 是一种卷积神经网络..."
]
result = evaluate_relevance(query, documents)
print(f"置信度: {result['confidence']}")
print(f"理由: {result['reasoning']}")
阈值选择的消融实验
论文建议的阈值是 (3, 7),但我不想盲目照搬。我在 50 个测试问题上尝试了三组阈值:
| 阈值组合 | 直接生成率 | 查询重写率 | Web 回退率 | Context Recall | 平均延迟 |
|---|---|---|---|---|---|
| (5, 8) | 12% | 64% | 24% | 0.71 | 3.8s |
| (4, 7) | 38% | 48% | 14% | 0.75 | 2.9s |
| (3, 7) | 58% | 32% | 10% | 0.78 | 2.3s |
为什么 (3, 7) 最优?
-
(5, 8) 的问题:高置信度区间过窄(8-10),导致大量中等质量的检索被降级到"查询重写",效率低下。比如"公司地址是什么?"这种简单问题,检索到的文档置信度是 7.5,本应直接生成,却被强制重写。
-
(4, 7) 的问题:效果中等,但低置信度阈值 4 太高,一些"勉强相关"的文档(置信度 3.5)被直接回退到 Web 搜索,浪费了知识库中的有效信息。
-
(3, 7) 的优势:
- 简单问题(事实查询)99% 的置信度≥7,直接生成,节省 token
- 边界问题(模糊查询)触发查询重写,成功率高
- 只有真正"检索不到"的问题(置信度<3)才回退 Web,避免过度依赖外部搜索
三条路由详解
路由 1:置信度≥7 → 直接生成
适用场景:检索到的文档高度相关,可以直接回答问题。
示例:"公司的年假政策是什么?" → 检索到《员工手册-休假制度》,置信度 9.2 → 直接生成。
路由 2:3≤置信度<7 → 查询重写
适用场景:检索结果中等质量,可能是用户问题表述不清或关键词不匹配。
示例:"怎么申请在家办公?" → 检索到《考勤管理办法》(弱相关),置信度 5.1 → 重写为"远程办公申请流程" → 二次检索到《远程办公管理规定》,置信度 8.7 → 生成答案。
路由 3:置信度<3 → Web 搜索
适用场景:知识库中没有相关信息,需要外部知识补充。
示例:"2026 年劳动法对加班的最新规定是什么?" → 知识库中没有最新法规,置信度 1.8 → 回退到 Web 搜索 → 获取外部信息 → 生成答案。
这三条路由的设计哲学是:优先使用内部知识(快且可控),必要时才求助外部(慢但全面)。
实验对比:CRAG 到底好在哪里?
我在 Agentic RAG 知识库专家系统中进行了对比实验,测试数据集包含 120 个真实用户问题(涵盖事实查询、推理问题、时效性问题)。
| 策略 | Context Recall | Faithfulness | 说明 |
|---|---|---|---|
| 纯向量检索 | 0.62 | 0.72 | Baseline(传统 RAG) |
| 混合检索(RRF) | 0.70 | 0.78 | +13% / +8% |
| 混合 + Reranker | 0.74 | 0.82 | +19% / +14% |
| 完整 CRAG | 0.78 | 0.85 | +26% / +18% |
为什么 CRAG 在 Context Recall 上提升最大?
Context Recall 衡量的是"相关信息的召回率"——系统是否找到了所有应该找到的信息。CRAG 的提升来自两个机制:
-
查询重写:当初次检索失败时,重写查询可以用不同的关键词再试一次。比如用户问"如何请假",初次检索用"请假"作为关键词,可能匹配不到《休假管理制度》;重写为"休假申请流程"后,成功匹配。
-
Web 回退:当知识库中确实没有信息时,Web 搜索可以补充外部知识。这直接解决了"检索不到"的问题——传统 RAG 会返回空结果,CRAG 会去外部找答案。
Faithfulness 的提升则来自"高质量上下文":通过置信度过滤,低质量文档不会进入生成阶段,减少了 LLM 被噪音误导的概率。
实践中的踩坑与优化
坑 1:评估器延迟过高
问题:最初使用 gpt-4o 作为评估器,每次评估耗时 2-3s,导致整体延迟飙升到 5-6s。
解决:换成 gpt-4o-mini,延迟降低到 200ms,效果几乎无损(分类任务不需要强推理)。
坑 2:查询重写陷入死循环
问题:某些问题重写后仍然检索不到相关文档,系统会不断重写→检索→重写,陷入死循环。
解决:设置最大重试次数为 2。如果两次重写后置信度仍<7,直接回退到 Web 搜索。
坑 3:Web 搜索结果格式不统一
问题:Web 搜索返回的是 HTML 片段,格式与知识库文档不一致,导致后续处理出错。
解决:封装统一的 Document 结构,所有外部来源的内容都转换为标准格式(包含 page_content、metadata、source 字段)。
坑 4:置信度分数不稳定
问题:同一个问题多次评估,置信度分数波动较大(比如 6.8 → 7.2 → 6.5),导致路由不稳定。
解决:在 Prompt 中增加 few-shot 示例,明确"7 分代表什么程度的相关性",稳定输出格式。同时在评估器中加入温度参数 temperature=0,减少随机性。
总结与下期预告
CRAG 的核心创新在于"评估→路由"机制,让 RAG 系统具备了自我反思能力:
- 能评估:通过置信度打分判断检索质量
- 能修正:通过查询重写和 Web 回退补救失败
- 能决策:根据置信度动态选择最优路径
在 Agentic RAG 知识库专家系统中,CRAG 实现了:
- Context Recall +26%(0.62 → 0.78)
- Faithfulness 0.85
- P95 延迟 2.3s
但 CRAG 只是第一步。置信度评估依赖的是"检索到的文档是否相关",但如何提升检索本身的质量?下期我将深入解析:
- RRF 混合检索:如何融合向量检索和关键词检索的优势
- BGE 重排序:如何用 Reranker 模型进一步过滤噪音
开源地址:github.com/Yunzenn/age…
欢迎 Star / Issue / PR,一起探索 Agentic RAG 的更多可能性。
本文是"从零开始理解 Agentic RAG"系列的第 1 篇,聚焦 CRAG 核心架构。后续文章将深入检索优化、评估体系、生产部署等话题。