RAG From Scratch 系列教程-3: Routing
语义路由与逻辑路由
路由(Routing)是高级RAG系统中的关键组件,它能够根据问题类型智能选择不同的处理路径或数据源。本文将详细解析图中展示的两种路由技术,包含工作原理、执行流程和可落地的代码实现。
一、技术概览
1. 逻辑路由(Logical Routing)
通过规则或分类器显式定义路由逻辑,例如:
python
if "医疗" in question:use_medical_db()
elif "法律" in question:use_law_db()2. 语义路由(Semantic Routing)
通过向量相似度隐式选择处理路径:
将问题嵌入为向量
计算与各提示模板的相似度
选择最匹配的路径
二、语义路由详解
原理
利用嵌入(embedding)向量捕捉语义特征,通过向量相似度自动选择处理策略,无需硬编码规则。
工作流程
Prompt #1阶段:生成候选路由选项
嵌入阶段:将问题和选项转换为向量
相似度计算:使用余弦相似度比较向量
Prompt #2阶段:执行选定路径的操作
代码实现
1. 定义路由提示模板
python
from langchain_core.prompts import PromptTemplateroute_templates = {"technical": PromptTemplate.from_template("""你是一个技术专家,请用专业术语回答:
{question}"""),"general": PromptTemplate.from_template("""用通俗易懂的方式解释:
{question}"""),"creative": PromptTemplate.from_template("""用富有创意的形式(如诗歌、故事)回答:
{question}""")
}2. 实现语义路由
python
from langchain_community.embeddings import OpenAIEmbeddings
from sklearn.metrics.pairwise import cosine_similarity
import numpy as npembeddings = OpenAIEmbeddings()def semantic_router(question):# 嵌入问题和模板question_vec = embeddings.embed_query(question)template_vecs = {k: embeddings.embed_query(v.template) for k, v in route_templates.items()}# 计算相似度similarities = {k: cosine_similarity([question_vec], [v])[0][0]for k, v in template_vecs.items()}# 选择最佳路由best_route = max(similarities.items(), key=lambda x: x[1])[0]return route_templates[best_route].format(question=question)# 使用示例
response = semantic_router("解释量子纠缠现象")
print(f"选择的路由类型:{best_route}\n回答:{response}")三、逻辑路由详解
原理
基于预定义规则或分类模型显式选择数据源或处理流程,适合有明确领域划分的场景。
工作流程
问题分类(规则/模型)
根据类别选择数据库
从选定DB检索
生成最终回答
代码实现
1. 定义多数据源
python
from langchain_community.vectorstores import FAISS
from langchain_community.embeddings import HuggingFaceEmbeddings# 初始化不同领域的向量库
tech_embeddings = HuggingFaceEmbeddings(model_name="all-mpnet-base-v2")
medical_embeddings = HuggingFaceEmbeddings(model_name="paraphrase-multilingual-MiniLM-L12-v2")tech_db = FAISS.load_local("tech_index", tech_embeddings)
medical_db = FAISS.load_local("medical_index", medical_embeddings)2. 实现逻辑路由
python
from langchain.chains import LLMChain
from langchain_community.llms import OpenAIclass LogicalRouter:def __init__(self):self.llm = OpenAI()self.classifier_prompt = """判断问题属于哪个领域:
选项:[技术, 医疗, 通用]
问题:{question}
领域:"""def route(self, question):# 领域分类domain = self.llm(self.classifier_prompt.format(question=question))# 选择数据源if "技术" in domain:return tech_db.similarity_search(question)elif "医疗" in domain:return medical_db.similarity_search(question)else:return general_db.similarity_search(question)# 使用示例
router = LogicalRouter()
docs = router.route("Transformer模型的核心创新是什么?")四、技术对比与选型建议
| 对比维度 | 语义路由 (Semantic Routing) | 逻辑路由 (Logical Routing) |
|---|---|---|
| 核心原理 | 基于向量相似度隐式匹配 | 基于预定义规则/分类器显式决策 |
| 实现方式 | 1. 问题嵌入为向量 2. 计算与模板的相似度 3. 选择最匹配路径 | 1. 硬编码规则或训练分类器 2. 条件分支选择数据源 |
| 代码复杂度 | 中(需设计模板和嵌入计算) | 高(需维护分类规则和分支逻辑) |
| 维护成本 | 低(自动适应新问题) | 高(需手动更新规则) |
| 决策透明度 | 低(黑盒相似度计算) | 高(明确的条件分支) |
| 适应能力 | 强(自动处理未见过的提问方式) | 弱(仅能处理预设类别) |
| 响应速度 | 较快(20-100ms) | 极快(<10ms,直接匹配) |
| 典型应用场景 | 开放域问答 多意图混合问题 | 垂直领域问答 结构化业务场景 |
| 与LLM结合度 | 深(依赖嵌入模型) | 浅(可完全独立于LLM) |
| 代码示例核心 | cosine_similarity(query_vec, template_vec) | if "关键词" in question: |
| 最佳实践 | 1. 设置相似度阈值 2. 模板多样化设计 | 1. 规则优先级管理 2. 设置默认分支 |
| 混合方案优势 | 先逻辑路由粗筛,再语义路由精分 | 逻辑路由为主,语义路由处理边缘案例 |
五、进阶组合方案
将两种路由方式结合使用可获得更好效果:
python
def hybrid_router(question):# 先用逻辑路由做粗筛domain = classify_domain(question) # 在领域内使用语义路由if domain == "技术":return semantic_router(question, tech_templates)elif domain == "医疗":return semantic_router(question, medical_templates)六、性能优化技巧
缓存路由结果:对相似问题复用路由决策
分层路由:先粗分类再细粒度路由
动态加载:仅加载当前需要的向量库
混合检索:结合关键词和语义路由
通过合理使用路由技术,RAG系统可实现:
响应速度提升30-50%(减少不必要的检索)
答案准确率提升20-35%(使用最适配的处理路径)
系统扩展性增强(方便新增数据源)
