Initial commit
This commit is contained in:
@@ -0,0 +1,414 @@
|
||||
# 第四节 生成集成与系统整合
|
||||
|
||||
Boss要打完喽!在最后一节来学习一下如何实现智能的生成集成模块,以及将所有模块整合成一个完整的RAG系统。
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
%% 生成集成与系统整合流程
|
||||
INPUT[📖 检索结果] --> ROUTE{🎯 查询路由}
|
||||
|
||||
%% 查询路由分支
|
||||
ROUTE -->|list| LIST_QUERY[📋 列表查询]
|
||||
ROUTE -->|detail| DETAIL_QUERY[📖 详细查询]
|
||||
ROUTE -->|general| GENERAL_QUERY[ℹ️ 一般查询]
|
||||
|
||||
%% 查询重写处理
|
||||
LIST_QUERY --> KEEP[📝 保持原查询]
|
||||
DETAIL_QUERY --> KEEP
|
||||
GENERAL_QUERY --> REWRITE[🔄 查询重写]
|
||||
|
||||
%% 父子文档处理
|
||||
KEEP --> PARENT[📚 获取父文档]
|
||||
REWRITE --> PARENT
|
||||
PARENT --> DEDUP[🧠 智能去重排序]
|
||||
|
||||
%% 生成模式路由
|
||||
DEDUP --> GEN_ROUTE{🎨 生成模式路由}
|
||||
GEN_ROUTE -->|list| LIST_GEN[📋 列表生成模式]
|
||||
GEN_ROUTE -->|detail| DETAIL_GEN[📝 分步指导模式]
|
||||
GEN_ROUTE -->|general| BASIC_GEN[💬 基础回答模式]
|
||||
|
||||
%% 最终输出
|
||||
LIST_GEN --> OUTPUT[✨ 返回结果]
|
||||
DETAIL_GEN --> OUTPUT
|
||||
BASIC_GEN --> OUTPUT
|
||||
|
||||
%% 查询路由详细流程
|
||||
subgraph RouteProcess [查询路由过程]
|
||||
R1[🔍 分析查询类型]
|
||||
R2[📊 判断用户意图]
|
||||
R3[🎯 选择处理策略]
|
||||
R1 --> R2 --> R3
|
||||
end
|
||||
|
||||
%% 查询重写详细流程
|
||||
subgraph RewriteProcess [查询重写过程]
|
||||
W1[📝 分析查询模糊度]
|
||||
W2[🔧 优化查询表达]
|
||||
W3[✅ 输出重写结果]
|
||||
W1 --> W2 --> W3
|
||||
end
|
||||
|
||||
%% 生成模式详细流程
|
||||
subgraph GenerationProcess [多模式生成过程]
|
||||
G1[📋 简洁列表输出]
|
||||
G2[📝 结构化详细指导]
|
||||
G3[💬 基础信息回答]
|
||||
G1 --> G2 --> G3
|
||||
end
|
||||
|
||||
%% 系统整合流程
|
||||
subgraph SystemProcess [系统整合过程]
|
||||
SYS1[🔧 模块初始化]
|
||||
SYS2[📚 知识库构建]
|
||||
SYS3[🔄 交互式问答]
|
||||
SYS1 --> SYS2 --> SYS3
|
||||
end
|
||||
|
||||
%% 连接子流程
|
||||
ROUTE -.-> RouteProcess
|
||||
REWRITE -.-> RewriteProcess
|
||||
GEN_ROUTE -.-> GenerationProcess
|
||||
OUTPUT -.-> SystemProcess
|
||||
|
||||
%% 样式定义
|
||||
classDef routing fill:#f3e5f5,stroke:#4a148c,stroke-width:2px
|
||||
classDef rewrite fill:#e8eaf6,stroke:#3f51b5,stroke-width:2px
|
||||
classDef generation fill:#fff3e0,stroke:#e65100,stroke-width:2px
|
||||
classDef system fill:#e3f2fd,stroke:#0277bd,stroke-width:2px
|
||||
classDef subprocess fill:#f1f8e9,stroke:#33691e,stroke-width:2px
|
||||
classDef output fill:#fce4ec,stroke:#880e4f,stroke-width:2px
|
||||
|
||||
%% 应用样式
|
||||
class ROUTE,LIST_QUERY,DETAIL_QUERY,GENERAL_QUERY,GEN_ROUTE routing
|
||||
class KEEP,REWRITE rewrite
|
||||
class LIST_GEN,DETAIL_GEN,BASIC_GEN generation
|
||||
class PARENT,DEDUP system
|
||||
class RouteProcess,RewriteProcess,GenerationProcess,SystemProcess subprocess
|
||||
class INPUT,OUTPUT output
|
||||
```
|
||||
|
||||
## 一、生成集成模块
|
||||
|
||||
生成集成模块是整个RAG系统的"大脑",负责理解用户意图、路由查询类型,并生成高质量的回答。
|
||||
|
||||
> [generation_integration.py完整代码](https://github.com/datawhalechina/all-in-rag/blob/main/code/C8/rag_modules/generation_integration.py)
|
||||
|
||||
### 1.1 设计思路
|
||||
|
||||
**智能查询路由**:根据用户查询自动判断是列表查询、详细查询还是一般查询,选择最适合的生成策略。
|
||||
|
||||
**查询重写优化**:对模糊不清的查询进行智能重写,提升检索效果。比如将"做菜"重写为"简单易做的家常菜谱"。
|
||||
|
||||
**多模式生成**:
|
||||
- **列表模式**:适用于推荐类查询,返回简洁的菜品列表
|
||||
- **详细模式**:适用于制作类查询,提供分步骤的详细指导
|
||||
- **基础模式**:适用于一般性问题,提供常规回答
|
||||
|
||||
> 上面说到的两种主要方法可以回顾 [**查询重构与分发**](https://github.com/datawhalechina/all-in-rag/blob/main/docs/chapter4/14_query_rewriting.md)
|
||||
|
||||
### 1.2 类结构设计
|
||||
|
||||
```python
|
||||
class GenerationIntegrationModule:
|
||||
"""生成集成模块 - 负责LLM集成和回答生成"""
|
||||
|
||||
def __init__(self, model_name: str = "kimi-k2-0711-preview",
|
||||
temperature: float = 0.1, max_tokens: int = 2048):
|
||||
self.model_name = model_name
|
||||
self.temperature = temperature
|
||||
self.max_tokens = max_tokens
|
||||
self.llm = None
|
||||
self.setup_llm()
|
||||
```
|
||||
|
||||
- `temperature`: 生成温度,控制回答的创造性
|
||||
- `max_tokens`: 最大生成长度
|
||||
- `llm`: Moonshot Chat模型实例
|
||||
|
||||
### 1.3 查询路由实现
|
||||
|
||||
```python
|
||||
def query_router(self, query: str) -> str:
|
||||
"""查询路由 - 根据查询类型选择不同的处理方式"""
|
||||
prompt = ChatPromptTemplate.from_template("""
|
||||
根据用户的问题,将其分类为以下三种类型之一:
|
||||
|
||||
1. 'list' - 用户想要获取菜品列表或推荐,只需要菜名
|
||||
例如:推荐几个素菜、有什么川菜、给我3个简单的菜
|
||||
|
||||
2. 'detail' - 用户想要具体的制作方法或详细信息
|
||||
例如:宫保鸡丁怎么做、制作步骤、需要什么食材
|
||||
|
||||
3. 'general' - 其他一般性问题
|
||||
例如:什么是川菜、制作技巧、营养价值
|
||||
|
||||
请只返回分类结果:list、detail 或 general
|
||||
|
||||
用户问题: {query}
|
||||
|
||||
分类结果:""")
|
||||
|
||||
# ... (LCEL链式调用)
|
||||
return result
|
||||
```
|
||||
|
||||
查询路由是整个系统的关键,决定了后续的处理流程。通过LLM自动判断查询意图,比简单的关键词匹配更准确。
|
||||
|
||||
### 1.4 查询重写优化
|
||||
|
||||
```python
|
||||
def query_rewrite(self, query: str) -> str:
|
||||
"""智能查询重写 - 让大模型判断是否需要重写查询"""
|
||||
# 使用LLM分析查询是否需要重写
|
||||
# 具体明确的查询(如"宫保鸡丁怎么做")保持原样
|
||||
# 模糊查询(如"做菜"、"推荐个菜")进行重写优化
|
||||
|
||||
# ... (提示词设计和LCEL链式调用)
|
||||
return response
|
||||
```
|
||||
|
||||
查询重写能够将模糊的用户输入转换为更适合检索的查询,显著提升系统的实用性。重写规则包括:保持原意不变、增加相关烹饪术语、优先推荐简单易做的菜品。
|
||||
|
||||
### 1.5 多模式生成
|
||||
|
||||
**列表模式生成**:
|
||||
```python
|
||||
def generate_list_answer(self, query: str, context_docs: List[Document]) -> str:
|
||||
"""生成列表式回答 - 适用于推荐类查询"""
|
||||
# 提取菜品名称
|
||||
dish_names = []
|
||||
for doc in context_docs:
|
||||
dish_name = doc.metadata.get('dish_name', '未知菜品')
|
||||
if dish_name not in dish_names:
|
||||
dish_names.append(dish_name)
|
||||
|
||||
# 构建简洁的列表回答
|
||||
if len(dish_names) <= 3:
|
||||
return f"为您推荐以下菜品:\n" + "\n".join([f"{i+1}. {name}" for i, name in enumerate(dish_names)])
|
||||
# ... (其他情况处理)
|
||||
```
|
||||
|
||||
**详细模式生成**:
|
||||
```python
|
||||
def generate_step_by_step_answer(self, query: str, context_docs: List[Document]) -> str:
|
||||
"""生成分步骤回答"""
|
||||
# 使用结构化提示词,包含:
|
||||
# - 🥘 菜品介绍
|
||||
# - 🛒 所需食材
|
||||
# - 👨🍳 制作步骤
|
||||
# - 💡 制作技巧
|
||||
|
||||
# ... (提示词设计和LCEL链式调用)
|
||||
return response
|
||||
```
|
||||
|
||||
详细模式使用结构化的提示词设计,让LLM能够生成格式规范、内容丰富的分步骤指导,重点突出实用性和可操作性。
|
||||
|
||||
## 二、系统整合
|
||||
|
||||
主程序负责协调各个模块,实现完整的RAG流程:数据准备 → 索引构建 → 检索优化 → 生成集成。同时提供了索引缓存、交互式问答等实用功能。
|
||||
|
||||
> [main.py完整代码](https://github.com/datawhalechina/all-in-rag/blob/main/code/C8/main.py)
|
||||
|
||||
### 2.1 主系统类设计
|
||||
|
||||
```python
|
||||
class RecipeRAGSystem:
|
||||
"""食谱RAG系统主类"""
|
||||
|
||||
def __init__(self, config: RAGConfig = None):
|
||||
self.config = config or DEFAULT_CONFIG
|
||||
self.data_module = None
|
||||
self.index_module = None
|
||||
self.retrieval_module = None
|
||||
self.generation_module = None
|
||||
|
||||
# 检查数据路径和API密钥
|
||||
if not Path(self.config.data_path).exists():
|
||||
raise FileNotFoundError(f"数据路径不存在: {self.config.data_path}")
|
||||
if not os.getenv("MOONSHOT_API_KEY"):
|
||||
raise ValueError("请设置 MOONSHOT_API_KEY 环境变量")
|
||||
```
|
||||
|
||||
主系统类负责协调所有模块,确保系统的完整性和一致性。
|
||||
|
||||
### 2.2 系统初始化流程
|
||||
|
||||
```python
|
||||
def initialize_system(self):
|
||||
"""初始化所有模块"""
|
||||
# 1. 初始化数据准备模块
|
||||
self.data_module = DataPreparationModule(self.config.data_path)
|
||||
|
||||
# 2. 初始化索引构建模块
|
||||
self.index_module = IndexConstructionModule(
|
||||
model_name=self.config.embedding_model,
|
||||
index_save_path=self.config.index_save_path
|
||||
)
|
||||
|
||||
# 3. 初始化生成集成模块
|
||||
self.generation_module = GenerationIntegrationModule(
|
||||
model_name=self.config.llm_model,
|
||||
temperature=self.config.temperature,
|
||||
max_tokens=self.config.max_tokens
|
||||
)
|
||||
```
|
||||
|
||||
初始化过程按照依赖关系有序进行,保证每个模块都能正确设置。
|
||||
|
||||
### 2.3 知识库构建流程
|
||||
|
||||
```python
|
||||
def build_knowledge_base(self):
|
||||
"""构建知识库"""
|
||||
# 1. 尝试加载已保存的索引
|
||||
vectorstore = self.index_module.load_index()
|
||||
|
||||
if vectorstore is not None:
|
||||
# 加载已有索引,但仍需要文档和分块用于检索模块
|
||||
self.data_module.load_documents()
|
||||
chunks = self.data_module.chunk_documents()
|
||||
else:
|
||||
# 构建新索引的完整流程
|
||||
self.data_module.load_documents()
|
||||
chunks = self.data_module.chunk_documents()
|
||||
vectorstore = self.index_module.build_vector_index(chunks)
|
||||
self.index_module.save_index()
|
||||
|
||||
# 初始化检索优化模块
|
||||
self.retrieval_module = RetrievalOptimizationModule(vectorstore, chunks)
|
||||
```
|
||||
|
||||
这个流程运用了之前设计的索引缓存机制,能够大幅提升系统启动速度。
|
||||
|
||||
### 2.4 智能问答流程
|
||||
|
||||
```python
|
||||
def ask_question(self, question: str, stream: bool = False):
|
||||
"""回答用户问题"""
|
||||
# 1. 查询路由
|
||||
route_type = self.generation_module.query_router(question)
|
||||
|
||||
# 2. 智能查询重写(根据路由类型)
|
||||
if route_type == 'list':
|
||||
rewritten_query = question # 列表查询保持原样
|
||||
else:
|
||||
rewritten_query = self.generation_module.query_rewrite(question)
|
||||
|
||||
# 3. 检索相关子块
|
||||
relevant_chunks = self.retrieval_module.hybrid_search(rewritten_query, top_k=self.config.top_k)
|
||||
|
||||
# 4. 根据路由类型选择回答方式
|
||||
if route_type == 'list':
|
||||
# 列表查询:返回菜品名称列表
|
||||
relevant_docs = self.data_module.get_parent_documents(relevant_chunks)
|
||||
return self.generation_module.generate_list_answer(question, relevant_docs)
|
||||
else:
|
||||
# 详细查询:获取完整文档并生成详细回答
|
||||
relevant_docs = self.data_module.get_parent_documents(relevant_chunks)
|
||||
|
||||
if route_type == "detail":
|
||||
# 详细查询使用分步指导模式
|
||||
return self.generation_module.generate_step_by_step_answer(question, relevant_docs)
|
||||
else:
|
||||
# 一般查询使用基础回答模式
|
||||
return self.generation_module.generate_basic_answer(question, relevant_docs)
|
||||
```
|
||||
|
||||
这部分展示了程序执行流程:智能路由 → 查询优化 → 混合检索 → 父子文档处理 → 多模式生成。
|
||||
|
||||
### 2.5 实际使用示例
|
||||
|
||||
#### 2.5.1 不同查询类型的效果
|
||||
|
||||
**列表查询示例**:
|
||||
```
|
||||
用户问题: "推荐几道简单的素菜"
|
||||
查询类型: list
|
||||
生成结果:
|
||||
为您推荐以下菜品:
|
||||
1. 西红柿炒鸡蛋
|
||||
2. 土豆丝
|
||||
3. 青椒炒豆腐
|
||||
```
|
||||
|
||||
**详细查询示例**:
|
||||
```
|
||||
用户问题: "宫保鸡丁怎么做?"
|
||||
查询类型: detail
|
||||
生成结果:
|
||||
## 🥘 菜品介绍
|
||||
宫保鸡丁是一道经典川菜,口感麻辣鲜香...
|
||||
|
||||
## 🛒 所需食材
|
||||
- 鸡胸肉 300g
|
||||
- 花生米 100g
|
||||
- 干辣椒 10个
|
||||
...
|
||||
|
||||
## 👨🍳 制作步骤
|
||||
1. 鸡肉切丁,用料酒和生抽腌制15分钟
|
||||
2. 热锅下油,爆炒花生米至微黄盛起
|
||||
...
|
||||
```
|
||||
|
||||
#### 2.5.2 交互式问答
|
||||
|
||||
系统提供了完整的命令行交互界面,启动时会显示"尝尝咸淡RAG系统"的欢迎信息:
|
||||
|
||||
```python
|
||||
def run_interactive(self):
|
||||
"""运行交互式问答"""
|
||||
print("=" * 60)
|
||||
print("🍽️ 尝尝咸淡RAG系统 - 交互式问答 🍽️")
|
||||
print("=" * 60)
|
||||
print("💡 解决您的选择困难症,告别'今天吃什么'的世纪难题!")
|
||||
|
||||
# 初始化系统和构建知识库
|
||||
self.initialize_system()
|
||||
self.build_knowledge_base()
|
||||
|
||||
while True:
|
||||
user_input = input("\n您的问题: ").strip()
|
||||
if user_input.lower() in ['退出', 'quit', 'exit']:
|
||||
break
|
||||
|
||||
# 询问是否使用流式输出
|
||||
stream_choice = input("是否使用流式输出? (y/n, 默认y): ").strip().lower()
|
||||
use_stream = stream_choice != 'n'
|
||||
|
||||
if use_stream:
|
||||
# 流式输出,实时显示生成过程
|
||||
for chunk in self.ask_question(user_input, stream=True):
|
||||
print(chunk, end="", flush=True)
|
||||
else:
|
||||
# 普通输出
|
||||
answer = self.ask_question(user_input, stream=False)
|
||||
print(answer)
|
||||
```
|
||||
|
||||
**运行效果示例**:
|
||||
```
|
||||
============================================================
|
||||
🍽️ 尝尝咸淡RAG系统 - 交互式问答 🍽️
|
||||
============================================================
|
||||
💡 解决您的选择困难症,告别'今天吃什么'的世纪难题!
|
||||
|
||||
✅ 成功加载已保存的向量索引!
|
||||
✅ 系统初始化完成!
|
||||
|
||||
您的问题: 推荐几道简单的素菜
|
||||
是否使用流式输出? (y/n, 默认y): y
|
||||
|
||||
为您推荐以下素菜:
|
||||
1. 西红柿炒鸡蛋 - 经典家常菜,简单易做
|
||||
2. 土豆丝 - 爽脆可口,适合新手
|
||||
3. 青椒炒豆腐 - 营养丰富,制作简单
|
||||
```
|
||||
|
||||
流式输出的实现通过LangChain的`chain.stream()`方法,它会返回一个生成器,每次yield一个文本片段。在交互式界面中,通过`print(chunk, end="", flush=True)`实时输出每个片段,`end=""`避免换行,`flush=True`确保立即显示,从而实现逐字逐句的流式效果。
|
||||
|
||||
## 三、优化方向
|
||||
|
||||
虽然当前系统已经具备了完整的RAG功能,但仍有许多优化空间。未来的优化可以聚焦于几个关键方向的融合与深化:可以通过 **集成图数据库** 将食谱数据构建为知识图谱,来揭示食材、菜品与烹饪方法间的复杂关联,进而支持复杂关系查询(如“和鸡肉搭配的食材有哪些”)、发掘潜在的食材组合并实现基于图的智能推荐。还可以 **融合多模态数据**,结合菜品图片等视觉信息,利用多模态模型进行图文联合检索,不仅能支持“这是什么菜”的视觉搜索,还可以通过图像识别食材来推荐相关菜谱。或者通过 **增强专业知识**,集成营养成分数据库、烹饪技巧知识图谱以及食材替换规则库等外部知识源,系统将能提供精准的营养分析、专业的烹饪指导,并灵活适应用户的饮食过敏或个人偏好。
|
||||
Reference in New Issue
Block a user