一、引言:从"一个 Agent"到"一群 Agent"的调度难题
上一篇文章我们聊了多 Agent 系统的记忆架构——让每个智能体"记得住、想得起"。但当系统里真的跑着十几个 Agent 时,一个更基础的问题会首先跳出来:请求进来之后,到底该交给哪个 Agent?
想象一个企业级客服系统:有处理订单的订单 Agent、解答售前的咨询 Agent、处理退款的售后 Agent、专门回复物流问题的物流 Agent,还有兜底的通用 Agent。用户发来一句"我昨天买的键盘想退了",系统怎么知道这该路由给售后 Agent 而不是售前 Agent?如果同时有 500 个用户涌进来,订单 Agent 已经忙不过来了,系统又怎么决定哪些请求先排队、哪些分流给别的 Agent?
这就是多 Agent 系统的任务路由(Task Routing)与负载均衡(Load Balancing)。路由解决的是"派给谁"的正确性问题,负载均衡解决的是"怎么派才不挤"的效率问题。两者结合,才能让一个多 Agent 系统既"接得住"又"接得准"。
本文将从路由的核心概念讲起,依次拆解三种主流路由方案(基于规则、基于语义、混合路由),然后给出负载均衡的四种经典策略,最后用一个基于 DeepSeek + Dify 的完整实战项目,把路由与负载均衡真正落地。
为什么路由是刚需,而不是优化项?
很多开发者第一版多 Agent 系统是"一根筋":所有请求都发给同一个大 Agent,让模型自己判断。这在请求量小、场景单一的时候没问题,但一旦规模化,三个问题立刻暴露:
- 上下文爆炸:每个 Agent 都带全套工具和指令,Prompt 越来越长,推理越来越慢,Token 成本指数上升。
- 职责混乱:同一个 Agent 既要懂订单又要懂物流,工具列表互相干扰,误调用、幻觉率显著升高。
- 单点瓶颈:所有请求挤在一个 Agent 上,一个慢查询拖垮全部体验。
而合理的路由架构,让每个 Agent 只带自己的领域工具和知识,请求按需分发——正确率更高、响应更快、成本更低,还能独立扩缩容。路由不是锦上添花,是多 Agent 系统走向生产环境的必经之路。
二、路由的核心概念:意图、技能与上下文
在设计路由之前,先建立三个基础概念:
意图(Intent):用户请求背后想达成的目标。用户说"我想退了这个键盘",意图是"退货退款",而不是"购买咨询"。意图是路由的第一依据。
技能(Skill):每个 Agent 能做什么的声明。技能通常包括:领域描述、可调用的工具、适合处理的输入类型。比如物流 Agent 的技能声明是"查询订单物流轨迹、预测送达时间、处理地址变更"。
上下文(Context):除了用户这句话之外,系统掌握的其他信息——用户历史、当前会话状态、各 Agent 的实时负载、业务优先级等。好的路由不只是"听懂这句话",而是"结合场景做决策"。
路由的本质,就是把 (意图, 上下文) → 目标 Agent 这个映射做对。映射的精度,决定了系统的服务质量。
三、路由方案一:基于规则的确定性路由
最朴素也最可靠的路由,是规则路由(Rule-based Routing):用关键词、正则、业务字段直接映射到 Agent。
# 规则路由示例:基于关键词的意图匹配
import re
ROUTES = [
{
"agent": "order_agent",
"pattern": re.compile(r"下单|购买|加购|库存|有货|多少钱|价格"),
},
{
"agent": "after_sale_agent",
"pattern": re.compile(r"退款|退货|换货|赔偿|投诉|质量问题"),
},
{
"agent": "logistics_agent",
"pattern": re.compile(r"物流|快递|发货|配送|签收|到哪了|快递单号"),
},
{
"agent": "pre_sale_agent",
"pattern": re.compile(r"推荐|适合|对比|区别|参数|保修期"),
},
]
def rule_route(message: str) -> str:
for route in ROUTES:
if route["pattern"].search(message):
return route["agent"]
return "general_agent" # 兜底
print(rule_route("我昨天买的键盘想退了")) # after_sale_agent
print(rule_route("这个键盘多少钱?")) # order_agent
print(rule_route("帮我查下快递到哪了")) # logistics_agent
优点:零推理成本、毫秒级响应、行为完全可预期、方便单元测试。缺点:无法处理模糊表达和长尾说法——"这个键盘我不想要了"匹配不到任何关键词,会漏到兜底 Agent。
所以规则路由适合两类场景:强约束的业务入口(如工单类型、菜单选项)和作为快速通道的预处理层(先拦截 80% 的典型请求,剩下的交给语义路由)。不要指望纯规则解决一切,它只是地基。
四、路由方案二:基于 LLM 的语义路由
当用户表达千变万化时,就要让大模型来做意图理解。语义路由(Semantic Routing) 的核心思路:把候选 Agent 的技能描述和用户请求一起交给 LLM,让它输出应该路由到的 Agent 编号。
4.1 零样本路由:让模型直接选
from openai import OpenAI
client = OpenAI(base_url="https://api.deepseek.com", api_key="your-key")
AGENT_REGISTRY = {
"order_agent": "处理下单、库存查询、价格咨询、商品购买流程",
"after_sale_agent": "处理退款、退货、换货、赔偿、投诉与售后问题",
"logistics_agent": "查询物流轨迹、配送时间、签收与地址变更",
"pre_sale_agent": "商品推荐、型号对比、参数解读、购买建议",
"general_agent": "其他所有不在上述范围内的通用问题",
}
def semantic_route(message: str, history: list = None) -> str:
registry_text = "\n".join(
f"{aid}: {desc}" for aid, desc in AGENT_REGISTRY.items()
)
resp = client.chat.completions.create(
model="deepseek-chat",
messages=[
{"role": "system", "content": (
"你是任务路由器。根据用户请求,从下面的 Agent 列表中选择最合适的 Agent。"
f"只输出 Agent 名称,不要任何解释。\n\n{registry_text}"
)},
{"role": "user", "content": message},
],
temperature=0,
max_tokens=10,
)
return resp.choices[0].message.content.strip()
print(semantic_route("我昨天买的键盘想退了")) # after_sale_agent
print(semantic_route("这个键盘我不太想要了")) # after_sale_agent(模糊表达也能命中)
关键细节:temperature=0 保证路由结果稳定;max_tokens=10 限制输出防止模型话痨;系统提示词里只放"技能描述"而不放"完整 Prompt",既省 Token 又避免把 Agent 的内部指令泄露给路由层。
4.2 少样本路由:用例子校准边界
零样本在"边界模糊"的请求上容易翻车,比如"这个键盘和那个机械键盘有什么区别"——既像售前对比,又像参数解读。此时可以给路由模型几个经典的"判断题"示例(few-shot),把边界校准清楚:
FEW_SHOT_EXAMPLES = [
("键盘和鼠标哪个适合办公?", "pre_sale_agent"),
("我买错了想换个颜色", "after_sale_agent"),
("能推荐一款 500 以内的机械键盘吗?", "pre_sale_agent"),
("退款多久能到账?", "after_sale_agent"),
]
def semantic_route_fs(message: str) -> str:
messages = [
{"role": "system", "content": "你是任务路由器,根据示例风格选择 Agent,只输出 Agent 名。"},
]
for q, a in FEW_SHOT_EXAMPLES:
messages.append({"role": "user", "content": q})
messages.append({"role": "assistant", "content": a})
messages.append({"role": "user", "content": message})
# ... 调用模型,返回 agent 名
少样本示例的选择有讲究:要选最容易被混淆的边界案例,而不是随便挑几个常见问题。示例越多不一定越好——超过 8 个示例后收益递减,还会拖慢首 Token 延迟。
4.3 语义路由的性能指标
语义路由不是"能跑就行",要量化。三个关键指标:
- 路由准确率(Routing Accuracy):路由到正确 Agent 的比例。用标注好的测试集评估,目标 ≥ 95%。
- 路由延迟(Routing Latency):路由本身消耗的时间。DeepSeek 推理通常 200-500ms,对客服场景可接受,但对高频内部调用要考虑缓存。
- 兜底率(Fallback Rate):被抛给 general_agent 的比例。太高说明路由不自信,太低说明在乱分。
建议上线前用真实历史对话标注 500-1000 条测试集,把这三个指标固化下来,每次调整路由策略都跑一遍回归。
五、路由方案三:混合路由——先规则拦截,再语义精分
纯规则太死板,纯语义太慢太贵。生产环境的最优解往往是混合路由(Hybrid Routing):用规则层做第一道快速过滤,语义层只处理规则层"拿不准"的请求。
def hybrid_route(message: str, history: list = None) -> str:
# 第一层:规则快速通道(0 成本,毫秒级)
rule_result = rule_route(message)
if rule_result != "general_agent":
return rule_result
# 第二层:业务字段强制路由(例如用户正在处理的工单类型)
if history and history.get("active_ticket_type") == "refund":
return "after_sale_agent"
# 第三层:语义路由兜底(只有规则拿不准才调用 LLM)
return semantic_route(message)
# 触发语义路由的请求量通常只占全部请求的 20-30%
这个架构的价值在于成本杠杆:假设每天 10 万请求,规则层命中 70%,只有 3 万个请求需要走 LLM 路由。按每请求 300 Token 计算,一天能省下约 2100 万 Token 的推理开销,同时把平均路由延迟从 300ms 压到 30ms 以内。
混合路由的工程细节
- 规则层要"偏保守":宁可少拦截,不要误拦截。误拦截的代价是用户被送错 Agent,比多花一次 LLM 调用贵得多。
- 语义层要"带兜底":LLM 输出不在注册表内时,必须回退到 general_agent,不能抛异常。
- 日志要可回放:每次路由决策都记录
(输入, 规则命中, 语义输出, 最终路由),便于离线分析路由错误。
六、负载均衡:请求很多时,怎么派才不挤?
路由解决了"派给谁",负载均衡解决"怎么派才不挤"。多 Agent 系统里,每个 Agent 背后可能挂着不同的后端资源(不同的模型实例、不同的知识库、不同的 API 限流配额),负载情况千差万别。经典策略有四种:
6.1 轮询(Round Robin)
请求按顺序轮流分给各个 Agent 实例,简单公平,但不感知实际负载——某个实例卡住了,照样往里塞请求。
import itertools
class RoundRobin:
def __init__(self, agents):
self.pool = itertools.cycle(agents)
def pick(self):
return next(self.pool)
6.2 最少连接(Least Connections)
记录每个 Agent 当前的"在途请求数",永远选最闲的那个。适合处理时长差异大的场景——有的请求 1 秒,有的 30 秒,轮询会导致慢请求堆积。
class LeastConnections:
def __init__(self, agents):
self.inflight = {a: 0 for a in agents}
def pick(self):
agent = min(self.inflight, key=self.inflight.get)
self.inflight[agent] += 1
return agent
def release(self, agent):
self.inflight[agent] -= 1
6.3 加权轮询(Weighted Round Robin)
给不同 Agent 配权重——性能强的、配额多的多分一些。适合异构实例场景:同一个订单 Agent 部署了 3 个实例,权重各不同。实现上可以用"权重计数递减"的经典算法,保证在多次调用中按权重比例均匀分发:
import heapq
class WeightedRoundRobin:
def __init__(self, agents_with_weights):
# agents_with_weights: [(agent_id, weight), ...]
self.items = [(0, i, aid, w) for i, (aid, w) in enumerate(agents_with_weights)]
heapq.heapify(self.items)
self.n = len(self.items)
def pick(self):
# 取出当前"累计权重最大"的 Agent,选择后减去总权重
cur, i, aid, w = heapq.heappop(self.items)
total = sum(x[3] for x in self.items) + w
heapq.heappush(self.items, (cur + total, i, aid, w))
return aid
# 订单 Agent 权重 3(实例多、性能强),售后 2,物流 1
rr = WeightedRoundRobin([("order", 3), ("after_sale", 2), ("logistics", 1)])
# 连续 12 次调用:order 约 6 次、after_sale 约 4 次、logistics 约 2 次
这段代码的核心是"让权重大的 Agent 的累计值增长更快,从而更频繁地成为最大值"——它不依赖随机数,行为可复现,方便压测和单测。注意权重不是越大越好:权重过高会让慢实例收到超出其处理能力的请求,反而拖垮整体延迟。
6.4 基于反馈的自适应均衡(Adaptive)
最先进也最复杂:实时监控每个 Agent 的 P95 延迟、错误率、队列深度,动态调整分发权重。比如物流 Agent 的 P95 延迟飙到 5 秒,就把它的权重从 1 调低到 0.3,让更多请求流向健康实例。
生产建议:不要一上来就上自适应。先从"轮询 + 最少连接"二选一跑起来,用监控数据说话,确认瓶颈确实在负载分配上,再逐步升级策略。
七、实战:基于 DeepSeek + Dify 构建带路由的客服多 Agent 系统
理论讲完,现在落地。我们基于 DeepSeek 推理服务 + Dify 工作流引擎,构建一个完整的客服多 Agent 系统:入口节点负责混合路由,四个领域 Agent 各司其职,外加一个通用兜底。
7.1 总体架构
用户消息
│
▼
┌─────────────────────────────────────┐
│ Dify 入口工作流(路由层) │
│ 1. 规则节点:关键词快速通道 │
│ 2. 语义节点:DeepSeek 意图路由 │
│ 3. 负载节点:检查目标 Agent 负载 │
└──────────────┬──────────────────────┘
│ 路由结果
┌──────────┼──────────┬───────────┐
▼ ▼ ▼ ▼
订单Agent 售后Agent 物流Agent 售前Agent 通用兜底Agent
(Dify App) (Dify App) (Dify App) (Dify App) (Dify App)
在 Dify 中,入口是一个工作流类型应用,四个领域 Agent 是四个独立的 Agent 类型应用,入口通过"HTTP 请求"节点或"代码"节点调用它们(也可以用 Dify 的 Agent 节点直接嵌套)。
7.2 入口路由工作流:核心节点编排
入口工作流按顺序编排四个节点:
- 开始节点:接收
query(用户消息)和session_history(会话历史)。 - 代码节点(规则路由):内置第三节的
rule_route函数,输出rule_result。 - 条件分支节点:若
rule_result != "general_agent",直接走"快速通道"输出;否则进入语义路由。 - LLM 节点(语义路由):调用 DeepSeek,系统提示词是 Agent 注册表描述,输出
semantic_result。 - 代码节点(负载检查 + 兜底):检查目标 Agent 的在途连接数,超过阈值则降级到通用 Agent,或进入排队提示。
- HTTP 请求节点:把
query转发给最终选中的 Agent 应用(Dify 的 Agent 应用都暴露了对话 API)。
7.3 负载检查与降级逻辑(代码节点)
def main(query: str, target_agent: str, inflight: dict) -> dict:
MAX_INFLIGHT = {
"order_agent": 20,
"after_sale_agent": 15,
"logistics_agent": 25,
"pre_sale_agent": 10,
}
if inflight.get(target_agent, 0) >= MAX_INFLIGHT.get(target_agent, 10):
# 目标 Agent 过载:降级到通用 Agent,并附加排队提示
return {
"final_agent": "general_agent",
"notice": "当前该业务线咨询量较大,已为您转接通用客服,预计等待时间较短。",
}
return {"final_agent": target_agent, "notice": ""}
这里用的是最朴素的"阈值 + 降级"策略。想更精细,可以把 inflight 换成滑动窗口统计的 QPS,或者直接读 Dify 应用监控 API 拿实时延迟数据做自适应均衡。
7.4 领域 Agent 的内部配置要点
路由只是"接住请求",接住之后 Agent 自己得"接得住"。每个领域 Agent 注意三点:
- Prompt 只写本领域职责:物流 Agent 的 System Prompt 不要出现"你还可以帮用户退款"这种越界指令,减少误操作。
- 工具按领域挂载:订单 Agent 挂订单查询 API、库存 API;物流 Agent 挂物流轨迹 API。工具越少,幻觉越少。
- 开启记忆但限定范围:用 Dify 的会话记忆功能,但按"本领域会话"隔离,避免跨领域上下文污染。
7.5 完整调用链路示例
入口路由确定 final_agent 后,通过 Dify 的对话 API 调用目标 Agent:
import requests
def call_agent(agent_app_key: str, query: str, user: str, conversation_id: str = ""):
resp = requests.post(
f"https://api.dify.ai/v1/chat-messages",
headers={"Authorization": f"Bearer {agent_app_key}"},
json={
"inputs": {},
"query": query,
"response_mode": "streaming",
"user": user,
"conversation_id": conversation_id,
},
)
return resp
# 路由层示例调用
final = {"final_agent": "after_sale_agent", "notice": ""}
if final["final_agent"] == "after_sale_agent":
call_agent(AGENT_KEYS["after_sale"], "我昨天买的键盘想退了", user_id)
7.6 一个完整的路由决策示例
用户发来:"键盘昨天到的,但是空格键有异响,能换吗?"
| 层级 | 判断 | 结果 |
|---|---|---|
| 规则层 | 命中"换"→ 售后关键词 | 直接路由 after_sale_agent ✅ |
| 负载层 | 售后在途 8/15 | 未过载,正常分发 ✅ |
| 最终 | 售后 Agent 接单 | 处理换货流程 |
再比如:"你觉得我该买青轴还是红轴?"——规则层无命中,语义层识别为"购买建议"→ pre_sale_agent,负载检查通过后分发。两个例子,一条链路,路由与负载均衡协同工作。
八、监控与调优:路由系统上线后怎么持续优化
路由系统上线不是终点,是起点。三个必须盯的观测面:
8.1 路由质量监控
- 错误路由率:用户被路由到 A,但实际是 B 的职责(通过用户转人工/差评/二次转发间接推断)。每周抽样本人工复核。
- 兜底率:持续偏高(>40%)说明语义层置信度不够,需要补充少样本示例或增强技能描述。
- 平均路由延迟:P50/P95 都要看。语义路由延迟异常时,检查是否出现长尾输入(超长消息被原样送入路由)。
8.2 负载均衡监控
- 各 Agent 在途请求数:长期接近阈值上限的 Agent 需要扩容或提权。
- P95 响应延迟:按 Agent 维度拆分,找出慢实例。
- 排队/降级率:降级率过高说明负载均衡策略太粗糙,考虑升级到自适应策略。
8.3 迭代节奏
建议按"周"为单位迭代:每周从生产日志抽 100 条路由决策做人工标注 → 修正规则表 → 补充 few-shot 示例 → 回归路由准确率 → 灰度发布。小步快跑,路由系统会越用越准。
九、总结与下期预告
本文完成了多 Agent 系统"任务调度"的完整拼图:
- 路由三方案:规则路由(快而稳)、语义路由(准而活)、混合路由(生产首选);
- 负载均衡四策略:轮询、最少连接、加权轮询、自适应均衡;
- 落地要点:入口工作流编排、负载阈值降级、领域 Agent 职责收敛、路由质量监控闭环。
一句话记住本文:路由管"方向",负载管"节奏",监控管"体检",三者缺一不可。
回顾开头的场景:500 个用户同时涌进来,混合路由用规则层秒级分流了 70% 的典型请求,语义层在 300ms 内处理剩下的模糊表达,负载层把过载业务线的请求平滑降级到兜底 Agent——没有一单丢失,没有一次明显卡顿。这就是"每个请求都被最合适的智能体接住"的工程含义。
下一期我们聊聊多 Agent 系统的工具权限与安全沙箱——当 Agent 开始调用真实 API、读写真实数据时,怎么保证它"有能力但不越权"。
📚 延伸阅读
如果你对 DeepSeek 的实战用法感兴趣,推荐阅读我的另一篇文章:
👉 DeepSeek 实战指南:提示词工程、API 集成与效率提升全攻略
这篇文章系统地拆解了 DeepSeek 的提示词工程技巧、API 封装方法以及日常效率提升场景,全文代码可直接运行,适合已经上手 DeepSeek 但希望更高效使用的开发者。
Dify 多 Agent 实战系列:
- Dify 多 Agent 记忆架构实战:让智能体"记得住、想得起、用得上"
- Dify 多 Agent 安全边界与权限治理实战:让每一个智能体都"知道边界、守得住门"
- Dify 多 Agent 上下文工程实战:让智能体"记住该记住的,忘掉该忘掉的"
- Dify 多 Agent 故障演练实战:用混沌工程主动"搞破坏",让智能体系统越炸越稳
- Dify 多 Agent 灰度发布实战:让每一次变更都"小步快跑、随时可回滚"
- Dify 多 Agent 评测实战:用 DeepSeek-R1 当裁判,打造多智能体系统的自动化质量保障体系
本文是"华为云Flexus+DeepSeek征文"系列文章之一。该系列基于华为云 Flexus 云服务器与 MaaS 平台 DeepSeek 推理服务,结合 Dify 工作流引擎,从部署、Agent 开发、评测、成本治理、稳定性建设、安全治理、记忆架构到任务路由,系统拆解企业级 AI 应用的工程实践。

336

被折叠的 条评论
为什么被折叠?



