Files
ailine/app/rag/README.md
2026-04-18 16:31:48 +08:00

137 lines
7.6 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.

# 在线 RAG 检索与生成系统 (Online RAG Retriever)
该模块负责 RAG 系统的阶段二:**在线检索与生成**。它接收用户提问,从知识库中检索出上下文,利用各种高级策略去噪、融合,并作为增强上下文输入给大语言模型 (LLM)。
## 📊 RAG-Fusion & 混合检索流水线示意图
```mermaid
graph TD
User((用户提问)) --> A[LLM 查询改写生成器]
subgraph RAG-Fusion 核心流程
A -->|改写为问题 1| B1[查询 1]
A -->|改写为问题 2| B2[查询 2]
A -->|原问题| B3[原始查询]
B1 & B2 & B3 --> C[混合检索器 Hybrid Retriever <br> Dense Vector + BM25 Sparse]
C --> D[多路召回结果合集 N=60条]
D --> E{RRF 倒数排名融合去重}
end
E -->|筛选出前 20 条| F[Cross-Encoder 重排器 Reranker]
F -->|精细打分排序 Top 5| G[最终纯净上下文 Context]
G --> H[将 Context 与原问题拼接输入大模型]
H --> I((LLM 生成最终回答))
```
---
## 🎯 演进路线与算法详解 (Roadmap)
### Level 1: 基础向量搜索 (Basic Similarity Search)
- **核心算法**: 近似最近邻搜索 (ANN, 常用 HNSW 算法)。将用户问题转化为向量后,计算它与库中向量的余弦相似度 (Cosine Similarity),取距离最近的 K 个块。
- **优缺点**: 速度极快。但只能捕捉“语义相似”,如果用户搜索特定专有名词、编号、订单号,纯向量检索往往会失效(产生“幻觉”匹配)。
### Level 2: 混合检索与重排序 (Hybrid Search + Reranker)
混合检索旨在结合向量的“语义泛化”与关键词的“精准匹配”,随后利用重排序模型过滤噪声。
**1. 基础召回 (混合检索)**
- **核心原理**: 结合基于 HNSW 的 Dense Vector 相似度搜索与基于 TF-IDF 的 BM25 稀疏检索 (Sparse Vector)。
- **实现指南**: 使用 `langchain_qdrant` 包中的 `Qdrant` 类连接数据库。通过调用 `Qdrant.from_existing_collection(...)` 实例化向量库,并使用 `.as_retriever(search_kwargs={"k": 20})` 方法生成基础检索器。Qdrant 底层会自动处理双路召回。
**2. 二次精排 (Cross-Encoder)**
- **核心原理**: 不同于双塔模型(分别算向量再求距离),交叉编码器将“用户问题 + 检索到的单例文档”拼接后整体输入 Transformer 模型,由模型直接输出 0~1 的相关性得分,精度极高。
- **实现指南**:
- 使用 `sentence-transformers` 库加载本地轻量级重排模型(如 `BAAI/bge-reranker-base`)。
- 引入 `langchain.retrievers.document_compressors` 包中的 `CrossEncoderReranker` 类包装该模型,设置参数 `top_n=5`
- 最后,使用 `langchain.retrievers` 包中的 `ContextualCompressionRetriever` 类,将 `base_compressor` (重排器) 和 `base_retriever` (基础检索器) 组合。
- **如何调用**: 业务逻辑中直接对组合后的检索器调用 `.invoke(query)` 方法,即可一键完成“大范围召回 20 条 -> 逐一打分精排选 5 条”的去噪流水线。
### Level 3: RAG-Fusion (多路改写与倒数排名融合)
RAG-Fusion 通过大模型发散思维,将单一问题改写为多个相似问题,扩大搜索面,再利用数学统计算法合并结果。
**1. 多路查询改写**
- **核心原理**: 克服用户初始提问词不达意或视角受限的问题。
- **实现指南**: 导入 `langchain.retrievers.multi_query` 包中的 `MultiQueryRetriever` 类。需向其提供一个已实例化的 LLM 对象(如基于 `ChatOpenAI` 封装的本地 VLLM 模型)。系统在底层会自动 Prompt 模型,将原始 `query` 转化为包含 3-5 个不同表述的查询列表。
**2. 倒数排名融合 (RRF)**
- **核心原理**: RRF (Reciprocal Rank Fusion) 是一种无需评分归一化的融合算法。公式为 $RRF\_score(d) = \sum_{q \in Q} \frac{1}{k + rank_q(d)}$,有效避免某一极端检索结果主导全局。
- **实现指南**:
- 针对每个改写后的查询 $q$,分别调用精排检索器的 `.invoke(q)` 获取文档列表。
- 使用 `langchain.retrievers` 中的 `EnsembleRetriever` 类(原生支持 RRF或在代码中遍历收集到的 `Document` 对象,基于其排名 `rank` 累加得分,最终通过 Python 的 `set` 去重并提取 `doc.page_content`
### Level 4: Agentic RAG / Self-RAG (智能体与自我反思)
- **核心原理**: 基于 LangGraph 的 ReAct (Reasoning and Acting) 状态机路由。大模型并非每次都去死板地执行检索,而是先判断问题:“这是闲聊?还是需要查知识库?”。如果是后者,模型输出一个 `ToolCall` 指令,触发检索。
- **实现指南**: 请参考下方的**与现有系统整合调用**章节。
- **示意图**:
```mermaid
sequenceDiagram
participant User
participant LangGraph Agent
participant RAG_Tool
participant Qdrant
User->>LangGraph Agent: "公司报销流程是什么?"
LangGraph Agent->>LangGraph Agent: 思考: 这是一个内部规章问题,需要查资料
LangGraph Agent->>RAG_Tool: ToolCall(search_knowledge_base, "公司报销流程")
RAG_Tool->>Qdrant: RAG-Fusion & 混合检索
Qdrant-->>RAG_Tool: 原始分块
RAG_Tool->>RAG_Tool: Cross-Encoder 重排过滤
RAG_Tool-->>LangGraph Agent: 返回最相关的5条报销规定
LangGraph Agent->>LangGraph Agent: 思考: 资料充分,开始撰写回答
LangGraph Agent-->>User: "根据知识库规定报销流程分为以下3步..."
```
---
## 📦 所需依赖与安装
除了基础的 LangChain 包外,在线检索模块为了支持重排和稀疏检索,还需要安装:
```bash
# 用于 Cross-Encoder 重排序模型 (如 BAAI/bge-reranker-base)
pip install sentence-transformers
# 用于 BM25 关键词混合检索
pip install rank_bm25
# 基础框架
pip install langchain langchain-core langchain-openai langchain-qdrant
```
---
## 📂 架构与文件结构设计
在 `app/rag/` 目录下,需创建以下文件来模块化上述功能:
```text
app/rag/
├── __init__.py
├── retriever.py # 负责 Qdrant 的基础召回与 ContextualCompressionRetriever
├── reranker.py # 负责加载 sentence-transformers 交叉编码器
├── query_transform.py # 负责基于 MultiQueryRetriever 的改写逻辑
├── pipeline.py # 组合上述组件,暴露出核心的 retrieve() 方法
└── tools.py # 将 Pipeline 包装成 LangChain Tool 供 Agent 调用
```
---
## <20> 与现有系统整合调用 (Agentic RAG 实现)
基于目前 LangGraph 系统的架构,我们将摒弃将代码堆砌在一起的旧方式,而是利用 **LangChain Tools** 的特性将 RAG 优雅地注入系统:
1. **封装检索工具 (Tool)**:
从 `langchain.tools` 导入 `@tool` 装饰器。定义一个名为 `search_knowledge_base(query: str)` 的函数。在函数内部,实例化并调用我们在 `pipeline.py` 中写好的多路召回与重排逻辑。
2. **模型绑定 (Bind)**:
在 `app/agent.py` 或 `app/nodes/tool_call.py` 中,将这个工具引入,并通过 `llm.bind_tools([search_knowledge_base])` 绑定到现有的本地大模型实例上。
3. **状态机路由 (Graph Routing)**:
你的 LangGraph 状态机会像处理普通对话一样自动接管:当模型判断需要调用查阅规章制度或专业资料时,它会输出 `ToolCall` 消息,流转到 `tool_node` 执行上述的 RAG 检索逻辑并返回上下文。
这让你无需修改任何前端 Streamlit 流式代码,就能平滑升级为具备超级知识库检索能力的智能体 (Agent)