RAG 检索流程(从用户输入到回答生成) ┌─────────────────────────────────────────────────────────────────────────┐ │ 1. 用户输入问题 │ │ "蓄水以来逐年发电量" │ └─────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────┐ │ 2. 意图分析 (core/intent_analyzer.py) │ │ ├── 问题改写:指代消解、省略补全 │ │ ├── use_context:是否使用历史上下文 │ │ ├── need_retrieval:是否需要检索知识库 │ │ └── 重复提问强制检索(新增规则) │ └─────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────┐ │ 3. 混合检索 (core/engine.py - search_knowledge) │ │ │ │ 3.1 向量检索 │ │ query_vector = embedding_model.encode(query) │ │ text_results = collection.query(query_embeddings, n_results=100) │ │ │ │ 3.2 图片独立召回(P0 新增) │ │ image_results = collection.query( │ │ where={'chunk_type': {'$in': ['image', 'chart', 'table']}}, │ │ n_results=5 # 独立控制图片数量 │ │ ) │ │ │ │ 3.3 BM25 关键词检索(可选) │ │ bm25_results = bm25_index.search(query, top_k=100) │ │ │ │ 3.4 RRF 融合 │ │ fused_results = reciprocal_rank_fusion([text, image, bm25]) │ │ │ │ 3.5 MMR 去重 │ │ fused_results = _apply_mmr(query, fused_results, top_k=30) │ │ │ │ 3.6 Rerank 重排序 │ │ final_results = rerank_results(query, fused_results, top_k=15) │ └─────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────┐ │ 4. 检索结果处理 (api/chat_routes.py) │ │ │ │ 4.1 构建 contexts │ │ for each result: │ │ if 图片切片: │ │ doc = meta['full_description'] # 使用完整描述(P1) │ │ else: │ │ doc = result['document'] │ │ contexts.append({'doc': doc, 'meta': meta}) │ │ │ │ 4.2 懒加载增强(可选) │ │ enhance_retrieved_chunks(contexts, query, kb_name) │ │ └── 对无 VLM 描述的图片生成 VLM 描述 │ └─────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────┐ │ 5. 图片选择 (api/chat_routes.py - select_images) │ │ │ │ 5.1 意图检测 │ │ - 精确图号查询:"图2.3" → MAX_IMAGES=2, MIN_SCORE=5.0 │ │ - 弱图片意图:"发电量图" → MAX_IMAGES=1 │ │ - 普通查询 → MAX_IMAGES=2 │ │ │ │ 5.2 提取图表引用(从 top 5 文本块) │ │ referenced_figures = {'2.3': {来源文件}} │ │ │ │ 5.3 图片打分 │ │ for each image in contexts: │ │ score = score_image_relevance(query, meta, doc) │ │ └── 图号匹配 +10 分 │ │ └── 关键词匹配 +2 分/个 │ │ └── 章节匹配 +1.5 分 │ │ └── 引用匹配 +8 分(需章节相关) │ │ │ │ 5.4 图文关联补充(P2 新增) │ │ for text_chunk in top 5: │ │ for fig_num in text_chunk['referenced_images']: │ │ 查找对应的图片切片并补充到结果中 │ │ │ │ 5.5 返回 top N 图片 │ │ return scored_images[:MAX_IMAGES] │ └─────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────┐ │ 6. 构建 LLM Prompt │ │ │ │ 6.1 文本上下文 │ │ context_text = "\n\n".join([ctx['doc'] for ctx in contexts[:5]]) │ │ │ │ 6.2 图片信息 │ │ if selected_images: │ │ image_info = "【可用图片】\n" + 图片描述列表 │ │ │ │ 6.3 最终 Prompt │ │ enhanced_context = context_text + image_info │ └─────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────┐ │ 7. LLM 生成回答 │ │ │ │ for token in engine.generate_answer_stream(query, enhanced_context): │ │ yield token # 流式输出 │ └─────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────┐ │ 8. 返回结果 │ │ { │ │ "type": "finish", │ │ "answer": "完整回答文本", │ │ "sources": [...], // 引用来源 │ │ "images": [...] // 精选图片 │ │ } │ └─────────────────────────────────────────────────────────────────────────┘ 关键优化点总结 ┌──────┬──────────────────┬────────────────────────────────────┐ │ 阶段 │ 优化 │ 效果 │ ├──────┼──────────────────┼────────────────────────────────────┤ │ 检索 │ P0: 图片独立召回 │ 图片保证进入候选池 │ ├──────┼──────────────────┼────────────────────────────────────┤ │ 入库 │ P1: 双字段存储 │ 短摘要用于检索,完整描述用于上下文 │ ├──────┼──────────────────┼────────────────────────────────────┤ │ 入库 │ P2: 图文关联索引 │ 文本命中时补充关联图片 │ ├──────┼──────────────────┼────────────────────────────────────┤ │ 选择 │ 章节相关性检查 │ 避免不相关图片加分 │ ├──────┼──────────────────┼────────────────────────────────────┤ │ 意图 │ 重复提问强制检索 │ 避免复用错误上下文 │ └──────┴──────────────────┴────────────────────────────────────┘