Agent 路由架构的一次尝试:LangGraph + Swarm Handoff + 小模型 Router

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,用小模型做路由判断,大模型做复杂任务处理。

核心收益:

  1. 成本可控:80% 的简单请求不触碰大模型
  2. 架构清晰:图结构让整个 Agent 系统一目了然
  3. 可追踪:每次路由都有 tool_call 记录,可审计可调试
  4. 可扩展:新增 Agent 只需添加节点和更新 Router 的 Prompt
  5. 灵活路由:支持回环、并行、上下文感知等进阶模式
相关推荐
luyu007_0077 小时前
鲁渝能源全功率无线充电为巡检机器人筑牢能源底座
人工智能·安全·机器人·能源
学困昇7 小时前
Linux 动静态库制作与原理:从 .a、.so 到 ELF 加载一次讲透
linux·运维·服务器·c语言·开发语言·c++·人工智能
一切皆是因缘际会7 小时前
从概率拟合到内生心智:七层投影架构重构AGI数字生命新范式
大数据·数据结构·人工智能·重构·架构·agi
Jump 不二7 小时前
AI Agent Skill 系统架构全解析:SKILL 规范与框架实现
人工智能·语言模型·系统架构
元宵大师7 小时前
[题材&选股] 5.21长鑫产业链集体退潮,电力、面板接棒主升浪!QTYX-V3.4.8量化复盘
人工智能
SunnyDays10117 小时前
Java 实现插入和删除 Excel 行和列
java·python·excel
梦想的颜色7 小时前
LangGraph实战指南:从零到一构建生产级多智能体系统
人工智能·claude code
kels88997 小时前
加密货币实时api的订单簿快照多久更新一次?
开发语言·笔记·python·金融·区块链
落日屿星辰7 小时前
PyTorch 模型迁移到昇腾NPU 完整指南
人工智能·pytorch·python