Files
all-in-rag/docs/chapter8/04_generation_sys.md
T
2026-05-12 09:41:56 +08:00

414 lines
15 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.
# 第四节 生成集成与系统整合
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功能,但仍有许多优化空间。未来的优化可以聚焦于几个关键方向的融合与深化:可以通过 **集成图数据库** 将食谱数据构建为知识图谱,来揭示食材、菜品与烹饪方法间的复杂关联,进而支持复杂关系查询(如“和鸡肉搭配的食材有哪些”)、发掘潜在的食材组合并实现基于图的智能推荐。还可以 **融合多模态数据**,结合菜品图片等视觉信息,利用多模态模型进行图文联合检索,不仅能支持“这是什么菜”的视觉搜索,还可以通过图像识别食材来推荐相关菜谱。或者通过 **增强专业知识**,集成营养成分数据库、烹饪技巧知识图谱以及食材替换规则库等外部知识源,系统将能提供精准的营养分析、专业的烹饪指导,并灵活适应用户的饮食过敏或个人偏好。