Files
rag/docs/RAG系统完整指南.md
lacerate551 a340eaaeee docs: 重写 RAG 系统指南并重命名(移除 AgenticRAG 内容)
- 全面重写文档,反映统一编排路径和四层缓存架构
- 添加 Query Cache 修复说明和语义缓存集成文档
- 重命名 Agentic_RAG完整指南.md → RAG系统完整指南.md
- 同步更新开发与系统模块说明.md 中的引用链接
2026-06-08 16:05:43 +08:00

39 KiB
Raw Blame History

RAG 系统完整指南

版本: v4.0(统一编排 + 四层缓存修复) 生产入口: api/chat_routes.py::rag()generate()core/engine.py 最后更新: 2026-06-05

本次更新:删除未使用的 AgenticRAG 备用编排路径10 个文件 ~2050 行),修复 Query Cache 键不匹配与阈值问题,将语义缓存集成至生产 /rag 端点。

一、功能概述

本系统是一个检索增强生成RAG问答系统采用单一统一编排路径,由 api/chat_routes.pygenerate() 函数直接编排全流程。核心能力包括:

功能 说明 实现位置
意图分析 LLM 驱动的双层判断(是否需要检索)+ 查询改写 core/intent_analyzer.py
混合检索 向量检索 + BM25 + RRF 融合 + Rerank 重排 core/engine.py
四层缓存 Query + Embedding + RerankLRU+ 语义缓存FAISS core/cache.py + core/semantic_cache.py
流式生成 SSE 流式答案输出,逐 token 推送 core/engine.py::generate_answer_stream()
引用标注 自动标注信息来源和引用编号 api/chat_routes.py::_attach_citations()
富媒体 图片/表格的智能提取与展示 api/chat_routes.py
查询理解 查询分解、扩展、MMR 去重、自适应 TopK core/ 各独立模块
安全护栏 敏感信息过滤、Prompt 安全守卫 api/response_utils.pycore/prompt_guard.py

二、系统架构

2.1 整体架构图

┌─────────────────────────────────────────────────────────────────────┐
│                          用户输入                                    │
└────────────────────────────┬────────────────────────────────────────┘
                             ↓
┌─────────────────────────────────────────────────────────────────────┐
│              语义缓存检查 (SemanticCache - FAISS)                    │
│              cosine ≥ 0.92 → 命中则直接返回缓存结果                  │
│              跳过检索 + 生成全流程(~100ms vs ~9s                  │
└────────────────────────────┬────────────────────────────────────────┘
                             ↓ 未命中
┌─────────────────────────────────────────────────────────────────────┐
│                    意图分析 (IntentAnalyzer)                         │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐             │
│  │  改写查询    │  │  双层判断    │  │  子查询拆分  │             │
│  │  (指代消解)  │  │  (是否检索)  │  │  (对比/推理) │             │
│  └──────┬───────┘  └──────┬───────┘  └──────┬───────┘             │
└─────────┼──────────────────┼──────────────────┼─────────────────────┘
          ↓                  ↓                  ↓
    ┌──────────┐    ┌──────────────────────────────────────────┐
    │ 直接回答 │    │           统一编排流程                     │
    │ (LLM)    │    │  1. 混合检索 (engine.search_knowledge)   │
    └──────────┘    │  2. 上下文提取 + 来源去重                 │
                    │  3. 图片补充检索 + 打分选择               │
                    │  4. 构建上下文                            │
                    │  5. 流式答案生成 (engine.generate_stream) │
                    │  6. 答案图号对齐 + 引用标注               │
                    │  7. 敏感信息过滤                          │
                    │  8. 语义缓存写入 + SSE finish             │
                    └────────────────────┬─────────────────────┘
                                         ↓
┌─────────────────────────────────────────────────────────────────────┐
│                        检索层 (RAGEngine)                            │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐             │
│  │  查询缓存    │  │  向量检索    │  │  BM25 检索   │             │
│  │  (LRU 500)   │  │  (语义匹配)  │  │ (关键词匹配) │             │
│  │  命中直接返回│  └──────┬───────┘  └──────┬───────┘             │
│  └──────────────┘         └─────────────────┘                      │
│                           ↓                                         │
│                   ┌──────────────┐                                  │
│                   │  RRF 融合    │  ← 动态权重(查询类型/长度驱动)│
│                   └──────┬───────┘                                  │
│                          ↓                                          │
│  ┌───────────┐  ┌──────────────┐  ┌──────────────┐               │
│  │ 废止过滤  │→ │  Rerank 重排 │→ │  MMR 去重    │               │
│  └───────────┘  │  (云端API)   │  └──────┬───────┘               │
│                 └──────┬───────┘          ↓                       │
│  ┌───────────┐  ┌──────────────┐  ┌──────────────┐               │
│  │ FAQ 加权  │→ │  黑名单过滤  │→ │  时间衰减    │               │
│  └───────────┘  └──────────────┘  └──────┬───────┘               │
│                                            ↓                       │
│  ┌───────────────┐  ┌──────────────┐                              │
│  │ 上下文扩展    │→ │ 自适应 TopK  │                              │
│  └───────────────┘  └──────────────┘                              │
└─────────────────────────────────────────────────────────────────────┘
                          ↓
┌─────────────────────────────────────────────────────────────────────┐
│                    答案生成 (LLM 流式)                               │
│  ┌────────────────────────────────────────────────────────────────┐ │
│  │  整合多源信息 + 标注来源 + 引用编号 + SSE 流式输出             │ │
│  └────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘

2.2 编排方式

系统采用函数式编排而非类组合模式。整个 RAG 流程由 api/chat_routes.pygenerate() 函数直接控制,按步骤调用各独立模块:

  • 意图分析core/intent_analyzer.pyanalyze_intent()
  • 检索管线core/engine.pysearch_knowledge()
  • 流式生成core/engine.pygenerate_answer_stream()
  • 引用标注api/chat_routes.py 内的 _attach_citations()
  • 缓存系统core/cache.pyRAGCacheManager 单例 + core/semantic_cache.pySemanticCache 单例

各模块通过 get_engine()get_cache_manager()get_semantic_cache() 等工厂函数获取全局单例实例。


三、四层缓存架构

3.1 缓存层次概览

层次 缓存类型 存储结构 容量 TTL 作用
L1 Query Cache LRU (OrderedDict) 500 条 1 小时 缓存完整问答结果,命中后跳过整个检索+生成
L2 Embedding Cache LRU (OrderedDict) 2000 条 24 小时 缓存向量化结果,避免重复调用 embedding 模型
L3 Rerank Cache LRU (OrderedDict) 1000 条 1 小时 缓存 Rerank 分数,避免重复调用 Reranker
L4 Semantic Cache FAISS IndexFlatIP 10000 条 无过期 语义级缓存,相似查询也能命中

3.2 Query Cache

Query Cache 是最外层的完整问答结果缓存。命中后直接返回缓存的 answer + sources + citations,跳过检索和生成全流程。

缓存键设计{query_hash}:{kb_name}:{kb_version}

  • 基于查询文本哈希 + 知识库名称 + 知识库版本号
  • 知识库版本变更时(如文档更新/重新索引),相关缓存自动失效

已修复的问题

  1. 键不匹配问题(已修复):此前 set_query_result() 在有 doc_ids 参数时使用 doc_hash 分支生成键,而 get_query_result() 始终使用 kb_version 分支——导致 GET 和 SET 的键永远不匹配,命中率始终为 0%。修复后两端统一使用 kb_version 分支。

  2. 写入阈值问题(已修复)CACHE_MIN_SCORE 原值为 0.3,但 ChromaDB 余弦距离经 1 - dist 计算后得分通常在 0.03-0.06 之间,远低于阈值,导致几乎不写入缓存。修复后设为 0.0

3.3 Embedding Cache

缓存文本向量化结果,由 RAGEngine 在调用 embedding 模型前后自动读写。键为查询文本哈希,避免对相同文本重复调用 embedding 模型(如 DashScope text-embedding-v3

3.4 Rerank Cache

缓存 Rerank 重排序的分数结果。键为 query + sorted(doc_ids) 的精确匹配。注意:由于 RRF 融合产出差异,命中率可能偏低。

3.5 语义缓存Semantic Cache

语义缓存基于 FAISS 向量索引实现语义级匹配——即使查询文字不完全相同只要语义足够相似cosine similarity ≥ 0.92),就能命中缓存。

工作机制

用户查询 → embedding 编码 → FAISS 向量检索
    → cosine ≥ 0.92 → 命中:返回缓存的 answer + sources + citations~100ms
    → cosine < 0.92 → 未命中:执行完整 RAG 流程后写入缓存

集成位置

  • 读取:在 generate() 函数的意图分析之后、混合检索之前(跳过整个检索+生成流程)
  • 写入:在 generate() 函数生成完整答案后、发送 finish 事件之前
  • 缓存内容answer、sources、citations、images、tables

验证结果:语义缓存命中率约 66.7%,平均响应从 ~9.2 秒降至 ~100 毫秒(约 92 倍加速)。

3.6 缓存失效机制

所有基于 LRU 的缓存L1-L3均支持基于知识库版本号kb_version)的自动失效:

  • 每个缓存条目关联 kb_version
  • 知识库文档变更时 kb_version 递增
  • 读取时检查 kb_version 是否匹配,不匹配则视为过期

语义缓存L4当前无 TTL 过期机制,仅受 max_size=10000 容量限制。

3.7 缓存配置

# config.py / config.example.py

# 查询结果缓存
QUERY_CACHE_ENABLED = True
QUERY_CACHE_SIZE = 500
QUERY_CACHE_TTL = 3600             # 秒

# 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

# 语义缓存
SEMANTIC_CACHE_ENABLED = True
SEMANTIC_CACHE_THRESHOLD = 0.92    # cosine 相似度阈值

# 缓存写入最低置信度
CACHE_MIN_SCORE = 0.0              # ChromaDB 余弦距离经 1-dist 后得分约 0.03-0.06,须设为 0

3.8 部署注意事项

当前所有缓存均为进程内内存存储LRU 使用 OrderedDict,语义缓存使用 FAISS 内存索引),有以下部署影响:

  • 单 WorkerGunicorn 默认 1 个 worker所有请求共享同一缓存实例缓存有效
  • 多 Worker:每个 worker 有独立缓存,不共享,缓存效率降低
  • 冷启动:进程重启后缓存全部丢失,需重新预热
  • max_requests=1000Gunicorn worker 定期重启会导致缓存周期性清空

对于生产环境多实例部署场景,已规划 Redis 外部缓存迁移方案(见 reports/redis_migration_plan.md)。


四、意图分析流程

4.1 IntentAnalyzer 双层判断

意图分析由 core/intent_analyzer.pyIntentAnalyzer 类完成,采用 LLM 驱动 的双层判断:

用户输入 + 对话历史
    ↓
┌─────────────────────────────────────────────┐
│        IntentAnalyzer.analyze()              │
│                                              │
│  Step 1: 查询改写                            │
│    - 指代消解:"那请假呢" → "出差相关请假流程"│
│    - 省略补全:"标准" → "差旅报销标准"        │
│    - 语义缓存:相似问题复用结果               │
│                                              │
│  Step 2: 双层判断                            │
│    - 第一层:历史上下文是否可答?              │
│    - 第二层:是否需要外部知识(检索)?        │
│                                              │
│  Step 3: 子查询拆分(对比/推理类)            │
│    - "年假和调休的区别" → ["年假规定", "调休规定"]│
└─────────────────────────────────────────────┘
    ↓
    IntentAnalysis:
      - rewritten_query: 改写后的查询
      - use_context: 是否使用上下文
      - need_retrieval: 是否需要检索
      - sub_queries: 子查询列表
      - intent: factual/comparison/reasoning/instruction/other

4.2 QueryClassifier 规则分类

core/query_classifier.py 提供无 LLM 调用的快速规则分类:

查询类型 说明 示例
META 元问题(文件列表、权限) "有哪些文档?"
REALTIME 实时信息 "今天天气"
SIMPLE 简单单属性查询 "出差标准"
FACT 事实查询 "差旅补贴标准是多少"
ENUMERATION 枚举/清单/条款 "严禁哪些情形"
COMPARISON 比较分析 "年假和调休的区别"
PROCESS 流程指引 "如何申请调岗"
FILE_SPECIFIC 特定文件内查询 "xxx.pdf中有哪些图片"

五、检索管线详解

5.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. 缓存写入 → 返回结果

5.2 混合检索代码示例

# 向量检索(语义相似)
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)

5.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→向量优先

5.4 Rerank 重排

后端:支持三种模式,由 RERANK_BACKEND 环境变量控制

RERANK_BACKEND 说明
"cloud" 仅使用云端 DashScope qwen3-rerank API
"local" 仅使用本地 BAAI/bge-reranker-baseCrossEncoder / ONNX
"fallback" 优先云端,失败时自动回退本地(推荐生产环境)

云端 Reranker推荐

# config.py
RERANK_BACKEND = os.getenv("RERANK_BACKEND", "local")
RERANK_CLOUD_MODEL = "qwen3-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备选

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.pysearch_knowledge()_search_multi_kb()RRF 融合 + 废止/章节过滤之后、MMR 去重之前执行。


六、生产 /rag 完整流程

入口 api/chat_routes.py::rag() → generate()

POST /rag  (SSE 流式)
    ↓
[chat_routes.generate()]
    │
    ├─ 发 SSE: start
    │
    ├─ 1. 语义缓存检查  SemanticCache.get()               # chat_routes
    │      ├─ 命中 → 直接流式发 SSE: chunk + finish结束~100ms
    │      └─ 未命中 → 继续;记录 embedding 供后续写入
    │
    ├─ 2. 意图分析    intent_analyzer.analyze_intent()
    │      ├─ need_retrieval=False → 直接 LLM 回答(流式发 SSE: chunk结束
    │      │    └─ use_context=True 时带历史上下文use_context=False 时纯闲聊
    │      └─ 否则继续sub_queries 传入检索
    │      └─[DEV] 发 SSE: intent_result
    │
    ├─ 3. 混合检索    search_hybrid() → engine.search_knowledge()
    │      (内部:查询缓存检查 → 向量+BM25+RRF+废止过滤+章节过滤
    │        +云端Rerank+MMR去重+FAQ加权+黑名单+时间衰减
    │        +上下文扩展+自适应TopK
    │      └─[DEV] 发 SSE: retrieval_debug
    │
    ├─ 4. 提取上下文/来源(按 source 去重doc_type 驱动溯源展示)
    │      └─[DEV] 发 SSE: chunks_retrieved
    │      └─ 发 SSE: sources
    │
    ├─ 5. 图片补充检索 + 图片打分选择 (select_images)
    │      └─[DEV] 发 SSE: images_selected
    ├─ 6. 构建上下文 (_order_texts_for_prompt)
    │      └─[DEV] 发 SSE: context_built
    │
    ├─ 7. 流式答案生成  engine.generate_answer_stream()
    │      └─ 逐 token 发 SSE: chunk
    │
    ├─ 8. 答案图号对齐过滤
    ├─ 9. 引用标注      _attach_citations()
    ├─ 10. 敏感信息过滤  filter_response()
    ├─ 11. 语义缓存写入  SemanticCache.set()              # 写入缓存供后续命中
    ├─ 12. 发 SSE: finishanswer + sources + citations + images + timing
    └─[异常] 发 SSE: error

SSE 事件序列

SSE 事件 type 含义
start 请求开始处理
intent_result 意图分析结果 [DEV]
retrieval_debug 检索管线各步骤 [DEV]
chunks_retrieved 召回切片详情 [DEV]
sources 检索到的来源列表
images_selected 图片选择详情 [DEV]
context_built 最终上下文构建 [DEV]
chunk 流式答案的每个 token
finish timingsourcescitationsimages
error 处理异常时的错误信息

标注 [DEV] 的事件仅在 IS_DEV=True 时发送。


七、API 调用方式

7.1 SSE 流式问答(主要接口)

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": 200}

7.2 代码调用

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 缓存统计查询

# 查看各层缓存命中率和统计
curl http://localhost:5001/cache/stats \
  -H "Authorization: Bearer mock-token-admin"

返回示例:

{
  "query_cache": {"total_entries": 50, "hits": 10, "misses": 6, "hit_rate": 0.625},
  "embedding_cache": {"total_entries": 200, "hits": 0, "misses": 0, "hit_rate": 0},
  "rerank_cache": {"total_entries": 100, "hits": 0, "misses": 0, "hit_rate": 0},
  "semantic_cache": {"total_entries": 15, "hits": 6, "misses": 3, "hit_rate": 0.667}
}

注:当 Query Cache 或 Semantic Cache 在外层拦截了重复查询时Embedding Cache 和 Rerank Cache 的命中率为 0 是正常现象——重复查询根本不会到达这些层。


八、配置说明

8.1 LLM 配置

# 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 检索参数

# 混合检索
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_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 设备配置

DEVICE = "auto"                  # auto / cuda / cpu / cuda:0
EMBEDDING_DEVICE = DEVICE        # 向量模型设备
RERANK_DEVICE = DEVICE           # Rerank 模型设备

九、文件结构

core/                        # RAG 核心引擎
├── engine.py                #   RAGEngine 单例检索主流程、Rerank、RRF、流式生成
├── cache.py                 #   三层 LRU 缓存管理器Query/Embedding/Rerank
├── semantic_cache.py        #   语义缓存FAISS IndexFlatIP
├── 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            #   循环防护(当前未接入生产流程)
├── prompt_guard.py          #   Prompt 安全守卫
├── llm_budget.py            #   LLM 调用预算控制
├── llm_utils.py             #   LLM 调用工具函数
├── 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 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 入口

reports/                     # 分析报告
├── cache_performance_report.md  #   缓存性能验证报告
└── redis_migration_plan.md      #   Redis 缓存迁移方案(规划中)

config/                      # 运行时配置
└── banned_words.txt         #   敏感词库

十、与传统 RAG 对比

特性 传统 RAG 本系统
意图判断 IntentAnalyzer LLM 双层判断
查询改写 口语化→专业术语 + 实体补全 + 指代消解
检索方式 单一向量检索 向量 + BM25 + FAQ + 图片独立召回
融合算法 RRF 动态权重融合
去重 MMR 语义去重
重排序 云端 qwen3-rerank API支持本地 BGE 回退)
问题分解 自动拆分对比/推理类查询
闲聊处理 意图分析自动判断
缓存体系 四层缓存Query + Embedding + Rerank + 语义缓存)
语义缓存 FAISS 向量索引相似查询复用92x 加速)
自适应 TopK 固定 top_k 根据置信度动态调整
上下文理解 多轮对话 + 历史上下文
响应时间 ~2秒 首次 ~3-8秒 / 缓存命中 ~100-200毫秒

十一、Rerank 性能分析

11.1 Rerank 调用路径

Rerank 在生产流程中有 一个调用路径

路径 位置 说明
主检索管线 engine.rerank_results() RRF 融合后、MMR 去重前执行,对候选重排取 top_k

11.2 性能特征

项目 说明
Rerank 缓存命中率 偏低——键基于 query + sorted(doc_ids) 精确匹配RRF 融合产出稍有不同就无法命中
性能计时 rerank_results() 返回 _rerank_time_ms 计时字段
Query Cache 拦截 重复查询被 Query Cache 在外层拦截,不会到达 Rerank 层(正确行为)

11.3 Rerank 配置参数

配置项 默认值 说明
USE_RERANK True 总开关
RERANK_BACKEND "local" 后端选择
RERANK_CLOUD_MODEL "qwen3-rerank" 云端模型名称
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 本地模型路径
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 缓存开关

十二、最佳实践

12.1 何时使用 /rag 接口

推荐使用

  • 复杂问题需要检索知识库
  • 用户表达模糊需要改写
  • 需要区分闲聊和知识问答
  • 需要多轮对话记忆
  • 需要引用来源和证据

不推荐使用(改用 /search 接口更快):

  • 简单明确的问题,只需返回原始检索结果
  • 对响应时间极度敏感且不需要 LLM 生成答案的场景

12.2 性能优化

# ONNX 加速默认已开启;如有兼容性问题可关闭(环境变量)
# RERANK_USE_ONNX=false

# 使用轻量 MMR文本相似度代替语义向量
# config.py: MMR_USE_EMBEDDING = False

# 调整语义缓存阈值(降低阈值可提高命中率,但可能降低准确性)
# config.py: SEMANTIC_CACHE_THRESHOLD = 0.90

# 调整缓存容量
# config.py: QUERY_CACHE_SIZE = 1000  # 增大查询缓存容量

12.3 调试技巧

# 查看检索调试信息
result = engine.search_knowledge("问题", top_k=10)
debug = result.get('_debug', {})
for step in debug.get('steps', []):
    print(f"步骤: {step['name']}, 详情: {step}")

# 查看缓存统计
from core.cache import get_cache_manager
cm = get_cache_manager()
print(cm.get_stats())

# 查看语义缓存统计
from core.semantic_cache import get_semantic_cache
sc = get_semantic_cache()
print({"hits": sc.hits, "misses": sc.misses, "total": sc.total_entries})

十三、演进记录

v4.02026-06-05— 统一编排 + 四层缓存修复

删除未使用的备用编排路径:移除了 core/agentic.py 及 8 个 Mixin 文件(共 10 个文件 ~2050 行)。这些文件实现了完整的决策循环编排(含置信度门控、质量评估、推理反思等),但从未接入任何 HTTP 路由。

修复 Query Cache

  1. 修复 GET/SET 键不匹配——此前 SET 使用 doc_hash 分支GET 使用 kb_version 分支,两端永远不匹配,命中率始终为 0%
  2. 修复 CACHE_MIN_SCORE = 0.3 阈值过高——ChromaDB 余弦距离经 1-dist 后得分约 0.03-0.06,远低于 0.3,导致几乎不写入缓存

集成语义缓存:将 FAISS 语义缓存从已删除的备用路径移植到生产 /rag 端点,在意图分析后、混合检索前检查,命中时跳过整个检索+生成流程。验证结果:命中率 66.7%92 倍加速。

v3.2 — 模型/Reranker/管线更新

引入云端 qwen3-rerank、ONNX 加速、动态 RRF 权重等。


十四、未来规划

Redis 缓存外部化

当前四层缓存均为进程内内存存储,在多 Worker / 多实例部署时无法共享。已规划 Redis 迁移方案(详见 reports/redis_migration_plan.md),核心设计:

  • RedisCacheManager 提供与 RAGCacheManager 相同的接口
  • 通过 REDIS_CACHE_URL 环境变量启用,向后兼容
  • 语义缓存采用混合方案FAISS 索引保持在进程内,缓存结果存储到 Redis
  • Query Cache、Embedding Cache、Rerank Cache 全部迁移到 Redis

可选能力接入

core/ 目录下仍保留以下独立模块,当前未接入生产流程,可按需启用:

  • confidence_gate.py:置信度门控,基于 Reranker 分数判断检索质量
  • quality_assessor.py:多维质量评估(相关性/完整性/准确性/覆盖面)
  • reasoning_reflector.py:推理反思,检查未验证的假设
  • loop_guard.py:循环防护,防止重复检索

参考资料

  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