Files
rag/docs/RAG数据流程.md
lacerate551 8268071fdc docs: 模型切换至 mimo-v2.5 + 文档全面更新
- config.py: INTENT_MODEL 从 deepseek-v4-flash 切换至 mimo-v2.5
- config.py: get_intent_client() 从百炼 API 切换至 mimo API
- RAG系统完整指南.md: v4.0→v4.1,新增图片检索子系统、P0安全网、
  救援管线、五层缓存架构文档;替换所有旧模型名和API地址
- RAG数据流程.md: 完全重写,匹配实际代码逻辑
- curl测试手册.md: 更新模型名和Reranker配置
- MinerU模型部署指南.md: VLM_MODEL 更新为 mimo-v2.5
- 开发与系统模块说明.md: API地址和模型名更新
- 测试指南.md: API地址和模型名更新
2026-06-21 23:11:46 +08:00

26 KiB
Raw Blame History

RAG 数据流程

本文档基于当前代码实际逻辑梳理,详细记录 RAG 系统从用户查询到回答生成的完整数据流。 涵盖意图分析、混合检索、重排序、救援管道、上下文构建、图片选择与注入、LLM 生成和引用溯源等核心环节。


一、概述

1.1 检索管线总览

用户查询
    │
    ▼
┌─────────────────────────────────────────────────────────────────────────┐
│  1. 意图分析 (intent_analyzer)                                           │
│     问题改写 · 指代消解 · 是否需要检索 · 重复提问检测                       │
│     模型mimo-v2.5                                                     │
└─────────────────────────────────────────────────────────────────────────┘
    │
    ▼
┌─────────────────────────────────────────────────────────────────────────┐
│  2. 混合检索 (engine.search_knowledge)                                    │
│     ┌──────────────┐    ┌──────────────┐                                │
│     │  向量检索      │    │  BM25 检索    │                                │
│     │  (ChromaDB)   │    │  (关键词匹配)  │                                │
│     └──────┬───────┘    └──────┬───────┘                                │
│            └────────┬──────────┘                                         │
│                     ▼                                                    │
│              RRF 融合 (Reciprocal Rank Fusion)                            │
│                     │                                                    │
│              查询缓存检查 (命中则跳过 3-7 步)                                │
└─────────────────────────────────────────────────────────────────────────┘
    │
    ▼
┌─────────────────────────────────────────────────────────────────────────┐
│  3. 云端 Rerank                                                          │
│     模型xop3qwen8breranker (讯飞云)                                     │
│     结果缓存rerank_cache (TTL=1h, 版本失效自动清除)                      │
└─────────────────────────────────────────────────────────────────────────┘
    │
    ▼
┌─────────────────────────────────────────────────────────────────────────┐
│  4. 救援管道 (chat_routes.py)                                            │
│     BM25 分歧救援 · 词法匹配救援 · 章节聚类救援                             │
│     目的:挽救被 CrossEncoder 低估但实际相关的切片                          │
└─────────────────────────────────────────────────────────────────────────┘
    │
    ▼
┌─────────────────────────────────────────────────────────────────────────┐
│  5. 上下文构建 + 图片选择                                                  │
│     _order_text_contexts_for_prompt · _build_context_with_budget          │
│     select_images · VLM 相关性筛选 · CrossEncoder 精排                    │
│     懒加载 VLM 描述 · 图片描述注入 · P0 安全网                              │
└─────────────────────────────────────────────────────────────────────────┘
    │
    ▼
┌─────────────────────────────────────────────────────────────────────────┐
│  6. LLM 生成                                                             │
│     模型mimo-v2.5                                                      │
│     流式输出 · 置信度指令 · 引用标注 · 图片后置过滤                          │
└─────────────────────────────────────────────────────────────────────────┘
    │
    ▼
┌─────────────────────────────────────────────────────────────────────────┐
│  7. 返回结果                                                              │
│     { answer, sources, images }                                          │
└─────────────────────────────────────────────────────────────────────────┘

1.2 模型配置一览

用途 模型 API 端点 说明
主 LLM mimo-v2.5 xiaomimimo.com 回答生成、上下文理解
意图分析 mimo-v2.5 xiaomimimo.com 问题改写与意图判断
VLM mimo-v2.5 xiaomimimo.com 图片理解与描述生成
云端重排序 xop3qwen8breranker 讯飞云 Maas API 替代本地 BGE-reranker
向量编码 bge-base-zh-v1.5 本地模型 查询与文档 embedding

模型可通过环境变量覆盖:DASHSCOPE_MODELINTENT_MODELVLM_MODELRERANK_CLOUD_MODEL

1.3 关键配置参数

参数 默认值 说明
RERANK_CONTEXT_MIN_SCORE 0.05 Rerank 分数低于此值的切片不送入 LLM
MAX_CONTEXT_CHUNKS 20 送给 LLM 的最大文本切片数
CONTEXT_MAX_CHARS 8000 上下文最大字符数(约 4000 token
CONTEXT_SOFT_LIMIT 6000 软限制,超过后只接受高分切片组
CONFIDENCE_WARN_THRESHOLD 0.15 top-3 均分低于此值时,提示 LLM 谨慎回答
CONFIDENCE_CAUTION_THRESHOLD 0.30 top-3 均分低于此值时,提示 LLM 优先引用原文

二、请求入口

2.1 API 路由

入口文件api/chat_routes.py

POST /chat    — 普通聊天(不检索知识库,直接 LLM 回答)
POST /rag     — 知识库问答(检索 + LLM 生成)
POST /search  — 纯检索(返回切片,不生成回答)

/rag 的核心函数 rag() 的职责:

  1. 调用意图分析模块,获取改写后的查询与检索决策
  2. 若需要检索,调用混合检索管线(search_hybrid()
  3. 执行救援管道BM25 分歧 / 词法匹配 / 章节聚类)
  4. 执行图片选择(select_images()
  5. 构建 LLM 上下文(排序 + 预算截断 + 图片注入)
  6. 调用 LLM 生成回答(流式输出)
  7. 后置图片过滤(_filter_images_by_answer()
  8. 组装最终响应(回答 + 引用来源 + 图片)

2.2 请求数据结构

# 请求
{
    "message": "用户问题",
    "history": [...]       # 可选:对话历史
}

# SSE 响应事件流
data: {"type": "intent_result", "data": {...}}
data: {"type": "chunks_retrieved", "data": {...}}
data: {"type": "images_selected", "data": {...}}
data: {"type": "context_built", "data": {...}}
data: {"type": "chunk", "content": "部分回答"}
data: {"type": "chunk", "content": "部分回答"}
...
data: {"type": "finish", "answer": "完整回答", "sources": [...], "images": [...]}

三、意图分析

入口文件core/intent_analyzer.py 使用模型mimo-v2.5

3.1 核心功能

意图分析器在检索前对用户查询进行预处理,输出结构化决策:

@dataclass
class IntentAnalysis:
    rewritten_query: str    # 改写后的查询(指代消解、省略补全)
    use_context: bool       # 是否使用历史上下文
    need_retrieval: bool    # 是否需要检索知识库
    intent: str             # 意图类型factual/comparison/reasoning/instruction
    sub_queries: list       # 子查询列表(对比/复杂查询拆分)

3.2 处理逻辑

功能 说明
问题改写 指代消解("它" → 具体实体)、省略补全(补全缺失主语)
上下文判断 根据对话历史决定是否需要前文信息
检索决策 判断是否需要查询知识库(闲聊类问题可跳过)
意图分类 识别查询意图(事实查询/对比分析/推理/操作指导)
子查询拆分 对比类查询拆分为多个子查询并行检索
语义缓存 相似度 ≥ 0.92 时复用历史意图分析结果

3.3 重复提问规则

当用户重复提问相同或相似问题时,意图分析器必须设置 need_retrieval = true。原因:用户可能对之前的回答不满意,或之前的回答包含错误信息,需要重新检索以获取更准确的结果。


四、检索阶段

入口文件core/engine.py 核心函数search_knowledge()

4.1 查询缓存检查

检索前先检查缓存,命中则直接返回历史结果,避免重复计算:

cached = cache.get_query_result(query, kb_name)
if cached:
    return cached

缓存层级5 层):

  1. query_cache — 精确查询结果缓存
  2. embedding_cache — embedding 向量缓存
  3. rerank_cache — rerank 分数缓存TTL=1h知识库版本变更自动失效
  4. semantic_cache — 语义相似查询缓存(阈值 0.92
  5. intent_exact_cache — 意图分析精确缓存

4.2 向量检索

使用本地 bge-base-zh-v1.5 模型将查询编码为向量,在 ChromaDB 中执行 ANN 检索:

query_vector = embedding_model.encode(query)
text_results = collection.query(
    query_embeddings=[query_vector],
    n_results=100   # recall_k召回候选数量
)

图片独立召回:同时对图片切片进行独立检索,保证图片有足够的召回机会:

image_results = collection.query(
    query_embeddings=[query_vector],
    where={'chunk_type': {'$in': ['image', 'chart', 'table']}},
    n_results=5
)

4.3 BM25 关键词检索

基于 BM25 算法执行关键词匹配检索,弥补向量检索在精确匹配上的不足:

bm25_results = bm25_index.search(query, top_k=100)

4.4 RRF 融合

使用 Reciprocal Rank Fusion 算法将向量检索和 BM25 检索的结果进行融合排序:

fused_results = reciprocal_rank_fusion(
    [text_results, image_results, bm25_results],
    weights=[VECTOR_WEIGHT, IMAGE_WEIGHT, BM25_WEIGHT]
)

4.5 子查询并行检索

意图分析器拆分的子查询(如对比类查询)会并行检索,结果合并后再 rerank。


五、重排序

5.1 云端 Rerank

调用模型xop3qwen8breranker讯飞云 Maas API

RRF 融合后的候选结果通过云端 Reranker 进行精排,基于查询与文档的语义相关性重新打分排序:

reranked = rerank_results(query, fused_results, top_k=15)

重要特征CrossEncoder 对不同类型切片的评分分布差异显著:

切片类型 典型分数范围 说明
文本切片 0.3 ~ 0.99 正常分布
表格切片 0.1 ~ 0.5 偏低,有专用救援逻辑
图片/图表切片 0.002 ~ 0.08 系统性偏低,需要宽松阈值

5.2 Rerank 缓存

  • 每个 (query, doc_id) 对的 rerank 分数独立缓存
  • TTL = 1 小时
  • 知识库版本号变更时自动失效

六、救援管道

入口文件api/chat_routes.py 目的:挽救被 CrossEncoder 低估但实际相关的切片

_order_text_contexts_for_prompt 之前执行,三个救援管道按顺序运行:

6.1 BM25 分歧救援 _rescue_bm25_divergence

触发条件BM25 排名 top-3 但 CrossEngineer 评分低于 min_score 的切片

逻辑BM25 是关键词精确匹配的强信号,如果 BM25 认为相关但 CE 误判,提升分数至保底值。

# 配置
BM25_DIVERGENCE_RESCUE_ENABLED = True
BM25_DIVERGENCE_MAX_RANK = 3  # 仅救援 BM25 rank <= 3 的切片

6.2 词法匹配救援 _rescue_lexical_match

触发条件切片文本精确包含查询关键词bigram 匹配率 > 35%)但 CE 评分低

逻辑当切片文本直接包含查询中的关键词组合时说明语义相关CE 可能因为表述差异低估。

6.3 章节聚类救援 _rescue_section_cluster

触发条件:同一 section 内所有切片都被 min_score 过滤("全灭 section"

逻辑:如果同一章节的切片全部被过滤,但其他章节有切片通过,说明 CE 对该章节整体低估。为全灭 section 的切片分配保底分数0.06)。

# 配置
SECTION_CLUSTER_RESCUE_ENABLED = True
CLUSTER_RESCUE_FLOOR = 0.06  # 略高于 RERANK_CONTEXT_MIN_SCORE=0.05

6.4 表格救援 _rescue_table_chunks

触发条件:查询涉及表格但上下文中没有表格数据(表格被预算截断)

逻辑:从被截断的切片中补回表格数据。


七、上下文构建

7.1 切片排序与过滤 _order_text_contexts_for_prompt

核心逻辑

  1. 文本切片 + 表格切片 → 进入 text_contexts
  2. 图片/图表切片 → 进入 chart_contexts(独立处理)
  3. min_score 过滤
    • text_contexts:使用 RERANK_CONTEXT_MIN_SCORE0.05
    • 表格保护:同 section 内如有切片通过阈值table 切片保底分数为 min_score * 0.3
    • chart_contexts:使用宽松阈值 min_score * 0.50.025
      • 原因CrossEncoder 对图片描述评分系统性偏低
      • 实际内容相关性由 select_images 独立评分保证
  4. 合并text_contexts + chart_contexts[:3]

7.2 预算构建 _build_context_with_budget

按字符预算构建上下文文本:

  1. 按 (source, section) 分组
  2. 组内按 chunk_index 排序(保持原文连续性)
  3. 组间按组内最高 Rerank 分数降序
  4. 逐组加入直到达到 CONTEXT_MAX_CHARS8000
  5. 超过 CONTEXT_SOFT_LIMIT6000后收紧准入

特殊处理:表格切片不受预算截断(结构化关键内容)

7.3 图片选择 select_images()

从检索结果中筛选与查询最相关的图片:

步骤一:动态预算

查询类型 MAX_IMAGES MIN_SCORE 检测方式
精确图号查询("图2.3" 2 5.0 正则匹配 图\s*(\d+\.?\d*)
有图片数据(检索含 image/chart 5 2.0 检查检索结果 chunk_type
文本引用图表 3 2.0 提取 top-5 文本中的图号/表号
普通查询 2 3.0 默认

步骤二:提取图表引用

从 top 5 文本块中提取 "见图2.3"、"如表2.2" 等引用,建立图号与来源文件的映射。

步骤三:图片相关性打分 score_image_relevance()

匹配项 加分
图号精确匹配(查询中有"图2.3" +10 分
表号精确匹配 +10 分
关键词匹配jieba 分词) +2 分/个,上限 8 分
字符重叠 +0.2 分/字符,上限 3 分
章节匹配 +1.5 分/关键词
图片类型chart +2 分
图片类型image +1 分
向量相似度 +2 分(最高)
引用匹配 + 章节相关 +8 分 + 5 分
VLM 相关性 < 0.3 -3 分VLM 描述与查询不相关)
VLM 相关性 ≥ 0.5 +2 分
章节不相关 -5 分(除非被文本引用)

步骤四VLM 相关性筛选

对有 VLM 描述的图片,使用关键词重叠率判断描述与查询的相关性:

  • 重叠率 < 0.3:降分 -3描述与查询不相关
  • 重叠率 ≥ 0.5:加分 +2

步骤五CrossEncoder 精排

select_images 候选用 CE 做语义精排:

  • CE < 0直接剔除语义不相关
  • CE 0~2保留但不加分弱相关
  • CE > 2加分 min((ce - 2) / 3, 1) * 5

步骤六:表格嵌入图片补充

处理 images_json 字段的表格切片,补充表格中嵌入的图片。

步骤七:文本引用图片补充

从 top 5 文本块中提取 referenced_images 字段,补充未选中的关联图片。

步骤八:返回 top N

scored_images.sort(key=lambda x: x['score'], reverse=True)
return scored_images[:MAX_IMAGES]

7.4 图片描述注入

核心逻辑:将 select_images 选中的图片的 full_description 注入到 LLM context 中。

context_text文本切片
    +
【相关图片信息】
【图片1】VLM 完整描述来源xxx 第N页
【图片2】VLM 完整描述来源xxx 第N页
    +
【回答要求】回答时请简要介绍每张图片的内容和用途。

P0 安全网(防止图片描述被过滤遗漏):

  1. selected_images 非空但 【相关图片信息】 未生成 → 补注入所有选中图片描述
  2. 若已有 【相关图片信息】 但遗漏部分图片 → 追加遗漏的描述
  3. DEV 模式日志:检查所有选中图片的 ID 是否出现在 context 中

7.5 置信度指令

根据 top-3 切片的平均 Rerank 分数注入不同的回答指令:

置信度范围 指令
< 0.15 "参考资料与问题的相关性较低,仅基于明确信息回答,不足则说明"
0.15 ~ 0.30 "参考资料的相关性一般,优先引用资料原文,避免推测"
≥ 0.30 无额外指令

八、LLM 生成

8.1 流式生成

使用 SSEServer-Sent Events实现流式输出

for token in engine.generate_answer_stream(query, enhanced_context, history):
    yield token  # 逐 token 推送给前端

LLM 模型mimo-v2.5

8.2 System Prompt

你是一个严谨的知识库问答助手。
你必须且只能根据用户提供的【参考资料】回答问题。
如果参考资料中有答案,必须引用对应内容回答,并在回答末尾标注引用编号。
如果参考资料中确实没有相关信息,简短说明即可,不要编造或补充资料外的内容。
禁止使用参考资料以外的知识进行补充或推测。
【重要-表格处理规则】当用户询问表格时,必须将 Markdown 表格原样输出...

8.3 图片后置过滤 _filter_images_by_answer

LLM 生成回答后,根据回答内容对图片做最终过滤:

  1. 候选 ≤ 1 张:直接返回
  2. 无图意图早退:回答和查询都不含图片引用词 → 返回空
  3. 图号精确豁免:图片描述包含回答引用的具体图号/表号 → 无条件保留
  4. 主题一致性:合并查询+回答关键词,图片描述重叠 ≥ 阈值才保留
    • 子章节惩罚:图片子章节与主要检索章节不一致时,阈值 +2
  5. 兜底:过滤后为空且有图片意图 → 保留分数最高的 1 张

8.4 回答结构

{
    "type": "finish",
    "answer": "根据蓄水以来的统计数据,三峡电站逐年发电量呈现波动上升趋势...",
    "sources": [
        {
            "source": "三峡公报_2022.pdf",
            "page": 12,
            "section": "综述 > 2.3 发电",
            "chunk_id": "三峡公报_text_24"
        }
    ],
    "images": [
        {
            "id": "ab77281e7913.jpg",
            "url": "/images/ab77281e7913.jpg",
            "type": "chart",
            "source": "三峡公报_2022.pdf",
            "page": 12,
            "description": "图2.3 柱状图2003-2022年逐年发电量",
            "full_description": "...完整 VLM 描述..."
        }
    ]
}

九、引用溯源

9.1 引用标注机制

_attach_citations() 负责在回答中插入引用标记,将回答内容与知识库来源关联:

根据统计数据[ref:三峡公报_text_24]2022年三峡电站年度发电量为787.90亿千瓦时[ref:三峡公报_table_5]。

9.2 引用数据来源

每个引用标记对应检索结果中的一个切片,包含:

字段 说明
source 源文件名
page 页码
section 章节路径
chunk_id 切片唯一标识
chunk_type 类型text / table / image / chart

十、文档入库流程(补充参考)

入库流程为检索提供数据基础,以下简要说明关键环节。

10.1 文档解析

入口文件parsers/mineru_parser.py 核心函数parse_with_mineru()

MinerU 解析 PDF/Word/Excel 文件,输出结构化内容:

.data/mineru_temp/{file_hash}/
├── auto/
│   ├── {doc_name}.md                  # Markdown 内容
│   ├── {doc_name}_content_list.json   # 结构化内容列表(核心)
│   └── images/                        # 提取的图片文件

content_list.json 中的条目类型

item_type 处理方式 关键字段
text 文本块 content, section_path, text_level
table 表格 content, table_html, image_path
image 图片 content(=caption), image_path, context_before/after
chart 图表 content(=caption), image_path, context_before/after

10.2 切片入库

入口文件knowledge/manager.py 核心函数add_file_to_kb()

MinerUChunk 列表
    │
    ├── 文本块 → 计算 embedding → 存入 ChromaDB
    │
    ├── 表格块 → 生成语义增强摘要 → 存入 ChromaDB
    │
    └── 图片块 → VLM 缓存检查 → 生成描述 → 存入 ChromaDB

图片描述策略

  1. 优先使用 VLM 缓存描述(由 mimo-v2.5 生成,语义更丰富)
  2. 若无缓存,生成轻量描述(基于文件名 + 章节路径 + 上下文)
  3. VLM 描述异步懒加载:首次检索命中时后台生成,下次查询即可使用

10.3 ChromaDB 存储结构

字段 类型 说明
ids str 切片唯一标识,如 doc.pdf_text_24
embeddings List[float] 向量表示
documents str 切片内容(文本/VLM 描述/摘要)
metadatas dict 元数据(见下表)

图片切片 metadata 关键字段

{
    'source': '三峡公报_2022.pdf',      # 源文件名
    'page': 12,                         # 页码
    'chunk_type': 'chart',              # 切片类型
    'section': '综述 > 2.3发电',        # 章节路径
    'image_path': 'ab77281e7913.jpg',   # 图片文件名
    'has_vlm_desc': True,               # 是否有 VLM 描述
    'vlm_desc': '图2.3 柱状图...',      # VLM 描述内容
    'chunk_id': '三峡公报_chart_5',     # 切片唯一标识
    'version': 'v10',                   # 知识库版本号
    'status': 'active',                 # 状态
}

注意ChromaDB metadata 中没有 full_description 字段。图片的完整描述存储在 vlm_desc 字段或 documents 字段中。full_description 仅在 select_images() 运行时动态计算。

10.4 懒加载增强

入口文件knowledge/lazy_enhance.py

对检索命中但没有 VLM 描述的图片切片,在后台线程异步调用 VLM 生成描述:

# 检索命中 → 后台线程调用 VLM → 写入文件缓存 + ChromaDB
enhance_retrieved_chunks(contexts, query, kb_name, defer_chromadb=True)
  • image/chart 切片:更新 ctx['doc'] 字段
  • table 切片:更新 ctx['image_description'] 字段
  • 缓存目录.data/cache/vlm/.data/cache/llm/

十一、缓存系统

11.1 缓存层级

层级 用途 容量 TTL
query_cache LRUCache 精确查询结果缓存 500
embedding_cache LRUCache 查询 embedding 向量 500
rerank_cache TTLCache Rerank 分数缓存 500 1h
semantic_cache SemanticCache 语义相似查询缓存 200
intent_exact_cache LRUCache 意图分析精确缓存 200

11.2 缓存失效

  • 版本失效知识库版本号变更时query_cache 和 rerank_cache 自动失效
  • 手动清除POST /cache/clearDEV 模式)

11.3 缓存 API

GET  /cache/stats   — 查看缓存统计
POST /cache/clear   — 清除所有缓存

十二、关键文件索引

文件 职责 关键函数/类
api/chat_routes.py API 路由与请求调度 rag(), select_images(), score_image_relevance(), _filter_images_by_answer(), _order_text_contexts_for_prompt(), _build_context_with_budget()
core/engine.py 检索引擎核心 search_knowledge(), rerank_results(), generate_answer_stream()
core/intent_analyzer.py 意图分析 analyze(), IntentAnalysis
core/bm25_index.py BM25 关键词检索 BM25Index.search()
core/mmr.py MMR 去重 mmr_rerank()
core/cache.py 缓存管理 RAGCacheManager, get_cache_manager()
core/semantic_cache.py 语义缓存 SemanticCache
core/chunker.py 语义分块器 SemanticChunker
core/llm_utils.py LLM 调用工具 call_llm(), call_llm_stream()
parsers/mineru_parser.py 文档解析 parse_with_mineru(), MinerUChunk
knowledge/manager.py 知识库管理 add_file_to_kb(), KBManager
knowledge/lazy_enhance.py 懒加载增强 lazy_vlm_description(), enhance_retrieved_chunks()
config.py 配置集中管理 模型/参数/开关