本文档基于论文 《Corrective Retrieval Augmented Generation》(arXiv:2401.15884v3),说明其提出的改良 RAG 方法,并给出在本项目中实现“基于知识库的问答机器人”的算法步骤与设计说明。
- 大模型幻觉:LLM 仅依赖参数知识难以保证生成内容的准确性,容易产生事实性错误与幻觉。
- 传统 RAG 的局限:检索增强生成(RAG)通过从外部知识库检索文档来增强输入,但其效果强依赖检索结果的相关性。若检索返回不相关或错误文档,反而会向生成器注入噪声,误导回答甚至加剧幻觉。
- 现有做法的不足:多数 RAG 会无差别地使用检索到的文档,且常把整篇文档当作参考,而文档中往往包含大量与问题无关的冗余内容。
CRAG 针对“检索出错时如何自我纠正”这一问题,提出一套可插拔的纠正策略,在保持与各类 RAG 兼容的前提下,提升生成的鲁棒性与知识利用效率。
- 先评估、再决策:用轻量级检索评估器对“问题–文档”相关性打分,得到整体置信度,再据此触发不同动作(Correct / Incorrect / Ambiguous)。
- 三种动作:
- Correct:认为检索结果可靠 → 对文档做知识精炼(分解–过滤–重组),只保留关键信息。
- Incorrect:认为检索结果不可靠 → 弃用检索结果,改用网络搜索等外部知识进行纠正。
- Ambiguous:置信度介于两者之间 → 同时使用精炼后的检索知识 + 网络搜索知识,软性融合。
- 知识精炼:对单篇文档做 Decompose-then-Recompose(分解–筛选–重组),按“条”(strip)评估相关性,过滤无关条、保留相关条并重组,形成更干净的内部知识。
- 网络搜索扩展:当检索被判为 Incorrect(或 Ambiguous 时作为补充)时,将问题改写成搜索查询,调用网络搜索(优先 Wikipedia 等权威来源),并对爬取内容同样做知识精炼,得到外部知识。
整体上,CRAG 是即插即用的:不改变底层检索器与生成器的接口,只在“检索结果 → 生成器输入”之间插入“评估 + 动作 + 知识精炼/网络搜索”的管道。
| 维度 | 传统 RAG | CRAG |
|---|---|---|
| 检索结果使用 | 通常无差别全部喂给生成器 | 先评估相关性,再决定用/不用/怎么用 |
| 文档粒度 | 多以整篇文档为单位 | 分解为“知识条”,按条过滤后重组 |
| 检索失败时 | 仍用错误文档,易导致幻觉 | Incorrect 时弃用检索,改用网络搜索 |
| 置信不确定时 | 无专门策略 | Ambiguous:内部精炼知识 + 外部搜索知识结合 |
因此,CRAG 的改进可以概括为:检索质量评估 + 基于置信度的动作分支 + 知识精炼(Decompose-then-Recompose)+ 网络搜索兜底与补充。
输入:用户问题 (x),检索得到的文档集合 (D = {d_1, d_2, \ldots, d_k})。
输出:生成回答 (y)。
涉及组件:
- (E):检索评估器
- (W):查询改写器(用于网络搜索)
- (G):生成器
步骤:
- 评估:对每个 ((x, d_i)) 用 (E) 打分,得到 (\text{score}_i)。
- 置信度与动作:根据 ({\text{score}_1, \ldots, \text{score}_k}) 得到整体判断,置信度取三者之一:
[CORRECT]/[INCORRECT]/[AMBIGUOUS](通过上、下阈值划分)。 - 知识准备:
- 若 Correct:(k \leftarrow \text{Knowledge_Refine}(x, D))(仅用精炼后的内部知识)。
- 若 Incorrect:(k \leftarrow \text{Web_Search}(W(x)))(仅用外部搜索知识,(W) 将问题改写成搜索查询)。
- 若 Ambiguous:(k \leftarrow \text{Knowledge_Refine}(x, D) + \text{Web_Search}(W(x)))(内部 + 外部)。
- 生成:(y \leftarrow G(x, k))。
其中:
- Knowledge_Refine:对 (D) 中文档做分解(切成多条)、用 (E) 对每条打分、过滤低分条、按顺序拼接成“内部知识”。
- Web_Search:用 (W(x)) 得到搜索查询 → 调用搜索 API → 获取页面/摘要 → 同样做分解与评估筛选,得到“外部知识”。
- 作用:判断“问题–文档”或“问题–知识条”的相关性,输出连续分数(如 [-1, 1])。
- 论文实现:基于 T5-large 微调,轻量(约 0.77B),对每个 (question, document) 单独打分。
- 实现要点:
- 可用小模型(如 T5、BERT 类)或轻量 LLM,输入为
"[CLS] question [SEP] document"或类似格式,输出为标量分数或二分类(相关/不相关)再映射为分数。 - 若无现成评估器,可用 LLM(如 Ollama/OpenAI)做“是否包含回答问题所需信息”的判别,并将 yes/no 映射为分数(例如 1 / -1),用于阈值判断。
- 可用小模型(如 T5、BERT 类)或轻量 LLM,输入为
- 输入:各文档的 score(或各知识条的 score 的聚合,如 max/mean)。
- 逻辑:
- 若 任一 score > 上阈值 → Correct。
- 若 全部 score < 下阈值 → Incorrect。
- 否则 → Ambiguous。
- 阈值:论文中按数据集设不同值(如 PopQA 用 0.59 / -0.99);本项目中可先设一组默认值,再按验证集调参。
- 分解:将每篇文档切成“条”(strip)。短文可 1–2 句一条;长文按句或按固定 token 数切分为若干段,每段视为一条。
- 打分与过滤:对每条 strip,用同一评估器 (E) 计算与问题 (x) 的 score;去掉 score 低于某阈值的条(论文中如 -0.5),或保留 top-k 条(如 top-5)。
- 重组:将保留的条按原顺序拼接,得到“内部知识”文本,作为后续生成上下文。
- 查询改写:用 (W) 将用户问题 (x) 改写成适合搜索引擎的短查询(论文用 LLM 抽 2–3 个关键词)。
- 搜索与抓取:调用搜索 API(如 Serper、Google Custom Search、Bing 等)得到 URL 列表;优先选 Wikipedia 等权威站点,抓取正文或摘要。
- 精炼:对抓取到的文本做与 4.3 相同的“分解–打分–过滤–重组”,得到“外部知识”。
若本地仅做知识库问答、不做真实网络搜索,可将“Web Search”替换为:从另一更大知识库/维基摘要库中再检索一轮,或返回“当前知识库未覆盖,建议联网搜索”的占位逻辑,以保留 CRAG 的决策结构。
- 输入:用户问题 (x) + 上述得到的知识 (k)(可能为内部知识、外部知识或两者拼接)。
- 使用任意兼容的 RAG 生成接口即可(如 LangChain / LangGraph / PydanticAI / Agno 的 RAG 链),只需保证 prompt 中包含 (k) 作为 context。
实现一个基于知识库的问答机器人(命令行即可),采用 CRAG 的“评估 → 动作 → 知识准备 → 生成”流程,可选地接入网络搜索或“二次检索”作为 Incorrect/Ambiguous 的补充。
- 框架:LangChain / LangGraph / PydanticAI / Agno 任选,用于:检索(向量库)、链/图编排、与 LLM 对话。
- 知识库:本地向量库(如 Chroma、FAISS)+ 文本切分(RecursiveCharacterTextSplitter 等),与现有
LangChain_RAG_Proj类似。 - 检索评估器:
- 简化版:用同一 LLM(Ollama/OpenAI)对“(问题, 文档)”做 yes/no 判断并映射为分数,无需单独训练模型。
- 完整版:使用在 (question, document) 数据上微调的小模型(如 sentence-transformers + 分类头)输出相关性分数。
- 生成器:与现有 RAG 项目一致,使用 Ollama 或 OpenAI 等,以“问题 + 精炼后的知识”为 context 生成回答。
-
基础 RAG 管道
- 加载本地知识库(文档切分、向量化、建索引)。
- 实现:用户问题 → 检索 top-k 文档 → 拼成 context → 调用 LLM 生成。
- 确保单轮问答在命令行可跑通。
-
检索评估器
- 实现接口:
score = evaluator(question, document),返回 float。 - 简化实现:用 LLM 对 “问题 + 文档片段” 做“是否包含回答问题所需信息”的判断,映射为 1.0 / -1.0(或 0/1 再缩放)。
- 可选:对“文档条”也复用同一接口,便于后续知识精炼。
- 实现接口:
-
动作触发
- 输入:每个检索文档的 score。
- 实现:根据上、下阈值得到 Correct / Incorrect / Ambiguous;
- 输出:动作类型 + 用于下一步的“待精炼文档集合”和“是否需要网络搜索”的标志。
-
知识精炼(Decompose-then-Recompose)
- 对“待精炼文档”按句或按块切分为 strips;
- 对每条 strip 调用评估器打分;
- 过滤低分条(或取 top-k),按顺序拼接成一段“精炼知识”字符串。
- 该字符串作为“内部知识”传入生成器。
-
网络搜索(或替代方案)
- 若有 API:实现查询改写 (W(x))(可用同一 LLM)+ 搜索 API + 结果抓取/摘要;对结果做与步骤 4 相同的精炼,得到“外部知识”。
- 若无 API:用“二次检索”(从更大知识库或不同 chunk 再检一轮)或固定提示“知识库未覆盖该问题”作为 Incorrect/Ambiguous 的替代。
-
CRAG 主流程编排
- 串联:检索 → 评估 → 动作判断 →
- Correct:仅知识精炼 → 生成;
- Incorrect:仅外部知识(或替代)→ 生成;
- Ambiguous:精炼知识 + 外部知识拼接 → 生成。
- 在命令行读入用户问题,输出最终回答;可同时打印当前动作(Correct/Incorrect/Ambiguous)便于调试。
- 串联:检索 → 评估 → 动作判断 →
-
调参与扩展
- 调节上/下阈值、精炼时的 strip 长度与 top-k、检索的 top-k;
- 可选:记录每轮动作与分数,用于分析检索质量与 CRAG 行为。
用户问题 x
↓
[检索器] → 文档集合 D
↓
[评估器 E] → 每个 (x, d_i) 的 score_i
↓
[动作触发] → Correct / Incorrect / Ambiguous
↓
┌─────────┼─────────┐
↓ ↓ ↓
Correct Incorrect Ambiguous
↓ ↓ ↓
Refine(D) Web(W(x)) Refine(D) + Web(W(x))
↓ ↓ ↓
└─────────┴─────────┘
↓
知识 k
↓
[生成器 G] → 回答 y
README.md:本文档(论文解读 + 算法与实现说明)。config.py或config.yaml:阈值、top-k、评估器/生成器模型名、是否启用网络搜索等。evaluator.py:检索评估器封装(LLM 或小模型)。refinement.py:知识精炼(分解、打分、过滤、重组)。search.py(可选):查询改写 + 网络搜索/二次检索 + 结果精炼。crag.py或pipeline.py:CRAG 主流程(检索 → 评估 → 动作 → 知识准备 → 生成)。cli.py或main.py:命令行入口,读入问题、调用 pipeline、打印回答与(可选)动作类型。requirements.txt:依赖(如 langchain、chromadb、ollama/openai 等)。
- 论文:Corrective Retrieval Augmented Generation (Shi-Qi Yan, Jia-Chen Gu, Yun Zhu, Zhen-Hua Ling), arXiv:2401.15884v3.
- 官方代码(论文中提及):github.com/HuskyInSalt/CRAG。
本目录下已实现完整 CRAG 流程,通过 Streamlit 提供交互界面;知识库路径为项目根目录下的 Files/,用户将 PDF 放入该目录后通过「构建知识库」即可使用。PDF 的文本识别与版面分析使用 MinerU 完成。
CRAG/
├── config.py # 路径、阈值、LLM/Embedding 配置
├── pdf_loader.py # MinerU:PDF → 版面抽取 → Document
├── vector_store.py # Chroma 向量库封装
├── knowledge_base.py # 从 Files/ 加载 PDF → 切分 → 写入向量库
├── evaluator.py # 检索评估器(问题-文档相关性 1.0/-1.0)
├── refinement.py # 知识精炼(Decompose-then-Recompose)
├── action_trigger.py # 动作触发:Correct / Incorrect / Ambiguous
├── search.py # 外部知识:查询改写 + 网络搜索占位
├── agent_model.py # PydanticAI 模型与 Agent(通义 qwen3-max)
├── crag.py # CRAG 主流程:检索→评估→动作→知识准备→生成
├── app_streamlit.py # Streamlit 交互界面
├── MinerU_Test.py # MinerU 相关测试脚本
├── requirements.txt # Python 依赖
├── Files/ # 知识库 PDF 目录(用户放入 PDF)
├── chroma_db/ # 向量库持久化(自动生成)
└── 运行截图/ # 运行效果截图
| 文件/目录 | 说明 |
|---|---|
config.py |
路径、阈值、LLM/Embedding 提供商与模型名等配置 |
pdf_loader.py |
基于 MinerU:PDF 每页转图像 → 版面抽取 → 文本块整理为 Document |
vector_store.py |
Chroma 向量库封装,Ollama/OpenAI/通义等 Embedding |
knowledge_base.py |
从 Files/ 加载 PDF(MinerU)→ 切分 → 写入向量库 |
evaluator.py |
检索评估器:PydanticAI 模型判断「问题-文档」是否相关,输出 1.0 / -1.0 |
refinement.py |
知识精炼:分解 → 打分 → 过滤 → 重组(Decompose-then-Recompose) |
action_trigger.py |
根据分数触发 Correct / Incorrect / Ambiguous |
search.py |
外部知识:查询改写 + 网络搜索占位(可扩展真实 API) |
agent_model.py |
PydanticAI 模型与 Agent(qwen3-max/通义),供评估与生成 |
crag.py |
CRAG 主流程:检索 → 评估 → 动作 → 知识准备 → 生成(LLM 走 PydanticAI) |
app_streamlit.py |
Streamlit 交互界面:输入问题、查看回答与动作类型、侧栏重建知识库 |
MinerU_Test.py |
MinerU 相关测试脚本 |
Files/ |
知识库 PDF 目录:用户在此放入 PDF,构建知识库时自动识别 |
chroma_db/ |
向量库持久化目录(自动生成) |
运行截图/ |
运行效果截图(如建立知识库、问答示例) |
requirements.txt |
Python 依赖列表 |
- Python ≥ 3.10
- 若使用 MinerU 做 PDF 识别:需 GPU 且已安装 PyTorch、transformers ≥ 4.56.0
- 若仅用 Ollama 本地模型:需已安装 Ollama 并拉取所用模型(如
qwen3:4b、nomic-embed-text)
在项目根目录执行:
pip install -r requirements.txt若使用 Ollama 且不需要 MinerU(例如先用已有向量库或纯文本导入),可先不装 MinerU 相关依赖(mineru-vl-utils、modelscope、transformers 等),仅安装 LangChain、Chroma、Streamlit 等;此时「构建知识库」需通过其他方式导入文档。
使用 MinerU 时建议:
pip install torch transformers modelscope mineru-vl-utils PyMuPDF- 编辑
config.py或通过环境变量:CRAG_LLM_PROVIDER:ollama/openai/dashscopeCRAG_LLM_MODEL:LLM 模型名(默认qwen3-max)CRAG_EMBEDDING_PROVIDER:ollama/openai/dashscopeCRAG_OLLAMA_LLM、CRAG_OLLAMA_EMBED:Ollama 模型名(当 provider 为 ollama 时)DASHSCOPE_API_KEY或DASH_API_KEY:通义 API Key(dashscope 时)OPENAI_API_KEY、OPENAI_API_BASE:OpenAI 或兼容 API
- 知识库路径为项目根目录下的
Files/,将 PDF 放入该目录即可。 - PDF 识别强制使用 MinerU(无 PyMuPDF 回退)。
- 将需要入库的 PDF 放入项目根目录下的
Files/。 - 启动 Streamlit 后,在侧边栏点击「重新构建知识库」。
构建过程会使用 MinerU 对每个 PDF 逐页做版面分析与文本抽取,切分后写入 Chroma。
streamlit run app_streamlit.py浏览器打开提示的地址(通常 http://localhost:8501),在输入框输入问题即可;可展开「查看使用的参考资料」查看 CRAG 实际使用的上下文与动作类型。
- 准备知识库:将 PDF 放入项目根目录下的
Files/,执行一次「构建知识库」(Streamlit 侧栏「重新构建知识库」)。 - 启动服务:运行
streamlit run app_streamlit.py。 - 提问:在 Streamlit 输入框发送问题,系统按 CRAG 流程:检索 → 评估 → 触发 Correct/Incorrect/Ambiguous → 精炼或补充知识 → 生成回答。
- 更新知识库:新增或更换 PDF 后,再次在界面点击「重新构建知识库」。
本文档为 CRAG 算法在“基于知识库的问答机器人”中的实现说明;当前实现已包含检索评估、动作触发、知识精炼与占位式外部知识,并按完成 PDF 识别。