Files
ailine/backend/app/rag/README.md
root 8b5fbbd395
Some checks failed
构建并部署 AI Agent 服务 / deploy (push) Failing after 6m35s
修改readme
2026-05-05 14:06:36 +08:00

273 lines
12 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)。
## 🎯 核心架构
### 技术栈
| 组件 | 技术选型 | 说明 |
|:-----|:---------|:-----|
| **基础检索** | `Qdrant` | HNSW 稠密向量检索 |
| **混合检索** | `Qdrant` + `BM25` | 稠密 + 稀疏向量融合Qdrant 原生 RRF |
| **查询改写** | `LangChain` | `MultiQueryGenerator` 多路改写 |
| **重排序** | `llama.cpp` | 本地服务OpenAI 兼容 Rerank API |
| **编排框架** | `asyncio` | 异步并行检索 |
| **服务接入** | `model_services` | 统一获取嵌入、LLM、重排序服务 |
### 检索流水线
```
用户查询
┌───────────────────┐
│ MultiQueryGenerator │ (可选)
│ 多路查询改写 │
└─────────┬─────────┘
┌───────────────────┐
│ 并行检索 │
│ (asyncio.gather) │
└─────────┬─────────┘
┌───────────────────┐
│ Qdrant 混合检索 │
│ (dense + sparse) │
└─────────┬─────────┘
┌───────────────────┐
│ RRF 分数融合 │ (Qdrant 原生)
└─────────┬─────────┘
┌───────────────────┐
│ 重排序 (可选) │
└─────────┬─────────┘
┌───────────────────┐
│ 父文档获取 │
└─────────┬─────────┘
增强上下文
```
### 技术特性
-**Qdrant 原生混合检索**:稠密向量 + BM25 稀疏向量,服务端 RRF 分数融合
-**父子文档策略**:子块精准检索,父块提供完整上下文
-**多路查询改写**:通过 LLM 将单一问题改写为多个不同角度的查询
-**远程重排序**:使用 llama.cpp 服务的 OpenAI 兼容 Rerank API
-**完全异步化**:检索、融合、重排序全链路 async / await
-**统一服务接入**:所有模型服务通过 `model_services` 获取
## 📂 架构与文件结构
```
backend/app/rag/
├── __init__.py
├── retriever.py # Qdrant 混合检索器(含父子文档支持)
├── rerank.py # llama.cpp 远程重排序器
├── query_transform.py # 多路查询改写生成器
├── fusion.py # RRF 融合算法(备用)
├── pipeline.py # RAG 流水线编排
├── tools.py # LangChain Tool 封装
├── evaluate.py # 评估工具
└── README.md # 本文档
backend/app/model_services/
├── embedding_services.py # 嵌入服务
├── chat_services.py # LLM 服务
└── rerank_services.py # 重排序服务
backend/rag_core/
├── vector_store.py # Qdrant 混合存储
├── sparse_embedder.py # BM25 稀疏嵌入
├── doc_store.py # PostgreSQL 文档存储
└── ... # 其他核心组件
```
## 🎯 演进路线与算法详解 (Roadmap)
### Level 1: 基础向量搜索 (Basic Similarity Search)
- **核心算法**: 近似最近邻搜索 (ANN, 常用 HNSW 算法)。将用户问题转化为向量后,计算它与库中向量的余弦相似度 (Cosine Similarity),取距离最近的 K 个块。
- **优缺点**: 速度极快。但只能捕捉"语义相似",如果用户搜索特定专有名词、编号、订单号,纯向量检索往往会失效(产生"幻觉"匹配)。
- **实现指南**:
- 使用 `model_services.embedding_services` 获取嵌入模型
- 使用 `app.rag.retriever` 中的 `create_base_retriever` 创建基础检索器
- 配置检索返回数量进行初步召回
### Level 2: 混合检索与重排序Hybrid Search + Reranker
混合检索旨在结合向量的"语义泛化"与关键词的"精确匹配",随后利用重排序模型过滤噪声。
**当前状态**
- 混合检索已完全实现,使用 Qdrant 原生双向量存储 + RRF 分数融合
- Qdrant 集合已配置稀疏向量字段,支持 dense + sparse 同步检索
- 重排序器使用 llama.cpp 服务的 OpenAI 兼容 Rerank API
**1. 混合检索(核心)**
- **核心原理**: 结合基于 HNSW 的 Dense Vector 相似度检索与基于 TF-IDF 的 BM25 稀疏检索 (Sparse Vector)
- **实现指南**: 使用 `app.rag.retriever` 中的 `create_hybrid_retriever``create_parent_hybrid_retriever` 函数
- **技术优势**: Qdrant 原生支持,无需客户端后处理,性能更优
**2. 二次精排 (Cross-Encoder)**
- **核心原理**: 不同于双塔模型(分别算向量再求距离),交叉编码器将"用户问题 + 检索到的单例文档"拼接后整体输入 Transformer 模型,由模型直接输出 0~1 的相关性得分,精度极高
- **实现指南**: 使用 `app.rag.rerank` 中的 `LLaMaCPPReranker` 类,设置 `top_n` 保留最相关结果
### Level 3: RAG-Fusion (多路改写与倒数排名融合)
RAG-Fusion 通过大模型发散思维,将单一问题改写为多个相似问题,扩大搜索面,再利用数学统计算法合并结果。
**1. 多路查询改写**
- **核心原理**: 克服用户初始提问词不达意或视角受限的问题
- **实现指南**: 使用 `app.rag.query_transform` 中的 `MultiQueryGenerator` 类,配置 `num_queries` 生成不同角度的查询
**2. 倒数排名融合 (RRF)**
- **核心原理**: RRF (Reciprocal Rank Fusion) 是一种无需评分归一化的融合算法。公式为 `RRF_score(d) = Σ 1/(k + rank_q(d))`,有效避免某一极端检索结果主导全局
- **当前实现**: 使用 Qdrant 原生 FusionQuery 进行服务端 RRF 融合,性能更优
### Level 4: Agentic RAG / Self-RAG (智能体与自我反思)
- **核心原理**: 基于 LangGraph 的 ReAct (Reasoning and Acting) 状态机路由。大模型并非每次都去死板地执行检索,而是先判断问题:"这是闲聊?还是需要查知识库?"。如果是后者,模型输出一个 `ToolCall` 指令,触发检索。
- **实现指南**: 使用 `app/rag/tools.py` 中的 `search_knowledge_base` 工具,将其绑定到 LangGraph 状态机中。
- **示意图**:
```
┌──────────┐ ┌──────────────┐ ┌──────────┐ ┌────────
│ User │────>│ LangGraph │────>│ RAG_Tool │────>│ Qdrant │
│ │ │ Agent │ │ │ │ │
│ "公司报 │ │ 思考: 这是 │ │ ToolCall │ │ RAG- │
│ 销流程?"│ │ 内部规章问题 │ │ search_ │ │ Fusion │
│ │ │ 需要查资料 │ │ knowledge│ │ & 混合 │
│ │<────│ 资料充分, │<────│ 返回最相 │<────│ 检索 │
│ "根据知 │ │ 开始撰写回答 │ │ 关5条规定 │ │ Cross- │
│ 识库规定 │ │ │ │ │ │ Encoder│
│ ..." │ │ │ │ │ │ 重排 │
└────────── └────────────── └──────────┘ └────────┘
```
### Level 5: GraphRAG 集成 (基于图和关系的 RAG)
- **核心原理**: 结合知识图谱的结构化关系和向量检索的语义相似度,解决跨文档复杂关系推理问题
- **实现指南**:
- 使用 `langchain_community.graphs` 模块构建知识图谱
- 配置本地大模型(如 `Gemma-4-E4B`)用于实体关系抽取
- 实现混合检索逻辑,结合向量相似度和图路径分析
## 🔧 核心组件详解
### 1. 检索器 (retriever.py)
提供基于 Qdrant 的向量检索能力。
**基础检索器**
- 功能:纯稠密向量检索
- 配置:集合名称、检索数量
**混合检索器**
- 功能:稠密 + 稀疏向量混合检索Qdrant 原生 RRF 融合
- 配置:集合名称、检索数量、分数阈值(可选)
**父子文档混合检索器**
- 功能:子块检索 → 父块获取,提供完整上下文
- 配置:集合名称、检索数量
### 2. 多路查询改写 (query_transform.py)
通过 LLM 将用户问题改写为多个不同版本,扩大搜索面。
**配置**
- LLM 服务:从 `model_services.chat_services` 获取
- 查询数量:默认 3 个
### 3. RRF 融合算法 (fusion.py)
Reciprocal Rank Fusion 算法,公式:`RRF_score(d) = Σ 1/(k + rank_q(d))`
**当前状态**
- 主要使用 Qdrant 原生 FusionQuery 进行服务端融合
- 本模块为备用实现,用于特殊场景
### 4. 重排序器 (rerank.py)
使用 llama.cpp 服务的 OpenAI 兼容 Rerank API 对检索结果重排序。
**配置**
- 服务地址:从环境变量或配置获取
- API Key从环境变量或配置获取
- Top N返回最相关的 N 个结果
### 5. RAG 流水线 (pipeline.py)
组合上述组件的完整检索流水线。
**主要功能**
- 多路查询改写(可选)
- 混合检索(支持父子文档)
- 重排序(可选)
- 上下文格式化
**配置选项**
- 集合名称
- LLM 服务
- 是否使用多路改写
- 是否使用重排序
- 检索/重排序数量
## 🔄 与 Agent 系统集成
### 封装为 LangChain Tool
- 创建工具函数,用于搜索知识库获取相关信息
- 工具描述要清晰,说明功能和用途
### 绑定到 LangGraph
- 将 RAG 工具添加到 Agent 可用工具列表
- 构建 LangGraph 图时传入工具列表
- 配置检查点(可选)用于状态持久化
## ⚙️ 环境配置
| 变量名 | 说明 | 默认值 |
|:-------|:-----|:-------|
| `QDRANT_URL` | Qdrant 向量数据库地址 | `http://115.190.121.151:6333` |
| `QDRANT_API_KEY` | Qdrant API 密钥 | - |
| `DB_HOST` | PostgreSQL 主机 | `115.190.121.151` |
| `DB_PORT` | PostgreSQL 端口 | `5432` |
| `DB_USER` | PostgreSQL 用户 | `postgres` |
| `DB_PASSWORD` | PostgreSQL 密码 | `postgres` |
| `DB_NAME` | PostgreSQL 数据库 | `rag_db` |
| `LLAMACPP_EMBEDDING_URL` | llama.cpp 嵌入服务地址 | `http://127.0.0.1:18001` |
| `LLAMACPP_RERANK_URL` | llama.cpp 重排序服务地址 | `http://127.0.0.1:18002` |
| `LLAMACPP_CHAT_URL` | llama.cpp 聊天服务地址 | `http://127.0.0.1:18000` |
| `LLAMACPP_API_KEY` | llama.cpp API 密钥 | `huang1998` |
## 🚀 快速开始
**步骤概览**
1. 初始化模型服务:从 `model_services` 获取嵌入、LLM、重排序服务
2. 创建检索器:选择 `create_base_retriever``create_hybrid_retriever``create_parent_hybrid_retriever`
3. 创建 RAG 流水线:配置是否使用多路改写、是否使用重排序等
4. 执行检索:调用 `aretrieve` 进行异步检索
5. 格式化上下文:调用 `format_context` 整理为 LLM 可用格式
## 📊 检索策略对比
| 策略 | 优点 | 缺点 | 适用场景 |
|:-----|:-----|:-----|:---------|
| **基础向量检索** | 速度快,语义理解好 | 专有名词匹配差 | 通用问答 |
| **混合检索** | 语义 + 关键词匹配 | - | 专业术语查询 |
| **父子文档混合检索** | 检索精准 + 上下文完整 | - | 生产环境通用 |
| **多路改写 + RRF** | 搜索面广,结果稳定 | 延迟略高 | 复杂问题 |
| **重排序** | 精度高 | 依赖额外模型 | 最终精排 |
## 🤝 与 rag_indexer 集成
- **向量存储**:共享 Qdrant 集合,确保嵌入模型一致
- **文档存储**:使用 PostgreSQL 存储父块,通过 UUID 映射
- **集合名称**:默认使用 `rag_documents` 集合
- **服务接入**:统一使用 `model_services` 获取模型服务
详见 [rag_indexer/README.md](../../rag_indexer/README.md)