语义路由:基于用户意图动态选择模型或工具
语义路由:智能分发请求的艺术
什么是语义路由
语义路由是一种根据输入内容的语义含义,动态决定后续处理路径的机制。它不再是简单的关键词匹配或固定规则,而是理解用户“想做什么”,然后将请求导向最合适的模型、工具或服务。
在大语言模型(LLM)和智能代理(Agent)的架构中,语义路由扮演着“总调度”的角色。当用户提出一个问题时,系统首先解析其意图,再决定是调用某个特定模型、查询数据库、执行代码,还是使用外部插件。
核心思想:用意图决定流向,而非用格式或字面内容。
为什么需要语义路由
| 场景 | 无路由时的问题 | 语义路由解决方案 |
|---|---|---|
| 多模型协同 | 所有请求都发给一个通用模型,专业任务效果差 | 将代码生成请求发给代码模型,翻译请求发给翻译模型 |
| 工具调用 | 需手动指定工具,用户体验割裂 | 自动识别“查天气”意图 → 调用天气API |
| 成本与延迟控制 | 简单问题也使用昂贵的大模型 | 简单闲聊由轻量模型处理,复杂推理才用大模型 |
| 安全与权限 | 敏感操作无防护 | 识别“删除数据”意图 → 要求二次确认或拦截 |
语义路由让系统在准确、效率、成本之间找到平衡,同时保持交互的自然与流畅。
路由的基础架构
一个典型的语义路由流程包含三个阶段:
- 意图分类 – 解析用户输入,输出一个意图标签(如
question,code_generate,translate)。 - 路由决策 – 根据意图映射到目标处理器(模型、工具、链)。
- 结果聚合 – 将处理结果返回给用户,必要时进行后处理或组合。
我们用一张简化流程图来表示:
用户输入 → [语义分析模块] → 意图标签 → [路由表] → 目标模型/工具 → 响应
实现语义路由的四种方式
1. 基于LLM的意图分类
直接利用大语言模型自身来输出意图。通过精心设计的提示词,让模型返回结构化的意图分类结果。
示例提示词:
你是一个意图分类器。根据用户输入,从以下类别中选择一个最匹配的:
- general_chat
- code_generation
- math_solving
- translation
仅输出类别名称,不要解释。
用户输入:用Python写一个快速排序
模型输出:code_generation
优点:实现简单,零样本能力强。
缺点:有推理延迟和成本,不够稳定(可能输出多余文字)。
优化:使用小型分类模型蒸馏大模型能力,或采用约束生成(如调用JSON模式)。
2. 向量嵌入 + 相似度路由
将输入文本转化为向量,与预先存储的意图描述向量进行相似度匹配。
步骤:
- 为每个意图准备若干代表性句子(如“翻译这句话” 对应
translation意图)。 - 用嵌入模型将所有句子转为向量,构成意图向量库。
- 新输入进来,同样转为向量,计算与库中向量的余弦相似度,选择最近的意图。
关键代码片段(伪代码):
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
intent_embeddings = load_intent_embeddings() # 预计算的意图向量矩阵
input_embedding = get_embedding(user_query)
similarities = cosine_similarity([input_embedding], intent_embeddings)
best_intent_idx = np.argmax(similarities)
优点:速度快,成本低,适合高频场景。
缺点:需要维护意图例句库,难以处理长尾或复合意图。
3. 规则与关键词协同过滤
对于明确领域,可以先用规则快速过滤,剩余模糊请求再交给模型。
示例:
- 若输入包含
[code]标签或以写一个函数开头 → 直接路由至代码模型。 - 否则交给通用模型进行意图识别。
这种分层路由能显著降低延迟,适合对响应时间要求严苛的生产环境。
4. 工具型路由:函数调用(Function Calling)
许多现代LLM支持原生函数调用能力。语义路由可封装为工具选择:模型判断需要调用哪个外部工具,并以结构化JSON返回工具名及参数。
定义工具集合:
[
{
"name": "weather_tool",
"description": "查询指定城市的实时天气",
"parameters": { "city": "string" }
},
{
"name": "calculator",
"description": "执行数学计算",
"parameters": { "expression": "string" }
}
]
用户输入:“北京今天热吗?” → 模型决策调用 weather_tool(city="北京")。这就是基于语义的工具路由。
设计路由时的关键考量
- 意图粒度:不宜过粗(无法区分专业任务)也不宜过细(维护成本高)。建议从5~10个核心意图开始迭代。
- 容错与兜底:始终保留一个“默认路由”(如通用对话模型),处理未识别意图,避免系统静默失败。
- 上下文连续性:多轮对话中,意图可能随对话进展改变。路由模块需要感知历史,或由上层对话管理器统一分配。
- 性能监控:记录每次路由决策的输入、意图、目标及用户反馈,定期评估准确率,对错误案例进行修复。
动手实践:搭建一个最小语义路由系统
我们将用Python结合openai库和轻量分类器,构建一个支持三种意图的路由器。
准备工作:安装依赖
pip install openai scikit-learn numpy
1. 定义意图和处理器
def general_chat_handler(query):
return f"通用模型回复:关于'{query}'的回复..."
def code_gen_handler(query):
return f"代码模型:已生成{query}的代码..."
def math_handler(query):
return f"数学求解器:{query}的计算结果是..."
2. 构建基于LLM的路由函数
import openai
def classify_intent(query):
prompt = f"""将以下用户问题分类为:general_chat, code_gen, math。
仅输出类别名称,不输出其他内容。
问题:{query}
类别:"""
response = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[{"role": "user", "content": prompt}],
temperature=0,
)
return response.choices[0].message.content.strip()
3. 路由调度
def semantic_router(query):
intent = classify_intent(query)
if intent == "code_gen":
return code_gen_handler(query)
elif intent == "math":
return math_handler(query)
else:
return general_chat_handler(query)
# 测试
print(semantic_router("如何写一个快排?"))
print(semantic_router("1+1等于几"))
扩展建议:实际应用中,可将classify_intent切换为嵌入匹配或本地微调的分类器,以降低延迟和成本。
进阶方向:自学习路由
语义路由可以持续进化。通过记录用户对路由后响应的反馈(点赞、点踩、纠错),我们能构造训练数据来微调路由模型。
- 收集有意向分歧的案例(人工审核或自动检测)。
- 重新标注意图,更新分类模型。
- 逐步引入多维度路由:不仅看意图,还结合用户角色、负载情况、模型健康度等,实现动态权重路由。
语义路由是构建认知型AI系统的基石之一。掌握它,你就能设计出更聪明、更高效、更经济的智能应用。