Agent 路由架构的一次尝试:LangGraph + Swarm Handoff + 小模型 Router
本文系统性地讲解一种高性价比的 Agent 路由架构:使用 LangGraph 的有向图编排流程,
借鉴 OpenAI Swarm 的 Handoff 思想实现 Agent 间的控制权转移,
以小模型作为中央路由器(Router Agent),按需分派任务给不同规模的专业 Agent。
目录
- 一、整体架构概览
- 二、三大核心思想
- [2.1 LangGraph 的图结构编排](#2.1 LangGraph 的图结构编排)
- [2.2 Swarm 的 Handoff 机制](#2.2 Swarm 的 Handoff 机制)
- [2.3 小模型做 Router Agent](#2.3 小模型做 Router Agent)
- 三、完整数据流程
- 四、逐步实现详解
- [4.1 第一步:定义状态结构](#4.1 第一步:定义状态结构)
- [4.2 第二步:定义路由工具(Handoff Tool)](#4.2 第二步:定义路由工具(Handoff Tool))
- [4.3 第三步:实现 Router Agent 节点](#4.3 第三步:实现 Router Agent 节点)
- [4.4 第四步:实现专业 Agent 节点](#4.4 第四步:实现专业 Agent 节点)
- [4.5 第五步:构建图并连接节点](#4.5 第五步:构建图并连接节点)
- [4.6 第六步:运行整个系统](#4.6 第六步:运行整个系统)
- 五、进阶机制
- [5.1 回环路由:Agent 可以退回请求](#5.1 回环路由:Agent 可以退回请求)
- [5.2 多轮对话的上下文保持](#5.2 多轮对话的上下文保持)
- [5.3 并行分派:Send 模式](#5.3 并行分派:Send 模式)
- 六、成本分析
- 七、与其他路由方案的对比
- 八、适用场景与局限性
- 九、总结
一、整体架构概览
┌─────────────────────────────────────────────────────────┐
│ 用户请求入口 │
└─────────────────────┬───────────────────────────────────┘
│
▼
┌───────────────────────────────┐
│ Router Agent(小模型) │
│ glm-4.5-air │
│ │
│ 职责: 分析意图 → 调用 Handoff │
│ → 选择目标 Agent │
└─────────┬─────────────────────┘
│ Function Calling (handoff tool)
│
┌──────────┼──────────┬──────────────┐
│ │ │ │
▼ ▼ ▼ ▼
┌──────────┐ ┌────────┐ ┌────────┐ ┌──────────┐
│Code Agent│ │Search │ │Chat │ │ Clarify │
│(大模型) │ │Agent │ │Agent │ │ Agent │
│GLM-5.1 │ │(中等) │ │(小模型)│ │ (小模型) │
│ │ │ │ │ │ │ 追问意图 │
└─────┬────┘ └───┬────┘ └───┬────┘ └────┬─────┘
│ │ │ │
│ │ │ │
└──────────┴──────────┴─────────────┘
│
▼
┌─────────────┐
│ 合并结果 │
│ 返回给用户 │
└─────────────┘
核心理念: 用最便宜的模型做最频繁的决策(路由),只在真正需要时才调用昂贵的模型。
二、三大核心思想
2.1 LangGraph 的图结构编排
LangGraph 把 Agent 系统建模为一个有向状态图(StateGraph)。
基本概念:
| 概念 | 含义 | 对应代码 |
|---|---|---|
| State | 图中流转的数据 | MessagesState(消息列表) |
| Node | 图中的处理节点 | graph.add_node("name", handler) |
| Edge | 节点之间的连线 | graph.add_edge("A", "B") |
| Conditional Edge | 条件分支 | graph.add_conditional_edges(...) |
| START / END | 起点和终点 | 虚拟节点 |
为什么用图?
- 流程可视化:开发者一眼看懂整个 Agent 系统
- 支持循环:Agent 可以把请求退回 Router(回环)
- 支持并行:一条消息可以同时分派给多个 Agent
- 支持状态追踪:每一步的状态变化都可以被记录和回放
最简图示例:
python
from langgraph.graph import StateGraph, MessagesState, START, END
graph = StateGraph(MessagesState)
# 添加节点
graph.add_node("router", router_node)
graph.add_node("code", code_agent_node)
graph.add_node("chat", chat_agent_node)
# 添加边:START → router → (条件分支) → code/chat → END
graph.add_edge(START, "router")
graph.add_conditional_edges("router", route_decision)
graph.add_edge("code", END)
graph.add_edge("chat", END)
# 编译并运行
app = graph.compile()
2.2 Swarm 的 Handoff 机制
OpenAI 的 Swarm 框架提出了一个简洁的 Agent 间协作模型:
路由 = 一个返回 Agent 的函数调用
核心机制:
python
from swarm import Agent
def transfer_to_code_agent():
"""这就是一个 Handoff --- 把控制权交给 code_agent"""
return code_agent
code_agent = Agent(
name="Code Agent",
instructions="你是一个编程专家...",
)
router_agent = Agent(
name="Router",
instructions="判断用户意图,转交合适的 Agent",
functions=[transfer_to_code_agent], # Handoff 作为工具注册
)
运行流程:
用户:"帮我写一个排序算法"
→ Router Agent 分析意图
→ Router 调用 transfer_to_code_agent() (一次 Function Calling)
→ 返回 code_agent 对象
→ 控制权转移给 code_agent
→ Code Agent 开始处理
→ 最终回复返回给用户
Handoff 的精妙之处:
| 特性 | 说明 |
|---|---|
| 统一抽象 | 路由和普通工具调用用同一套 Function Calling 机制 |
| 可追踪 | 每次 Handoff 都是一条 tool_call 记录,可以审计 |
| 可嵌套 | Agent A → Agent B → Agent C,链式传递 |
| 可回传 | Agent B 处理完可以把结果交回给 Agent A |
2.3 小模型做 Router Agent
为什么路由判断要用小模型?
路由判断的特点:
- 输入短:通常就是一条用户消息
- 输出短:只需要输出一个 Agent 名称 + 简短理由
- 不需要创造力:这是一个分类任务,不是生成任务
- 调用频率最高:每条用户消息都要经过 Router
这意味着: 路由判断恰好是小模型擅长、大模型浪费的任务。
| 模型 | 路由能力 | 单次成本 | 响应延迟 |
|---|---|---|---|
| GLM-5.1 | 过度浪费 | 高 | 慢 |
| GLM-4.7 | 偶尔浪费 | 中 | 中 |
| GLM-4.5-Air | 够用且最优 | 极低(¥0.8/百万) | 极快 |
Router 的 System Prompt 设计原则:
1. 明确角色:你是一个路由调度器,不负责回答问题
2. 列出所有可选 Agent 及其适用场景
3. 要求必须调用 handoff 工具(tool_choice="required")
4. 提供决策边界说明(什么情况选什么 Agent)
三、完整数据流程
以一次完整的用户请求为例,展示数据在系统中流转的全过程:
用户发送:"帮我用 Python 实现一个 LRU 缓存,并解释原理"
═══════════════════════════════════════════════════════════
Step 1: 请求进入 Router Agent
═══════════════════════════════════════════════════════════
Input State:
{
"messages": [
{"role": "user", "content": "帮我用 Python 实现一个 LRU 缓存,并解释原理"}
]
}
═══════════════════════════════════════════════════════════
Step 2: Router Agent (小模型) 进行意图分析
═══════════════════════════════════════════════════════════
发送给小模型的请求:
{
model: "glm-4.5-air",
messages: [
{"role": "system", "content": "你是一个路由调度器..."},
{"role": "user", "content": "帮我用 Python 实现一个 LRU 缓存,并解释原理"}
],
tools: [handoff_tool],
tool_choice: "required"
}
小模型的响应 (Function Calling):
{
"tool_calls": [{
"function": {
"name": "handoff",
"arguments": {
"target_agent": "code",
"reason": "用户需要代码实现和技术解释",
"extra_context": "涉及 Python 数据结构,LRU 缓存算法"
}
}
}]
}
═══════════════════════════════════════════════════════════
Step 3: 解析路由结果,图跳转到 Code Agent
═══════════════════════════════════════════════════════════
LangGraph 的 Command 机制:
→ 解析 target_agent = "code"
→ Command(goto="code", update={路由信息})
State 更新:
{
"messages": [
{"role": "user", "content": "帮我用 Python 实现一个 LRU 缓存,并解释原理"},
{"role": "assistant", "content": null, "tool_calls": [...]},
{"role": "tool", "content": "路由到 code agent: 涉及 Python 数据结构..."}
]
}
═══════════════════════════════════════════════════════════
Step 4: Code Agent (大模型) 处理请求
═══════════════════════════════════════════════════════════
发送给大模型的请求:
{
model: "glm-5.1",
messages: [
{"role": "system", "content": "你是一个资深 Python 开发者..."},
...state["messages"] // 包含完整的上下文
]
}
大模型的响应:
{
"content": "以下是一个基于 OrderedDict 的 LRU 缓存实现:\n\n```python\nfrom collections import OrderedDict\n\nclass LRUCache:\n def __init__(self, capacity: int):\n self.cache = OrderedDict()\n self.capacity = capacity\n ...\n```\n\nLRU (Least Recently Used) 的原理是..."
}
═══════════════════════════════════════════════════════════
Step 5: 结果返回给用户
═══════════════════════════════════════════════════════════
最终 State:
{
"messages": [
{"role": "user", "content": "帮我用 Python 实现一个 LRU 缓存..."},
{"role": "assistant", "tool_calls": [handoff → code]},
{"role": "tool", "content": "路由信息"},
{"role": "assistant", "content": "以下是 LRU 缓存实现...(完整代码和解释)"}
]
}
→ LangGraph 到达 END 节点
→ 最终的 assistant 消息返回给用户
关键观察: 用户完全感知不到 Router 的存在,只看到最终答案。但系统在背后省下了大模型的路由判断成本。
四、逐步实现详解
4.1 第一步:定义状态结构
LangGraph 的图需要一个 State 来在节点之间传递数据。最常用的就是 MessagesState:
python
from langgraph.graph import MessagesState
from typing import Annotated
from typing_extensions import TypedDict
class AgentState(MessagesState):
"""扩展状态:在消息列表之外增加路由元信息"""
current_agent: str # 当前正在处理的 Agent 名称
routing_history: list # 路由历史记录(用于调试和审计)
extra_context: str # Router 传递给目标 Agent 的补充信息
字段说明:
| 字段 | 类型 | 作用 |
|---|---|---|
messages |
list[Message] | 继承自 MessagesState,完整的对话历史 |
current_agent |
str | 记录当前正在执行的 Agent(调试用) |
routing_history |
list | 记录路由轨迹:Router → Code Agent → Router → ... |
extra_context |
str | Router 传递给下游的补充上下文 |
4.2 第二步:定义路由工具(Handoff Tool)
这是整个架构的核心抽象 --- 把"路由决策"建模为一个 Function Calling 工具:
python
# 路由工具的 JSON Schema 定义
HANDOFF_TOOL = {
"type": "function",
"function": {
"name": "handoff",
"description": "将用户请求转交给最合适的专业 Agent 处理",
"parameters": {
"type": "object",
"properties": {
"target_agent": {
"type": "string",
"enum": ["code", "search", "chat", "clarify"],
"description": "目标 Agent 名称"
},
"confidence": {
"type": "number",
"description": "你对这次路由判断的信心 (0.0-1.0)"
},
"reason": {
"type": "string",
"description": "路由决策的理由"
},
"extra_context": {
"type": "string",
"description": "传递给目标 Agent 的补充上下文或重写后的问题"
}
},
"required": ["target_agent", "confidence", "reason"]
}
}
}
# Agent 名称到中文名称的映射(用于日志)
AGENT_DISPLAY_NAMES = {
"code": "编程专家",
"search": "信息搜索员",
"chat": "通用助手",
"clarify": "意图澄清员",
}
设计要点:
enum约束确保小模型只能输出预定义的 Agent 名称,不会"发明"新路由confidence字段用于后续可能的回环判断extra_context允许 Router 在必要时重写用户问题,让下游 Agent 更容易理解
4.3 第三步:实现 Router Agent 节点
这是小模型发挥作用的节点:
python
import json
from langgraph.types import Command
ROUTER_SYSTEM_PROMPT = """你是一个高效的路由调度器。你的唯一职责是分析用户意图,然后将请求转交给最合适的专业 Agent。
## 可选 Agent
- **code**: 编程、调试、代码生成、代码审查、技术架构设计、算法问题
- **search**: 需要联网搜索最新信息、新闻查询、实时数据
- **chat**: 日常闲聊、简单问答、概念解释、翻译、写作(非代码)
- **clarify**: 用户意图不明确、问题过于模糊、缺少关键信息
## 路由指南
1. 编程相关 → code(即使只是问概念,只要是技术话题就走这里)
2. 需要实时信息 → search("最新的"、"今天的"、"2025年的")
3. 闲聊 / 简单问答 → chat
4. 看不懂用户想问什么 → clarify
5. 如果一个请求涉及多个方面,选择最核心的那个
## 重要
- 你 **绝对不要** 尝试直接回答用户的问题
- 你 **必须** 调用 handoff 工具
- 在 extra_context 中,可以补充你认为对目标 Agent 有用的信息
"""
def router_node(state: AgentState) -> Command:
"""Router Agent:用小模型做路由判断"""
# 调用小模型
response = small_model_client.chat.completions.create(
model="glm-4.5-air",
messages=[
{"role": "system", "content": ROUTER_SYSTEM_PROMPT},
*state["messages"]
],
tools=[HANDOFF_TOOL],
tool_choice="required", # 强制调用 handoff,不允许自由回复
temperature=0.0, # 路由判断不需要随机性
)
# 解析 Function Calling 结果
tool_call = response.choices[0].message.tool_calls[0]
args = json.loads(tool_call.function.arguments)
target = args["target_agent"]
confidence = args.get("confidence", 1.0)
reason = args.get("reason", "")
extra_context = args.get("extra_context", "")
# 记录路由历史(调试和审计用)
routing_entry = {
"from": "router",
"to": target,
"reason": reason,
"confidence": confidence,
}
# 构造 LangGraph 的 Command:跳转到目标节点 + 更新状态
return Command(
goto=target,
update={
"current_agent": target,
"extra_context": extra_context,
"routing_history": state.get("routing_history", []) + [routing_entry],
"messages": [
{
"role": "assistant",
"content": None,
"tool_calls": [tool_call],
},
{
"role": "tool",
"content": f"已路由到 {AGENT_DISPLAY_NAMES.get(target, target)}: {reason}",
"tool_call_id": tool_call.id,
},
],
},
)
Command 是 LangGraph 的路由原语:
python
Command(
goto="code", # 下一个要执行的节点名称
update={...} # 要合并到 State 中的数据
)
这等价于在图中动态选择了一条边,同时携带了额外的状态更新。
4.4 第四步:实现专业 Agent 节点
每个专业 Agent 就是一个普通的 LLM 调用节点:
python
# ─────────────────────────────────────
# Code Agent:处理编程任务(使用大模型)
# ─────────────────────────────────────
CODE_AGENT_PROMPT = """你是一个资深的全栈开发工程师。你需要:
1. 仔细理解用户的编程需求
2. 给出高质量的代码实现
3. 附带清晰的解释说明
"""
def code_agent_node(state: AgentState):
"""Code Agent:大模型处理复杂编程任务"""
# 如果 Router 提供了补充上下文,注入到 system prompt 中
system_msg = CODE_AGENT_PROMPT
if state.get("extra_context"):
system_msg += f"\n\n[路由补充信息]: {state['extra_context']}"
response = large_model_client.chat.completions.create(
model="glm-5.1", # 大模型,能力强
messages=[
{"role": "system", "content": system_msg},
*state["messages"]
],
)
return {
"messages": [response.choices[0].message],
"current_agent": "code",
}
# ─────────────────────────────────────
# Chat Agent:处理简单对话(使用小模型)
# ─────────────────────────────────────
CHAT_AGENT_PROMPT = """你是一个友好、耐心的助手。用简洁易懂的语言回答用户的问题。"""
def chat_agent_node(state: AgentState):
"""Chat Agent:小模型处理简单对话"""
response = small_model_client.chat.completions.create(
model="glm-4.5-air", # 小模型,够用
messages=[
{"role": "system", "content": CHAT_AGENT_PROMPT},
*state["messages"]
],
)
return {
"messages": [response.choices[0].message],
"current_agent": "chat",
}
# ─────────────────────────────────────
# Search Agent:处理搜索任务(中等模型 + 搜索工具)
# ─────────────────────────────────────
SEARCH_AGENT_PROMPT = """你是一个信息搜索专家。你需要:
1. 分析用户需要搜索什么信息
2. 使用搜索工具获取最新数据
3. 整理搜索结果并给出清晰的回答
"""
def search_agent_node(state: AgentState):
"""Search Agent:中等模型 + 搜索工具"""
response = medium_model_client.chat.completions.create(
model="glm-4.7", # 中等模型
messages=[
{"role": "system", "content": SEARCH_AGENT_PROMPT},
*state["messages"]
],
tools=[SEARCH_TOOL], # 搜索工具
)
# 处理可能的搜索工具调用(省略具体实现)
# ... 执行搜索 → 将结果喂回模型 → 生成最终回答
return {
"messages": [final_message],
"current_agent": "search",
}
# ─────────────────────────────────────
# Clarify Agent:处理模糊意图(使用小模型)
# ─────────────────────────────────────
CLARIFY_AGENT_PROMPT = """用户的意图不够明确。请:
1. 礼貌地向用户说明你需要更多信息
2. 提出具体的追问(2-3个选项)
3. 帮助用户把模糊的问题具体化
"""
def clarify_agent_node(state: AgentState):
"""Clarify Agent:小模型追问用户意图"""
response = small_model_client.chat.completions.create(
model="glm-4.5-air",
messages=[
{"role": "system", "content": CLARIFY_AGENT_PROMPT},
*state["messages"]
],
)
return {
"messages": [response.choices[0].message],
"current_agent": "clarify",
}
4.5 第五步:构建图并连接节点
把所有节点组装成一个完整的有向图:
python
from langgraph.graph import StateGraph, START, END
# 创建图
graph = StateGraph(AgentState)
# ── 注册节点 ──
graph.add_node("router", router_node)
graph.add_node("code", code_agent_node)
graph.add_node("search", search_agent_node)
graph.add_node("chat", chat_agent_node)
graph.add_node("clarify", clarify_agent_node)
# ── 连接边 ──
# 入口:START → router(所有请求先经过路由)
graph.add_edge(START, "router")
# 注意:router 节点不使用 add_conditional_edges
# 因为 router_node 返回的是 Command,Command 本身就包含了 goto 目标
# LangGraph 会自动根据 Command.goto 进行跳转
# 出口:所有专业 Agent 处理完毕后 → END
graph.add_edge("code", END)
graph.add_edge("search", END)
graph.add_edge("chat", END)
graph.add_edge("clarify", END)
# ── 编译图 ──
app = graph.compile()
为什么 router 不需要 add_conditional_edges?
因为 router_node 返回的是 Command(goto=target)。LangGraph 识别到 Command 返回值后,会自动使用 goto 指定的目标节点。这比 add_conditional_edges 更灵活,因为目标是在运行时由小模型动态决定的。
编译后的图结构:
START ──→ router ─┬──→ code ────→ END
├──→ search ──→ END
├──→ chat ────→ END
└──→ clarify ─→ END
4.6 第六步:运行整个系统
python
# ── 初始化客户端 ──
from openai import OpenAI
# 智谱 GLM 系列统一使用 OpenAI 兼容接口
BASE_URL = "https://open.bigmodel.cn/api/paas/v4/"
small_model_client = OpenAI(
base_url=BASE_URL,
api_key="your-zhipu-api-key"
)
large_model_client = OpenAI(
base_url=BASE_URL,
api_key="your-zhipu-api-key"
)
medium_model_client = OpenAI(
base_url=BASE_URL,
api_key="your-zhipu-api-key"
)
# ── 运行 ──
result = app.invoke({
"messages": [
{"role": "user", "content": "帮我用 Python 写一个快排算法"}
]
})
# 最终回复就是最后一条 assistant 消息
final_message = result["messages"][-1]
print(final_message.content)
流式输出(推荐用于实际产品):
python
# 流式处理,实时输出
for event in app.stream(
{"messages": [{"role": "user", "content": "帮我写一个快排"}]},
stream_mode="values"
):
if event["messages"] and event["messages"][-1].content:
print(event["messages"][-1].content, end="", flush=True)
五、进阶机制
5.1 回环路由:Agent 可以退回请求
有时候 Router 判断失误,专业 Agent 发现自己处理不了,可以把请求退回给 Router:
python
from langgraph.types import Command
def code_agent_node(state: AgentState):
"""Code Agent:增加回环能力"""
# 让大模型先判断能不能处理
check_response = large_model_client.chat.completions.create(
model="glm-5.1",
messages=[
{
"role": "system",
"content": "判断这个请求是否属于编程范畴。如果是,回复 YES;如果不确定或不是,回复 NO 并说明理由。"
},
*state["messages"]
],
)
if "NO" in check_response.choices[0].message.content:
# 处理不了,退回给 Router
return Command(
goto="router",
update={
"messages": [{
"role": "assistant",
"content": f"[Code Agent 退回]: {check_response.choices[0].message.content},请重新路由。"
}],
"routing_history": state.get("routing_history", []) + [{
"from": "code",
"to": "router",
"reason": "无法处理,退回重路由",
}],
},
)
# 正常处理
response = large_model_client.chat.completions.create(
model="glm-5.1",
messages=[
{"role": "system", "content": CODE_AGENT_PROMPT},
*state["messages"]
],
)
return {
"messages": [response.choices[0].message],
}
回环的图结构变化:
START ──→ router ─┬──→ code ────┬──→ END
│ │
│ └──→ router (回环)
├──→ search ──→ END
├──→ chat ────→ END
└──→ clarify ─→ END
防无限循环: 增加最大路由次数限制。
python
MAX_ROUTING_ROUNDS = 3
def router_node(state: AgentState) -> Command:
routing_count = len(state.get("routing_history", []))
if routing_count >= MAX_ROUTING_ROUNDS:
# 超过最大路由次数,强制走 chat Agent 兜底
return Command(
goto="chat",
update={
"messages": [{
"role": "system",
"content": "多次路由未命中,请尽力回答用户的问题。"
}],
},
)
# ... 正常路由逻辑 ...
5.2 多轮对话的上下文保持
在多轮对话场景中,Router 需要参考完整的对话历史,而不只是最新一条消息:
python
def router_node(state: AgentState) -> Command:
# 构建带上下文的消息列表
messages_for_router = [
{"role": "system", "content": ROUTER_SYSTEM_PROMPT},
]
# 注入路由历史作为上下文
if state.get("routing_history"):
history_summary = "之前的路由记录:\n"
for h in state["routing_history"]:
history_summary += f" - {h['from']} → {h['to']}: {h.get('reason', '')}\n"
messages_for_router.append({
"role": "system",
"content": history_summary,
})
# 加入完整对话历史
messages_for_router.extend(state["messages"])
response = small_model_client.chat.completions.create(
model="glm-4.5-air",
messages=messages_for_router,
tools=[HANDOFF_TOOL],
tool_choice="required",
)
# ... 后续解析逻辑 ...
为什么多轮对话要特殊处理?
用户: "帮我写一个快排" → Router → Code Agent
用户: "能优化一下吗" → Router 需要知道上一轮是 Code Agent
用户: "顺便解释一下时间复杂度" → Router 需要知道在讨论什么代码
5.3 并行分派:Send 模式
当一个请求需要多个 Agent 同时处理时,可以使用 LangGraph 的 Send:
python
from langgraph.types import Send
def router_node(state: AgentState) -> Command | list[Send]:
user_msg = state["messages"][-1].content
# 场景:用户问了一个综合性问题
if "对比" in user_msg and "解释" in user_msg:
# 分拆为多个子任务,并行处理
return [
Send("code", {"messages": state["messages"], "task": "给出代码实现"}),
Send("chat", {"messages": state["messages"], "task": "给出概念解释"}),
]
# 普通路由
# ... 单 Agent 路由逻辑 ...
并行分派的数据流:
用户: "实现 LRU 缓存并解释原理"
│
▼
router
┌─┴─┐
│ │
▼ ▼
code chat ← 两个 Agent 并行处理
│ │
└─┬─┘
▼
合并结果
▼
END
六、成本分析
假设日处理 10,000 条用户请求,分布如下:
| 请求类型 | 占比 | 数量 | 路由模型 | 处理模型 |
|---|---|---|---|---|
| 编程相关 | 20% | 2,000 | glm-4.5-air | glm-5.1 |
| 信息搜索 | 10% | 1,000 | glm-4.5-air | glm-4.7 + 搜索 |
| 日常闲聊 | 60% | 6,000 | glm-4.5-air | glm-4.5-air |
| 意图不明 | 10% | 1,000 | glm-4.5-air | glm-4.5-air |
Token 用量估算(每条请求):
智谱 GLM 系列定价参考(以官网实时价格为准,取输入长度 <32K 档位):
- GLM-4.5-Air:¥0.8 / ¥2(每百万输入/输出 Token,短输出)
- GLM-4.7:¥2 / ¥8(每百万输入/输出 Token,短输出)
- GLM-5.1:¥6 / ¥24(每百万输入/输出 Token)
| 环节 | 平均 Token | 模型 | 单价(每百万 Token) | 小计 |
|---|---|---|---|---|
| 路由判断 × 10,000 | 输入 300 / 输出 100 | glm-4.5-air | ¥0.8 / ¥2 | ¥4.4 |
| 编程处理 × 2,000 | 输入 1,500 / 输出 1,500 | glm-5.1 | ¥6 / ¥24 | ¥90 |
| 搜索处理 × 1,000 | 输入 1,000 / 输出 500 | glm-4.7 | ¥2 / ¥8 | ¥6 |
| 闲聊处理 × 6,000 | 输入 500 / 输出 300 | glm-4.5-air | ¥0.8 / ¥2 | ¥6 |
| 澄清追问 × 1,000 | 输入 400 / 输出 200 | glm-4.5-air | ¥0.8 / ¥2 | ¥0.72 |
路由方案日成本合计:约 ¥107
对比方案:全部用 GLM-5.1:
| 环节 | Token | 模型 | 费用 |
|---|---|---|---|
| 全部请求 × 10,000 | 输入 1,000 / 输出 800 | glm-5.1 | ¥252 |
节省: 约 ¥145 / 天 ≈ ¥4,350 / 月(约 58% 成本下降)
其中 GLM-4.5-Air 以极低成本处理了 80% 的请求,是大头节省来源。
七、与其他路由方案的对比
| 方案 | 路由延迟 | 路由成本 | 灵活性 | 适用规模 |
|---|---|---|---|---|
| 本文方案(小模型 + Command) | ~300ms | 极低 | 高(Prompt 可调) | 中大型 |
| Semantic Router(向量匹配) | ~50ms | 零 Token | 中(需训练语料) | 高并发 |
| 硬编码规则(if-else) | <1ms | 零 | 低(维护成本高) | 简单场景 |
| 全量大模型路由 | ~2s | 高 | 最高 | 无需优化时(如全用 GLM-5.1) |
| 混合方案:向量 + 小模型 | ~80ms | 极低 | 高 | 生产推荐 |
生产推荐: 先用 Semantic Router 做快速匹配(80% 的请求),匹配失败的 fallback 到小模型路由(20% 的边界 case),这样兼顾速度和灵活性。
八、适用场景与局限性
适用场景
- 多领域 Agent 系统:客服、技术支持、编程助手、学习工具等需要多个专业 Agent 的场景
- 成本敏感的生产环境:日调用量大,需要精确控制模型调用成本
- 需要可观测性的系统:路由历史记录可用于分析用户意图分布、优化路由策略
- 快速迭代的 MVP:只需修改 Router 的 Prompt 就能调整路由策略,无需改代码
局限性
- 增加系统复杂度:多了一层 Router,调试链路更长
- 路由错误会级联放大:Router 判断失误会导致用户得到错误的 Agent 回复
- 小模型的路由精度有限:对于模糊边界的问题,小模型可能不如大模型判断准确
- 延迟叠加:每个请求多了 ~300ms 的路由判断时间
何时不用这套方案
- 只有一个 Agent,不需要路由
- 请求量极小(<100/天),成本不是问题
- 对延迟极其敏感(不能接受额外的路由判断时间)
九、总结
本文介绍的路由架构可以用一句话概括:
用 LangGraph 的 Command 做路由跳转,用 Swarm 的 Handoff 思想把路由建模为 Function Calling,用小模型做路由判断,大模型做复杂任务处理。
核心收益:
- 成本可控:80% 的简单请求不触碰大模型
- 架构清晰:图结构让整个 Agent 系统一目了然
- 可追踪:每次路由都有 tool_call 记录,可审计可调试
- 可扩展:新增 Agent 只需添加节点和更新 Router 的 Prompt
- 灵活路由:支持回环、并行、上下文感知等进阶模式