# Agentic RAG 完整指南 > **版本**: v3.2(模型/Reranker/管线更新) > **生产入口**: `api/chat_routes.py::rag()` → `core/engine.py`(轻量编排,当前启用) > **备用编排**: `core/agentic.py::AgenticRAG.process()` + 8 个 Mixin(完整决策循环,未接线) > **最后更新**: 2026-06-04 > > ⚠️ 项目存在两套编排,生产 `/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. (图谱检索已废弃,graph/ 目录已清空) │ │ 7. 融合答案生成 (AnswerMixin) │ │ 8. 幻觉验证 (AnswerMixin) │ │ 9. 富媒体提取 (RichMediaMixin) │ │ 10. 引用标注 (CitationMixin) │ └────────────────────┬─────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────────────┐ │ 检索层 (RAGEngine) │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ 向量检索 │ │ BM25 检索 │ │ FAQ 独立召回 │ │ │ │ (语义匹配) │ │ (关键词匹配) │ │ (精准命中) │ │ │ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │ │ └─────────────────┼─────────────────┘ │ │ ↓ │ │ ┌──────────────┐ │ │ │ RRF 融合 │ ← 动态权重(查询类型/长度驱动)│ │ └──────┬───────┘ │ │ ↓ │ │ ┌───────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ 废止过滤 │→ │ Rerank 重排 │→ │ MMR 去重 │ │ │ └───────────┘ │ (云端API) │ └──────┬───────┘ │ │ └──────┬───────┘ ↓ │ │ ┌───────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ 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+废止过滤+章节过滤 │ +云端Rerank+MMR去重+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: finish(answer + 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. ★ Rerank 重排 ★(云端 DashScope qwen3-rerank 或本地 BGE) │ └─ rerank_results(query, results, top_k) │ └─ 由 RERANK_BACKEND 控制(local/cloud/fallback) │ ├─ 9. MMR 去重 │ ├─ 语义向量版(MMR_USE_EMBEDDING=True) │ └─ 文本 Jaccard 版(MMR_USE_EMBEDDING=False,生产推荐) │ ├─ 10. FAQ 分数加权(Score Boosting) │ ├─ 11. 黑名单过滤(负反馈降权) │ ├─ 12. 时间衰减(Time Decay) │ ├─ 13. 上下文扩展(Rerank 后,补充相邻切片) │ ├─ 14. 自适应 TopK(根据置信度调整返回数量) │ └─ 15. 缓存写入 → 返回结果 ``` ### 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]) # Rerank 重排(云端 DashScope qwen3-rerank 或本地 BGE) reranked = rerank_results(query, fused, top_k=15) # MMR 去重 mmr_results = mmr_rerank(query_emb, reranked, top_k=30, lambda_param=0.5) ``` ### 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 重排 **后端**: 支持三种模式,由 `RERANK_BACKEND` 环境变量控制 | RERANK_BACKEND | 说明 | |----------------|------| | `"cloud"` | 仅使用云端 DashScope `qwen3-rerank` API | | `"local"` | 仅使用本地 `BAAI/bge-reranker-base`(CrossEncoder / ONNX) | | `"fallback"` | 优先云端,失败时自动回退本地(推荐生产环境) | **云端 Reranker(推荐)**: ```python # config.py RERANK_BACKEND = os.getenv("RERANK_BACKEND", "local") # local / cloud / fallback RERANK_CLOUD_MODEL = "qwen3-rerank" # DashScope 云端 Rerank 模型 RERANK_CLOUD_API_KEY = os.getenv("RERANK_CLOUD_API_KEY", DASHSCOPE_API_KEY) RERANK_CLOUD_BASE_URL = "https://dashscope.aliyuncs.com/compatible-api/v1/reranks" RERANK_CLOUD_TIMEOUT = 15 # 云端请求超时(秒) ``` `CloudReranker` 类(`core/engine.py`)封装 DashScope 的 `/compatible-api/v1/reranks` 接口,提供与本地 `CrossEncoder.predict()` / `ONNXReranker.predict()` 一致的调用接口。 **本地 Reranker(备选)**: ```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 / CloudReranker sorted_indices = np.argsort(scores)[::-1] # 返回 top_k 个最高分结果 ``` **调用位置**: `core/engine.py` 的 `search_knowledge()` 和 `_search_multi_kb()` 中,RRF 融合 + 废止/章节过滤之后、MMR 去重之前执行。 **引擎初始化顺序**: `RAGEngine.__init__()` 中按 `RERANK_BACKEND` 决定加载策略: - `cloud` / `fallback`:先尝试创建 `CloudReranker`,需要 `RERANK_CLOUD_API_KEY` - `local` / `fallback`(云端失败时):加载本地 `BAAI/bge-reranker-base`,支持 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()`~~ | ~~图谱检索(已废弃,graph/ 目录已清空)~~ | | 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": [] }' ``` **响应格式**: SSE(Server-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) 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 = "qwen3.6-flash" # 文本生成模型(主力 LLM) INTENT_MODEL = "qwen-turbo" # 意图分析模型(轻量快速) VLM_MODEL = "qwen-vl-plus" # 视觉语言模型(图片描述) RAG_CHAT_MODEL = "qwen3.6-flash" # 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_BACKEND = "local" # "local"=本地模型, "cloud"=云端API, "fallback"=优先云端失败回退本地 RERANK_CLOUD_MODEL = "qwen3-rerank" # 云端 Rerank 模型(DashScope API) 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 = False # True=语义向量(慢),False=文本Jaccard相似度(快,生产推荐) 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 # IntentAnalyzer(LLM 意图分析) ├── 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 # KnowledgeBaseManager(7 个 Mixin 组合) ├── router.py # KnowledgeBaseRouter(智能知识库路由) ├── sync.py # KnowledgeSyncService(文件变更监控+增量向量化) ├── base.py # 知识库基类定义 ├── collection.py # 集合(Collection)CRUD 操作 ├── 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 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 语义去重 | | 重排序 | 无 | 云端 qwen3-rerank API(支持本地 BGE 回退) | | 问题分解 | 无 | 自动拆分对比/推理类查询 | | 闲聊处理 | 无 | 意图分析自动判断 | | 网络搜索 | 无 | 可选支持(Serper API) | | 知识图谱 | 无 | ~~可选支持(Neo4j)~~(已废弃,graph/ 目录已清空) | | 幻觉验证 | 无 | 基于参考信息的答案验证 | | 置信度门控 | 无 | Reranker 分数驱动,低分触发补救 | | 缓存 | 无 | 三层缓存 + 语义缓存 | | 自适应 TopK | 固定 top_k | 根据置信度动态调整 | | 上下文理解 | 无 | 多轮对话 + 历史上下文 | | 响应时间 | ~2秒 | ~3-8秒(取决于 Rerank + LLM) | --- ## 十一、Rerank 性能分析 ### 11.1 Rerank 调用路径 Rerank 在系统中有 **两个独立调用路径**: | 路径 | 位置 | 说明 | |------|------|------| | 主检索管线 | `engine.rerank_results()` | RRF 融合后、MMR 去重前执行,对候选重排取 top_k | | 置信度门控 | `confidence_gate._compute_scores()` | 直接调用 `reranker.predict()`,可能重复推理 | ### 11.2 性能瓶颈 | 瓶颈 | 严重程度 | 说明 | |------|---------|------| | Rerank 缓存命中率偏低 | 🟡 中 | `rerank_results()` 已正确调用缓存读写,但缓存 key 基于 `query + sorted(doc_ids)` 精确匹配,RRF 融合产出稍有不同就无法命中 | | 置信度门控重复推理 | 🟡 中 | 同一 query+documents 可能被 Rerank 两次(当前仅备用路径使用,暂未影响生产) | | ~~无性能计时~~ | ~~🟡 中~~ | 已修复:`rerank_results()` 现返回 `_rerank_time_ms` 计时字段 | | 查询分类器策略未生效 | 🟢 低 | `QueryClassifier` 定义的差异化 rerank 参数未传递到引擎 | ### 11.3 Rerank 配置参数 | 配置项 | 默认值 | 说明 | |--------|--------|------| | `USE_RERANK` | `True` | 总开关 | | `RERANK_BACKEND` | `"local"` | 后端选择:`local`=本地模型, `cloud`=云端API, `fallback`=优先云端失败回退本地 | | `RERANK_CLOUD_MODEL` | `"qwen3-rerank"` | 云端 Rerank 模型名称(DashScope API) | | `RERANK_CLOUD_API_KEY` | 同 `DASHSCOPE_API_KEY` | 云端 API 密钥 | | `RERANK_CLOUD_BASE_URL` | `https://dashscope.aliyuncs.com/compatible-api/v1/reranks` | 云端 API 地址 | | `RERANK_CLOUD_TIMEOUT` | `15` | 云端请求超时(秒) | | `RERANK_MODEL_PATH` | `models/bge-reranker-base` | 本地模型路径(仅 local/fallback 模式) | | `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 重排**:云端 qwen3-rerank API 精确排序,支持本地 BGE 回退 - **置信度门控**:Reranker 分数驱动,低分触发补救流程 - **幻觉验证**:基于参考信息验证答案,防止 LLM 编造 ### 二、分阶段优化策略 #### 1. 检索前:优化查询质量 - **智能查询重写**:口语化表述 → 精准检索术语 - **复杂问题分解**:对比/推理类查询自动拆分为子查询 - **意图分析**:LLM 双层判断,避免不必要的检索 #### 2. 检索中:提升召回精准度 - **多路召回与融合**:向量 + BM25 + FAQ + 图片独立召回 - **动态 RRF 权重**:查询类型/长度驱动的权重调整 - **MMR 去重**:Rerank 后进一步精炼,平衡相关性与多样性(召回100 → Rerank取15 → MMR精炼) - **Rerank 重排**:云端 qwen3-rerank 精排,置信度门控过滤低质量结果 #### 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 社区