Files
rag/docs/Agentic_RAG完整指南.md
lacerate551 100d1a06eb init: RAG 知识库服务初始提交
- 后端 API(Flask + Gunicorn)
- RAG 引擎(混合检索 + 云端 Reranker + 引用溯源)
- 文档解析(MinerU + 多格式支持)
- Docker 生产部署配置
- 排除前端项目、敏感配置、模型文件
2026-06-04 17:35:27 +08:00

880 lines
41 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Agentic RAG 完整指南
> **版本**: v3.1 (文档勘误修正)
> **生产入口**: `api/chat_routes.py::rag()` → `core/engine.py`(轻量编排,当前启用)
> **备用编排**: `core/agentic.py::AgenticRAG.process()` + 8 个 Mixin完整决策循环未接线
> **最后更新**: 2026-06-03
>
> ⚠️ 项目存在两套编排,生产 `/rag` 走的不是 `AgenticRAG`——详见下方「一·五、两套编排路径」。
## 一、功能概述
Agentic RAG 是一个智能问答系统,基于 Mixin 模式组合 8 个功能模块,具备以下核心能力:
| 功能 | 说明 | Mixin 模块 |
|------|------|-----------|
| **意图分析** | LLM 驱动的查询改写 + 双层判断(是否需要检索) | `IntentAnalyzer`(独立模块) |
| **查询重写** | 口语化→专业术语、实体补全、指代消解 | `QueryRewriteMixin` |
| **混合检索** | 向量检索 + BM25 + RRF 融合 + Rerank 重排 | `SearchMixin``RAGEngine` |
| **多源融合** | 知识库 + 网络搜索 + 知识图谱,智能处理冲突 | `AnswerMixin` |
| **幻觉验证** | 基于参考信息验证答案,防止 LLM 编造 | `AnswerMixin` |
| **引用标注** | 自动标注信息来源和引用编号 | `CitationMixin` |
| **富媒体提取** | 图片/表格的智能提取与展示 | `RichMediaMixin` |
| **质量评估** | 多维度质量评估(相关性/完整性/准确性/覆盖面) | `QualityMixin` |
| **上下文压缩** | Rerank 阈值过滤 + Token 预算控制 | `ContextMixin` |
| **元问题处理** | 文件列表、权限查询等非知识类问题 | `MetaQuestionMixin` |
| **置信度门控** | 基于 Reranker 分数判断检索质量,低分触发补救 | `ConfidenceGate`(独立模块) |
---
## ⚠️ 一·五、两套编排路径(务必先读)
> **关键认知**:本项目存在**两套并存的编排orchestration**。生产 HTTP 接口 `/rag` 走的是**轻量编排**,而 `AgenticRAG.process()` 那套**完整决策循环目前处于备用状态、未接入任何 HTTP 路由**。
> 阅读下方所有架构图前请先理解这一点——下面 2.1 的「整体架构图」描绘的是**备用路径AgenticRAG.process**,不是当前生产实际跑的流程。
### 路径对比
| 维度 | 🟢 生产路径(当前启用) | 💤 备用路径(未接线) |
|------|----------------------|---------------------|
| 入口 | `api/chat_routes.py``rag()``generate()` | `core/agentic.py``AgenticRAG.process()` |
| 编排者 | `chat_routes` 自己的流程代码 | `AgenticRAG`8 个 Mixin 组合) |
| 意图分析 | ✅ `intent_analyzer.analyze_intent()` | ✅ `IntentAnalyzer` / `QueryRewriteMixin` |
| 检索 | ✅ `search_hybrid()``engine.search_knowledge()` | ✅ `engine.search_knowledge()` |
| 查询分解/扩展/MMR/自适应TopK | ✅ 在 `engine` 内部执行 | ✅ 同左 |
| 答案生成 | ✅ `engine.generate_answer_stream()`(流式) | `AnswerMixin._generate_fused_answer()` |
| 引用标注 | ✅ `chat_routes._attach_citations()`(本地版) | `CitationMixin._attach_citations()` |
| 置信度门控 | ❌ 不调用 | `ConfidenceGate`(仅此路径用) |
| 多维质量评估 | ❌ 不调用 | `QualityMixin._assess_quality()` |
| 推理反思 | ❌ 不调用 | `QualityMixin._reflect_on_answer()` |
| 循环防护 | ❌ 不调用 | `LoopGuard`(仅此路径用) |
| 幻觉验证 | ❌ 不调用 | `AnswerMixin._verify_and_refine_answer()` |
### 重要结论
- **Agentic 的核心能力是活跃的**:意图分析+LLM改写、子查询拆分、查询扩展、自适应 TopK、MMR 去重、混合检索+Rerank——这些都在 `/rag` 中**真实运行**,只是由 `chat_routes` + `engine` 直接调用,而非通过 `AgenticRAG` 类。
- **休眠的只是「决策循环编排类」**`AgenticRAG.process()` 及其独有组件(置信度门控 / 质量评估 / 推理反思 / 循环防护 / 幻觉验证)未接入 `/rag`
- import 证据:`confidence_gate.py``quality_assessor.py``reasoning_reflector.py``loop_guard.py` 以及 8 个 `agentic_*` Mixin **只被 `core/agentic.py` import**;而 `AgenticRAG` 实例虽在 `api/__init__.py:90` 启动时创建,但其唯一读取入口 `_get_agentic_rag()` **零调用**
- **这不是死代码可删**`AgenticRAG` 在启动时被实例化(直接删会导致启动报错),且 `_extract_rich_media``scripts/test_rag_image_recall.py` 使用。它是「**一套更重、更完整、目前未启用的 Agentic 决策闭环**」,未来可选择接入。
### 🔬 如何验证「系统现在到底走哪套流程」
**方法 1看开发环境 SSE 调试事件(最直接)**
`/rag``IS_DEV=True` 时会发出一串**只有 `chat_routes` 编排才会发**的调试事件,收到它们即证明走的是生产路径:
```bash
# UTF-8 payload 避免 Windows shell 编码问题
curl -s -N -X POST http://localhost:5001/rag \
-H "Content-Type: application/json; charset=utf-8" \
-H "Authorization: Bearer mock-token-admin" \
--data-binary @payload.json
```
观察 SSE 事件序列,**生产路径**会依次出现这些 `type``AgenticRAG.process` 不发这些):
| SSE 事件 `type` | 来源代码 | 含义 |
|----------------|---------|------|
| `start` | `chat_routes.py:1232` | 请求开始处理 |
| `intent_result` | `chat_routes.py:1228` | 意图分析结果(来自 `intent_analyzer`[DEV] |
| `retrieval_debug` | `chat_routes.py:1311` | 检索管线各步骤(来自 `engine.search_knowledge``_debug`[DEV] |
| `chunks_retrieved` | `chat_routes.py:1416` | 召回切片详情 [DEV] |
| `sources` | `chat_routes.py:1547` | 检索到的来源列表 |
| `images_selected` | `chat_routes.py:1574` | 图片选择详情 [DEV] |
| `context_built` | `chat_routes.py:1622` | 最终上下文构建 [DEV] |
| `chunk` | `chat_routes.py:1630` | 流式答案的每个 token |
| `finish` | `chat_routes.py:1699` | 含 `timing``sources``citations` |
| `error` | `chat_routes.py:1733` | 处理异常时的错误信息 |
> 标注 [DEV] 的事件仅在 `IS_DEV=True` 时发送,其余事件在生产环境也会发送。
**方法 2看服务端日志**
- 启动时:出现一次 `Agentic RAG 引擎已初始化``api/__init__.py:95`,仅实例化,不代表被调用)。
- 每次 `/rag` 请求:出现 `[意图分析] use_context=... need_retrieval=...``chat_routes.py:1224`)。
- **不会**出现任何来自 `AgenticRAG.process()` 内部的日志(如查询重写 `📝 查询重写``🔍 知识库检索: N 条结果`)——若出现则说明走了备用路径。
**方法 3埋点验证最确定**
临时在 `core/agentic.py``AgenticRAG.process()` 第一行加 `logger.warning("AgenticRAG.process CALLED")`,重启后发 `/rag` 请求——**该日志不会触发**,即证明生产不走 `AgenticRAG`
**方法 4静态确认调用链**
```bash
grep -rn "_get_agentic_rag()" --include="*.py" . # 仅定义,无调用者 → AgenticRAG 实例未被请求使用
grep -rn "\.process(" --include="*.py" api/ # /rag、/chat 均无 .process() 调用
```
---
## 二、系统架构
> ⚠️ 注意:下方 2.1「整体架构图」描绘的是**备用路径 `AgenticRAG.process()`** 的完整设计;当前生产 `/rag` 的实际流程见上方「一·五」及本节 2.3「生产 /rag 实际流程」。
### 2.1 整体架构图
```
┌─────────────────────────────────────────────────────────────────────┐
│ 用户输入 │
└────────────────────────────┬────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────┐
│ 意图分析 (IntentAnalyzer) │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ 改写查询 │ │ 双层判断 │ │ 子查询拆分 │ │
│ │ (指代消解) │ │ (是否检索) │ │ (对比/推理) │ │
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │
└─────────┼──────────────────┼──────────────────┼─────────────────────┘
↓ ↓ ↓
┌──────────┐ ┌──────────────────────────────────────────┐
│ 直接回答 │ │ AgenticRAG.process() │
│ (LLM) │ │ 1. 元问题检查 │
└──────────┘ │ 2. 查询重写 (QueryRewriteMixin) │
│ 3. 知识库检索 (RAGEngine.search_knowledge)│
│ 4. 上下文压缩 (ContextMixin) │
│ 5. 网络搜索 (SearchMixin, 可选) │
│ 6. 图谱检索 (SearchMixin, 可选) │
│ 7. 融合答案生成 (AnswerMixin) │
│ 8. 幻觉验证 (AnswerMixin) │
│ 9. 富媒体提取 (RichMediaMixin) │
│ 10. 引用标注 (CitationMixin) │
└────────────────────┬─────────────────────┘
┌─────────────────────────────────────────────────────────────────────┐
│ 检索层 (RAGEngine) │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ 向量检索 │ │ BM25 检索 │ │ FAQ 独立召回 │ │
│ │ (语义匹配) │ │ (关键词匹配) │ │ (精准命中) │ │
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │
│ └─────────────────┼─────────────────┘ │
│ ↓ │
│ ┌──────────────┐ │
│ │ RRF 融合 │ ← 动态权重(查询类型/长度驱动)│
│ └──────┬───────┘ │
│ ↓ │
│ ┌───────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ 废止过滤 │→ │ MMR 去重 │→ │ Rerank 重排 │ │
│ └───────────┘ └──────┬───────┘ └──────┬───────┘ │
│ ↓ ↓ │
│ ┌───────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ FAQ 加权 │→ │ 黑名单过滤 │→ │ 时间衰减 │ │
│ └───────────┘ └──────────────┘ └──────┬───────┘ │
│ ↓ │
│ ┌───────────────┐ ┌──────────────┐ │
│ │ 上下文扩展 │→ │ 自适应 TopK │ │
│ └───────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────┐
│ 答案生成 (LLM 流式) │
│ ┌────────────────────────────────────────────────────────────────┐ │
│ │ 整合多源信息 + 标注来源 + 处理冲突 + 引用编号 + SSE 流式输出 │ │
│ └────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
```
### 2.2 Mixin 组合架构
```python
class AgenticRAG(
QueryRewriteMixin, # 查询重写:口语化→专业术语、实体补全
SearchMixin, # 检索功能:网络搜索、图谱检索
AnswerMixin, # 答案生成:融合回答、幻觉验证
CitationMixin, # 引用处理:来源标注、引用编号
RichMediaMixin, # 富媒体:图片/表格提取
QualityMixin, # 质量评估:多维评估
ContextMixin, # 上下文处理:压缩、过滤
MetaQuestionMixin # 元问题:文件列表、权限查询
):
...
```
> 注:以上 2.1 / 2.2 是 `AgenticRAG`(备用路径)的设计。**当前生产 `/rag` 不实例化走这条链**,实际流程见下方 2.3。
### 2.3 生产 /rag 实际流程(当前启用)
入口 `api/chat_routes.py::rag() → generate()`**不经过 `AgenticRAG`**
```
POST /rag (SSE 流式)
[chat_routes.generate()] ← 轻量编排,不实例化 AgenticRAG
├─ 发 SSE: start
├─ 1. 意图分析 intent_analyzer.analyze_intent() # chat_routes:1222
│ ├─ need_retrieval=False → 直接 LLM 回答(流式发 SSE: chunk结束
│ │ └─ use_context=True 时带历史上下文use_context=False 时纯闲聊
│ └─ 否则继续sub_queries 传入检索
│ └─[DEV] 发 SSE: intent_result
├─ 2. 混合检索 search_hybrid() → engine.search_knowledge() # chat_routes:1300
│ (内部:向量+BM25+RRF+废止过滤+章节过滤+MMR+Rerank
│ +FAQ加权+黑名单+时间衰减+上下文扩展+自适应TopK
│ └─[DEV] 发 SSE: retrieval_debug
├─ 3. 提取上下文/来源(按 source 去重doc_type 驱动溯源展示) # chat_routes:1362
│ └─[DEV] 发 SSE: chunks_retrieved
│ └─ 发 SSE: sources
├─ 4. 图片补充检索 + 图片打分选择 (select_images)
│ └─[DEV] 发 SSE: images_selected
├─ 5. 构建上下文 (_order_text_contexts_for_prompt)
│ └─[DEV] 发 SSE: context_built
├─ 6. 流式答案生成 engine.generate_answer_stream() # chat_routes:1628
│ └─ 逐 token 发 SSE: chunk
├─ 7. 答案图号对齐过滤
├─ 8. 引用标注 chat_routes._attach_citations()(本地版,非 CitationMixin # chat_routes:1668
├─ 9. 敏感信息过滤 filter_response()
├─ 10. 发 SSE: finishanswer + sources + citations + images + timing
└─[异常] 发 SSE: error
```
**与备用路径AgenticRAG.process的差异**:生产路径**没有**置信度门控、多维质量评估、推理反思、循环防护、幻觉验证这几步——它们只存在于 `AgenticRAG.process()`
---
## 三、意图分析流程
### 3.1 IntentAnalyzer 双层判断
意图分析由 `core/intent_analyzer.py``IntentAnalyzer` 类完成,采用 **LLM 驱动** 的双层判断:
```
用户输入 + 对话历史
┌─────────────────────────────────────────────┐
│ IntentAnalyzer.analyze() │
│ │
│ Step 1: 查询改写 │
│ - 指代消解:"那请假呢" → "出差相关请假流程"│
│ - 省略补全:"标准" → "差旅报销标准" │
│ - 语义缓存:相似问题复用结果 │
│ │
│ Step 2: 双层判断 │
│ - 第一层:历史上下文是否可答? │
│ - 第二层:是否需要外部知识(检索)? │
│ │
│ Step 3: 子查询拆分(对比/推理类) │
│ - "年假和调休的区别" → ["年假规定", "调休规定"]│
└─────────────────────────────────────────────┘
IntentAnalysis:
- rewritten_query: 改写后的查询
- use_context: 是否使用上下文
- need_retrieval: 是否需要检索
- sub_queries: 子查询列表
- intent: factual/comparison/reasoning/instruction/other
```
### 3.2 QueryClassifier 规则分类
`core/query_classifier.py` 提供无 LLM 调用的快速规则分类:
| 查询类型 | 说明 | 示例 |
|----------|------|------|
| `META` | 元问题(文件列表、权限) | "有哪些文档?" |
| `REALTIME` | 实时信息 | "今天天气" |
| `SIMPLE` | 简单单属性查询 | "出差标准" |
| `FACT` | 事实查询 | "差旅补贴标准是多少" |
| `ENUMERATION` | 枚举/清单/条款 | "严禁哪些情形" |
| `COMPARISON` | 比较分析 | "年假和调休的区别" |
| `PROCESS` | 流程指引 | "如何申请调岗" |
| `FILE_SPECIFIC` | 特定文件内查询 | "xxx.pdf中有哪些图片" |
---
## 四、检索管线详解
### 4.1 完整检索流程
```
search_knowledge(query, top_k=30)
├─ 1. 查询缓存检查 → 命中则直接返回
├─ 2. 子查询并行检索(如有 sub_queries
│ └─ 各子查询独立检索后合并去重
├─ 3. 查询拆分QueryDecomposer
│ └─ 对比/推理类查询自动拆分
├─ 4. 查询扩展QueryExpansion
│ └─ 同义词/语义扩展threshold=0.8
├─ 5. 多知识库检索USE_MULTI_KB=True
│ ├─ 各向量库并行检索ThreadPoolExecutor
│ ├─ 每个库: 向量检索 + BM25 + 图片独立召回
│ ├─ FAQ 集合独立召回
│ └─ RRF 融合
├─ 6. 废止切片过滤status != "active"
├─ 7. 章节过滤(查询提到章节时优先匹配)
├─ 8. 上下文扩展MMR 前,防止邻居被去重)
├─ 9. MMR 去重(前置到 Rerank 前)
│ ├─ 语义向量版MMR_USE_EMBEDDING=True
│ └─ 文本 Jaccard 版MMR_USE_EMBEDDING=False
├─ 10. ★ Rerank 重排 ★
│ └─ rerank_results(query, results, top_k)
├─ 11. FAQ 分数加权Score Boosting
├─ 12. 黑名单过滤(负反馈降权)
├─ 13. 时间衰减Time Decay
├─ 14. 上下文扩展Rerank 后,补充相邻切片)
├─ 15. 自适应 TopK根据置信度调整返回数量
└─ 16. 缓存写入 → 返回结果
```
### 4.2 混合检索代码示例
```python
# 向量检索(语义相似)
vector_results = collection.query(query_embeddings=[query_vector], n_results=recall_k)
# BM25 检索(关键词匹配)
bm25_results = bm25_index.search(query, top_k=recall_k)
# FAQ 独立召回
faq_results = faq_collection.query(query_embeddings=[query_vector], n_results=3)
# 图片独立召回P0 通道)
image_results = collection.query(query_embeddings=[query_vector], n_results=5, where={"chunk_type": {"$in": ["image", "chart", "table"]}})
# RRF 融合(动态权重)
fused = reciprocal_rank_fusion([vector_results, bm25_results], weights=[vector_w, bm25_w])
# MMR 去重
mmr_results = mmr_rerank(query_emb, candidates, top_k=30, lambda_param=0.5)
# Rerank 重排
final = rerank_results(query, mmr_results, top_k=15)
```
### 4.3 RRF 融合算法
```
RRF分数 = Σ (权重 / (k + 排名位置))
示例k=60
文档A: 向量排名1 → 0.5/(60+1) = 0.00820
BM25排名3 → 0.5/(60+3) = 0.00794
总分 = 0.01614
动态权重策略:
- 短查询(<15字: BM25权重↑ (0.6), 向量权重↓ (0.4)
- 长查询(>50字: 向量权重↑ (0.7), BM25权重↓ (0.3)
- 查询类型驱动: FACT→BM25优先, PROCESS→向量优先
```
### 4.4 Rerank 重排
**模型**: `BAAI/bge-reranker-base`CrossEncoder 交叉编码器,~278MB
```python
def rerank_results(self, query, results, top_k=5):
pairs = [(query, doc) for doc in results['documents'][0]]
scores = self.reranker.predict(pairs) # CrossEncoder 或 ONNXReranker
sorted_indices = np.argsort(scores)[::-1]
# 返回 top_k 个最高分结果
```
**调用位置**: `core/engine.py``search_knowledge()``_search_multi_kb()`MMR 去重之后执行。
**ONNX 加速**: `ONNXReranker` 使用 `optimum.onnxruntime` 进行推理CPU 上比原生 PyTorch 快 2-3 倍。首次使用时自动将 PyTorch 模型导出为 ONNX 格式。
---
## 五、置信度门控
`core/confidence_gate.py` 基于 Reranker 分数判断检索结果质量:
```
检索结果 → Reranker 计算置信度 → 阈值判断 → 决策
┌─────────────────┼─────────────────┐
↓ ↓ ↓
PASS (≥0.4) REWRITE (0.2~0.4) WEB_SEARCH (<0.2)
继续生成 查询重写 网络搜索补救
```
**阈值配置**:
- `PASS_THRESHOLD = 0.2`: 通过阈值(低于此值需要补救)
- `GOOD_THRESHOLD = 0.4`: 良好阈值(高质量结果)
- `EXCELLENT_THRESHOLD = 0.7`: 优秀阈值
---
## 六、AgenticRAG 主流程
### 6.1 process() 方法
```python
def process(self, query, verbose=True, history=None,
allowed_levels=None, role=None, department=None,
emit_log=None) -> dict:
"""
返回:
{
"answer": str, # 最终答案
"sources": list, # 来源列表
"images": list, # 图片列表
"tables": list, # 表格列表
"citations": list, # 引用列表
"log_trace": list # 推理过程追踪
}
"""
```
### 6.2 流程步骤
| 步骤 | 方法 | 说明 |
|------|------|------|
| 1 | `_is_meta_question()` | 检查元问题(文件列表、权限等) |
| 2 | `should_rewrite()` + `_rewrite_query()` | 查询重写(口语化→专业术语、实体补全) |
| 3 | `engine.search_knowledge()` / `engine.search_multiple()` | 知识库检索(含向量+BM25+RRF+MMR+Rerank |
| 4 | `_compress_contexts()` | 上下文压缩Rerank 阈值过滤) |
| 5 | `_web_search_flow()` | 网络搜索(可选,需 SERPER_API_KEY |
| 6 | `_graph_search()` | 图谱检索(可选,需 Neo4j |
| 7 | `_generate_fused_answer()` | 融合答案生成(多源信息+冲突处理) |
| 8 | `_verify_and_refine_answer()` | 幻觉验证(防止 LLM 编造) |
| 9 | `_extract_rich_media()` | 富媒体提取(图片/表格) |
| 10 | `_attach_citations()` | 引用标注 |
---
## 七、API 调用方式
### 7.1 SSE 流式问答(主要接口)
```bash
curl -X POST http://localhost:5001/rag \
-H "Content-Type: application/json" \
-H "Authorization: Bearer mock-token-admin" \
-d '{
"query": "出差补助标准是什么?",
"chat_history": []
}'
```
**响应格式**: SSEServer-Sent Events流式返回
```
event: token
data: {"text": "根据"}
event: token
data: {"text": "规定"}
...
event: finish
data: {"answer": "完整答案", "sources": [...], "citations": [...], "images": [...], "duration_ms": 3200}
```
### 7.2 代码调用
```python
from core.engine import get_engine
# 初始化引擎
engine = get_engine()
# 检索
result = engine.search_knowledge("出差补助标准是什么?", top_k=10)
# 流式生成答案
for token in engine.generate_answer_stream(query, context, history=history):
print(token, end="", flush=True)
```
### 7.3 AgenticRAG 调用
```python
from core.agentic import AgenticRAG
rag = AgenticRAG(max_iterations=3, enable_web_search=True, enable_graph=True)
result = rag.process("出差补助标准是什么?")
print(f"答案: {result['answer']}")
print(f"来源: {result['sources']}")
print(f"图片: {result['images']}")
print(f"引用: {result['citations']}")
```
---
## 八、配置说明
### 8.1 LLM 配置
```python
# config.py
DASHSCOPE_API_KEY = "your-api-key" # 通义千问 API
DASHSCOPE_BASE_URL = "https://dashscope.aliyuncs.com/compatible-mode/v1"
DASHSCOPE_MODEL = "qwen-max" # 文本生成模型
DASHSCOPE_VL_MODEL = "qwen-vl-plus" # 视觉模型(图片描述)
RAG_CHAT_MODEL = "qwen-max" # RAG 对话模型
```
### 8.2 检索参数
```python
# 混合检索
USE_MULTI_KB = True # 多向量库模式
USE_HYBRID_SEARCH = True # 向量 + BM25 混合检索
VECTOR_WEIGHT = 0.5 # 向量检索权重
BM25_WEIGHT = 0.5 # BM25 检索权重
RAG_SEARCH_TOP_K = 30 # 最终返回结果数
RAG_SEARCH_CANDIDATES = 100 # 候选池大小
RECALL_MULTIPLIER = 3 # 候选池最小倍数
# 重排序
USE_RERANK = True # 启用重排序
RERANK_CANDIDATES = 20 # 送入重排序的候选数
RERANK_TOP_K = 15 # 重排序后保留数
RERANK_USE_ONNX = True # ONNX 加速(环境变量控制,默认开启)
# RRF 融合
RRF_K = 60 # RRF 常数
DYNAMIC_RRF_ENABLED = True # 动态权重
# MMR 去重
MMR_ENABLED = True
MMR_USE_EMBEDDING = True # True=语义向量False=文本相似度(快)
MMR_TOP_K = 30 # MMR 保留数
MMR_LAMBDA = 0.5 # 相关性 vs 多样性权衡
```
### 8.3 缓存配置
```python
# 查询结果缓存
QUERY_CACHE_ENABLED = True
QUERY_CACHE_SIZE = 500
QUERY_CACHE_TTL = 3600 # 1小时
# Embedding 缓存
EMBEDDING_CACHE_ENABLED = True
EMBEDDING_CACHE_SIZE = 2000
EMBEDDING_CACHE_TTL = 86400 # 24小时
# Rerank 缓存
RERANK_CACHE_ENABLED = True
RERANK_CACHE_SIZE = 1000
RERANK_CACHE_TTL = 3600 # 1小时
# 语义缓存
SEMANTIC_CACHE_ENABLED = True
SEMANTIC_CACHE_THRESHOLD = 0.92 # 相似度阈值
```
### 8.4 设备配置
```python
DEVICE = "auto" # auto / cuda / cpu / cuda:0
EMBEDDING_DEVICE = DEVICE # 向量模型设备
RERANK_DEVICE = DEVICE # Rerank 模型设备
```
---
## 九、文件结构
```
core/ # RAG 核心引擎
├── engine.py # RAGEngine 单例检索主流程、Rerank、RRF
├── agentic.py # AgenticRAG 主类Mixin 组合)
├── agentic_base.py # 基础常量与条件导入
├── agentic_query.py # QueryRewriteMixin查询重写
├── agentic_search.py # SearchMixin网络/图谱检索)
├── agentic_answer.py # AnswerMixin答案生成、幻觉验证
├── agentic_citation.py # CitationMixin引用标注
├── agentic_media.py # RichMediaMixin富媒体提取
├── agentic_quality.py # QualityMixin质量评估
├── agentic_context.py # ContextMixin上下文压缩
├── agentic_meta.py # MetaQuestionMixin元问题处理
├── bm25_index.py # BM25Index关键词检索
├── chunker.py # 文本分块器
├── mmr.py # MMR 去重(语义向量版 + 文本 Jaccard 版)
├── query_classifier.py # QueryClassifier规则快速分类
├── intent_analyzer.py # IntentAnalyzerLLM 意图分析)
├── query_decomposer.py # QueryDecomposer复杂查询拆分
├── query_expansion.py # 查询扩展
├── adaptive_topk.py # AdaptiveTopK自适应 TopK
├── confidence_gate.py # ConfidenceGate置信度门控
├── quality_assessor.py # 多维质量评估
├── reasoning_reflector.py # 推理反思
├── loop_guard.py # 循环防护
├── llm_budget.py # LLM 调用预算控制
├── llm_utils.py # LLM 调用工具函数
├── semantic_cache.py # 语义缓存
├── cache.py # 三层缓存管理器Query/Embedding/Rerank
├── status_codes.py # 状态码定义
└── constants.py # 公共常量
knowledge/ # 知识库管理
├── manager.py # KnowledgeBaseManager7 个 Mixin 组合)
├── router.py # KnowledgeBaseRouter智能知识库路由
├── sync.py # KnowledgeSyncService文件变更监控+增量向量化)
├── base.py # 知识库基类定义
├── collection.py # 集合CollectionCRUD 操作
├── document.py # 文档管理(上传/删除/状态流转)
├── document_versions.py # 文档版本管理
├── chunk.py # 分块操作(创建/查询/更新)
├── index.py # 索引管理BM25 构建/重建)
├── search.py # 知识库内搜索
├── processing.py # 文档处理流水线(解析→分块→向量化)
├── permission.py # 权限控制(角色/部门级访问控制)
├── lazy_enhance.py # 延迟增强(按需生成摘要/关键词)
└── cleanup.py # 清理操作(孤立切片/过期数据)
api/ # API 路由层
├── __init__.py # create_app() 工厂
├── chat_routes.py # /chat, /rag(SSE), /search
├── kb_routes.py # /collections
├── document_routes.py # /documents/*
├── sync_routes.py # /sync
├── session_routes.py # /sessions会话管理
├── image_routes.py # /images图片访问/上传)
├── feedback_routes.py # /feedback用户反馈/点赞/踩)
├── auth_routes.py # /auth认证/登录/Token
├── audit_routes.py # /audit审计日志
└── response_utils.py # 响应工具函数
services/ # 业务服务层
├── session.py # 会话管理服务
├── feedback.py # 反馈处理服务
└── outline.py # 大纲生成服务
graph/ # 知识图谱
├── graph_manager.py # 图谱管理器Neo4j 连接/操作)
├── entity_extractor.py # 实体提取器
├── graph_build.py # 图谱构建(从文档→实体→关系)
└── graph_rag.py # 图谱 RAG 检索
auth/ # 认证与安全
├── gateway.py # API 网关认证
└── security.py # 安全工具Token 验证/权限检查)
repositories/ # 数据持久层
├── session_repo.py # 会话仓储接口
├── sqlite_session_repo.py # SQLite 会话仓储实现
└── stateless_session_repo.py # 无状态会话仓储
parsers/ # 文档解析器
├── mineru_parser.py # MinerU PDF/DOCX/PPTX 解析
├── excel_parser.py # Excel 解析
├── txt_parser.py # 纯文本解析
├── image_extractor.py # 图片提取器(从文档中提取/处理图片)
└── pdf_mineru.py # MinerU PDF 辅助入口
exam_pkg/ # 出题系统
├── api.py # 出题/批阅 API
├── generator.py # 试题生成Dify 工作流)
├── grader.py # 试卷批阅
├── manager.py # 出题管理器(核心业务逻辑)
└── local_db.py # 本地数据库SQLite
tools/ # 运维/分析工具
├── export_chunks.py # 导出切片
├── llm_evaluator.py # LLM 评估器
├── chunk_analyzer.py # 切片质量分析
├── chunk_metrics.py # 切片指标统计
├── chunk_report.py # 切片报告生成
├── clean_vector_store.py # 清理向量库
├── rebuild_pdf_vectors.py # 重建 PDF 向量
└── upload_test_files.py # 上传测试文件
deploy/ # 部署配置
├── Dockerfile # 开发环境 Docker
├── Dockerfile.prod # 生产环境 Docker
├── docker-compose.yml # 开发环境编排
├── docker-compose.prod.yml # 生产环境编排
├── nginx.conf # Nginx 反向代理配置
├── gunicorn.conf.py # Gunicorn WSGI 配置
└── wsgi.py # WSGI 入口
config/ # 运行时配置
└── banned_words.txt # 敏感词库
```
---
## 十、与传统 RAG 对比
| 特性 | 传统 RAG | Agentic RAG (当前) |
|------|---------|-------------------|
| 意图判断 | 无 | IntentAnalyzer LLM 双层判断 |
| 查询改写 | 无 | 口语化→专业术语 + 实体补全 + 指代消解 |
| 检索方式 | 单一向量检索 | 向量 + BM25 + FAQ + 图片独立召回 |
| 融合算法 | 无 | RRF 动态权重融合 |
| 去重 | 无 | MMR 语义去重 |
| 重排序 | 无 | CrossEncoder Rerank支持 ONNX 加速) |
| 问题分解 | 无 | 自动拆分对比/推理类查询 |
| 闲聊处理 | 无 | 意图分析自动判断 |
| 网络搜索 | 无 | 可选支持Serper API |
| 知识图谱 | 无 | 可选支持Neo4j |
| 幻觉验证 | 无 | 基于参考信息的答案验证 |
| 置信度门控 | 无 | Reranker 分数驱动,低分触发补救 |
| 缓存 | 无 | 三层缓存 + 语义缓存 |
| 自适应 TopK | 固定 top_k | 根据置信度动态调整 |
| 上下文理解 | 无 | 多轮对话 + 历史上下文 |
| 响应时间 | ~2秒 | ~3-8秒取决于 Rerank + LLM |
---
## 十一、Rerank 性能分析
### 11.1 Rerank 调用路径
Rerank 在系统中有 **两个独立调用路径**
| 路径 | 位置 | 说明 |
|------|------|------|
| 主检索管线 | `engine.rerank_results()` | MMR 去重后执行,对 30 个候选重排取 top_k |
| 置信度门控 | `confidence_gate._compute_scores()` | 直接调用 `reranker.predict()`,可能重复推理 |
### 11.2 性能瓶颈
| 瓶颈 | 严重程度 | 说明 |
|------|---------|------|
| Rerank 缓存命中率偏低 | 🟡 中 | `rerank_results()` 已正确调用缓存读写,但缓存 key 基于 `query + sorted(doc_ids)` 精确匹配MMR 去重产出稍有不同就无法命中 |
| 置信度门控重复推理 | 🟡 中 | 同一 query+documents 可能被 Rerank 两次(当前仅备用路径使用,暂未影响生产) |
| 无性能计时 | 🟡 中 | `rerank_results()` 内无计时代码,无法量化耗时占比 |
| 查询分类器策略未生效 | 🟢 低 | `QueryClassifier` 定义的差异化 rerank 参数未传递到引擎 |
### 11.3 Rerank 配置参数
| 配置项 | 默认值 | 说明 |
|--------|--------|------|
| `USE_RERANK` | `True` | 总开关 |
| `RERANK_MODEL_PATH` | `models/bge-reranker-base` | 模型路径 |
| `RERANK_CANDIDATES` | `20` | 送入 Rerank 的候选数 |
| `RERANK_TOP_K` | `15` | Rerank 后保留数 |
| `RERANK_USE_ONNX` | `True`(环境变量默认) | ONNX 加速开关 |
| `RERANK_DEVICE` | 跟随 `DEVICE` | 设备选择 |
| `RERANK_THRESHOLD` | `0.3` | 上下文过滤阈值 |
| `RERANK_CACHE_ENABLED` | `True` | 缓存开关(已在 `rerank_results()` 中使用) |
---
## 十二、最佳实践
### 12.1 何时使用 Agentic RAG
**推荐使用**
- 复杂问题需要多轮检索
- 用户表达模糊需要改写
- 需要区分闲聊和知识问答
- 需要多轮对话记忆
- 需要引用来源和幻觉验证
**不推荐使用**
- 简单明确的问题(用 `/search` 接口更快)
- 对响应时间极度敏感的场景
### 12.2 性能优化
```python
# 减少迭代次数
rag = AgenticRAG(max_iterations=2)
# 禁用网络搜索
rag = AgenticRAG(enable_web_search=False)
# ONNX 加速默认已开启;如有兼容性问题可关闭(环境变量)
# RERANK_USE_ONNX=false
# 使用轻量 MMR文本相似度代替语义向量
# config.py: MMR_USE_EMBEDDING = False
```
### 12.3 调试技巧
```python
# 查看检索调试信息
result = engine.search_knowledge("问题", top_k=10)
debug = result.get('_debug', {})
for step in debug.get('steps', []):
print(f"步骤: {step['name']}, 详情: {step}")
```
---
## 附加篇Agentic RAG 深入优化与工作机制
### 一、Agentic RAG 的核心架构
Agentic RAG 构建了动态的决策闭环,核心组件包括:
- **意图分析器**LLM 驱动的双层判断,替代硬编码规则
- **查询重写器**:口语化→专业术语、实体补全、指代消解
- **混合检索引擎**:向量 + BM25 + FAQ + 图片独立召回 + RRF 融合
- **MMR 去重**:平衡相关性与多样性,前置到 Rerank 前减少输入量
- **Rerank 重排**CrossEncoder 精确排序,支持 ONNX 加速
- **置信度门控**Reranker 分数驱动,低分触发补救流程
- **幻觉验证**:基于参考信息验证答案,防止 LLM 编造
### 二、分阶段优化策略
#### 1. 检索前:优化查询质量
- **智能查询重写**:口语化表述 → 精准检索术语
- **复杂问题分解**:对比/推理类查询自动拆分为子查询
- **意图分析**LLM 双层判断,避免不必要的检索
#### 2. 检索中:提升召回精准度
- **多路召回与融合**:向量 + BM25 + FAQ + 图片独立召回
- **动态 RRF 权重**:查询类型/长度驱动的权重调整
- **MMR 去重**:前置到 Rerank 前,减少 Rerank 输入量召回100 → MMR取30 → Rerank取15
- **Rerank 重排**CrossEncoder 精排,置信度门控过滤低质量结果
#### 3. 检索后:质量评估与自我迭代
- **多维质量评估**:相关性/完整性/准确性/覆盖面
- **推理反思**:检查推理过程中未验证的假设
- **分层补救**:低置信度 → 查询重写 → 网络搜索
### 三、系统级优化
#### 1. 避免"循环检索"陷阱
- 循环防护器(`loop_guard.py`):最多允许 N 次重写检索
- 置信度递增检查:连续两次无提升则终止
#### 2. 平衡智能性与效率
- 轻量级决策模型:意图分析使用低温度、少 token 的 LLM 调用
- 三层缓存Query Cache + Embedding Cache + Rerank Cache
- 语义缓存相似查询复用结果threshold=0.92
- LLM 预算控制:`MAX_LLM_CALLS_PER_QUERY = 2`
#### 3. 安全与可解释性
- 证据溯源:引用标注 + 来源编号
- 思维链展示:`log_trace` 记录推理过程
- 安全护栏:输入验证 + 输出过滤 + 权限控制
### 四、学术前沿
1. **RAG-Gym**:三维度系统优化(提示工程 + 执行器调优 + 评判器训练)
2. **过程监督 vs 结果监督**:细粒度过程奖励显著提升训练效率
3. **Re2Search**推理反思机制F1 score 提升 10%+
### 参考资料
1. Xiong, G., et al. (2025). RAG-Gym: Systematic Optimization of Language Agents for Retrieval-Augmented Generation. arXiv:2502.13957
2. Zhang, W., et al. (2025). Process vs. Outcome Reward: Which is Better for Agentic RAG Reinforcement Learning. arXiv:2505.14069
3. Agentic RAG 实战指南:从查询重写到多步重查全掌握。火山引擎 ADG 社区