Agent Harness系列(五):模型路由层设计——怎么让每个任务自动跑在最合适的模型上
系列收官篇。前四篇拆了会话控制、上下文管理、记忆、工具执行。但还有一层没有显式画在架构图里,却横跨所有层——模型路由。用一个模型跑所有任务,要么太贵(全用旗舰),要么质量不够(全用便宜的)。这篇讲怎么在 Harness 里设计智能路由,让每个任务自动跑在最合适的模型上。
为什么需要模型路由
一个跑了一个月的 Agent,日均处理 180 条消息,任务类型分布大致是这样的:
| 任务类型 | 占比 | 需要的模型能力 |
|---|---|---|
| 简单问答(天气、翻译、算术) | 35% | 基础 |
| 文本处理(摘要、改写) | 20% | 中等 |
| 单步工具调用 | 18% | 中等 |
| 多步工具链 | 12% | 高 |
| 代码生成/审查 | 10% | 高 |
| 复杂推理 | 5% | 最高 |
如果全用旗舰模型(如 Opus 4.7,$5/$25 MTok):
月成本 ≈ 180条 × 30天 × ~3000 token/条 × $15/MTok输出 ≈ $243/月
如果 73% 的简单任务(问答+文本+单步工具)用便宜模型($0.27 MTok),复杂任务才用旗舰:
简单任务: 131条 × 30天 × ~2000 token × $0.41/MTok ≈ $3.2/月
复杂任务: 49条 × 30天 × ~4000 token × $25/MTok ≈ $147/月
混合月成本 ≈ $150/月(省了 38%)
同样的消息量,路由后省 38% 成本,而且简单任务的响应速度反而更快(小模型推理更快)。
路由架构的 3 种设计模式
模式 1:基于规则的静态路由
最简单的方案。根据预设规则把任务分流到不同模型。
def route_by_rules(message: str, tools_needed: int) -> str:
"""基于规则的静态路由"""
# 规则1:多步工具调用 → 旗舰模型
if tools_needed >= 3:
return "anthropic/claude-opus-4-7"
# 规则2:代码相关 → 中高端模型
code_signals = ["代码", "函数", "bug", "报错", "review", "重构", "测试"]
if any(s in message for s in code_signals):
return "anthropic/claude-sonnet-4-6"
# 规则3:需要推理 → 中高端模型
reasoning_signals = ["分析", "为什么", "比较", "优缺点", "方案", "设计", "架构"]
if any(s in message for s in reasoning_signals):
return "anthropic/claude-sonnet-4-6"
# 规则4:其他 → 便宜模型
return "deepseek/deepseek-v3"
| 优点 | 缺点 |
|---|---|
| 零延迟(纯字符串匹配) | 关键词匹配不够精准 |
| 实现简单 | 边界 case 处理不了 |
| 行为可预测 | 规则维护成本随模型增多线性增长 |
适用场景:任务类型明确可分(比如"代码类"和"非代码类"),模型选择不超过 3 个。
模式 2:基于 LLM 的动态路由
用一个轻量模型先判断任务复杂度,再路由到对应模型。
ROUTER_PROMPT = """你是一个任务分类器。根据用户消息判断任务复杂度,返回 JSON。
分类标准:
- simple: 简单问答、翻译、格式转换、单步查询
- medium: 多步操作、文本分析、单文件代码修改
- complex: 架构设计、多文件重构、复杂推理、长链工具调用
只返回 JSON: {"complexity": "simple|medium|complex"}"""
async def route_by_llm(message: str) -> str:
"""用轻量模型做路由决策"""
response = await client.chat.completions.create(
model="qwen/qwen3.5-9b", # 用最便宜的模型做路由
messages=[
{"role": "system", "content": ROUTER_PROMPT},
{"role": "user", "content": message}
],
max_tokens=50,
response_format={"type": "json_object"}
)
result = json.loads(response.choices[0].message.content)
model_map = {
"simple": "deepseek/deepseek-v3", # $0.27/MTok
"medium": "anthropic/claude-sonnet-4-6", # $3/MTok
"complex": "anthropic/claude-opus-4-7", # $5/MTok
}
return model_map.get(result["complexity"], "anthropic/claude-sonnet-4-6")
| 优点 | 缺点 |
|---|---|
| 语义理解,比关键词精准 | 多一次模型调用(+200-500ms 延迟) |
| 不需要维护规则 | 路由模型本身也会犯错 |
| 能处理模糊任务 | 路由调用也有成本(虽然很低) |
路由调用的成本:用 Qwen 3.5 9B 做路由,每次调用约 100 token 输入 + 20 token 输出 ≈ $0.000016。每天 180 条消息的路由成本约 $0.003——可以忽略。
适用场景:任务类型多样、边界模糊,静态规则覆盖不了。
模式 3:级联路由(Cascade)
先用便宜模型跑,如果结果质量不够再升级到更强的模型。
async def route_cascade(message: str, tools: list) -> tuple:
"""级联路由:先便宜后贵"""
models = [
("deepseek/deepseek-v3", 0.85), # 便宜,置信度阈值 0.85
("anthropic/claude-sonnet-4-6", 0.70), # 中等,置信度阈值 0.70
("anthropic/claude-opus-4-7", 0.0), # 最贵,兜底
]
for model, threshold in models:
response = await client.chat.completions.create(
model=model,
messages=[{"role": "user", "content": message}],
tools=tools,
)
result = response.choices[0]
# 简单的质量判断(生产中可以更复杂)
confidence = estimate_confidence(result)
if confidence >= threshold:
return result, model # 质量够了,不升级
return result, models[-1][0] # 兜底
def estimate_confidence(result) -> float:
"""估算回答质量(简化版)"""
content = result.message.content or ""
# 低置信度信号
if "我不确定" in content or "可能" in content:
return 0.5
if len(content) < 20: # 回答太短
return 0.6
if result.finish_reason == "length": # 被截断
return 0.4
return 0.9 # 默认高置信度
| 优点 | 缺点 |
|---|---|
| 简单任务真的只花便宜模型的钱 | 失败时延迟翻倍(要跑两次) |
| 自动适配任务难度 | 质量判断逻辑需要调优 |
| 不需要预分类 | 实现最复杂 |
适用场景:成本敏感、能容忍偶尔的额外延迟。适合异步/后台 Agent(不需要实时响应)。
3 种模式的决策矩阵
| 维度 | 静态规则 | LLM 动态 | 级联 |
|---|---|---|---|
| 路由延迟 | 0ms | 200-500ms | 0ms(成功)/翻倍(升级) |
| 路由精度 | 60-70% | 85-90% | 80-85% |
| 实现复杂度 | ⭐ | ⭐⭐ | ⭐⭐⭐⭐ |
| 成本节省 | 20-30% | 30-45% | 35-50% |
| 适合场景 | 任务类型清晰 | 通用 | 后台/异步 |
我的推荐:从静态规则开始,不够了升 LLM 动态路由。 级联路由只在特定场景值得(后台批量任务、成本极度敏感)。
降级链设计:路由之外的可靠性保障
路由解决"选哪个模型"。降级链解决"选好的模型挂了怎么办"。
class ModelRouter:
def __init__(self):
self.breakers = {} # 每个模型一个熔断器
async def call(self, message: str, tools: list) -> tuple:
"""路由 + 降级"""
primary = self.route(message, tools)
fallback_chain = self.get_fallback_chain(primary)
for model in fallback_chain:
breaker = self.breakers.setdefault(model, CircuitBreaker())
try:
result = await breaker.call(
lambda: client.chat.completions.create(
model=model, messages=[...], tools=tools
)
)
return result, model
except Exception as e:
print(f"{model} 失败: {e}")
continue
raise Exception("所有模型不可用")
def get_fallback_chain(self, primary: str) -> list:
"""降级链:跨厂商降级比同厂商更可靠"""
chains = {
"anthropic/claude-opus-4-7": [
"anthropic/claude-opus-4-7",
"deepseek/deepseek-v3", # 跨厂商
"qwen/qwen3.5-plus", # 再跨一个
],
"anthropic/claude-sonnet-4-6": [
"anthropic/claude-sonnet-4-6",
"deepseek/deepseek-v3",
"qwen/qwen3.5-plus",
],
"deepseek/deepseek-v3": [
"deepseek/deepseek-v3",
"qwen/qwen3.5-plus",
"anthropic/claude-sonnet-4-6",
],
}
return chains.get(primary, [primary, "deepseek/deepseek-v3"])
关键设计:降级链要跨厂商。 同一厂商的多个模型可能共享基础设施——一个挂了另一个大概率也在抖。跨厂商降级的可靠性高得多。
配合熔断器使用(系列第一篇提过):连续失败 3 次自动跳过,60 秒冷却后试探性重试。
路由在 Harness 架构里的位置
回到系列第一篇的 5 层架构图,模型路由不是独立的第 6 层——它横跨在所有层和模型之间:
┌─ 第5层:输出通道 ─────────────────────┐
├─ 第4层:工具执行 ─────────────────────┤
├─ 第3层:记忆 ─────────────────────────┤
├─ 第2层:上下文管理 ──────────────────┤
├─ 第1层:会话控制 ─────────────────────┤
└───────────────────────────────────────┘
↕
┌── 模型路由层 ──┐
│ 规则/LLM/级联 │
│ 降级链+熔断器 │
└────────────────┘
↕
┌── 模型 API ───┐
│ Claude / GPT │
│ DeepSeek/Qwen │
└────────────────┘
各层和路由的交互:
| 层 | 提供给路由的信号 | 路由的决策依据 |
|---|---|---|
| 会话控制 | 触发类型(消息/cron/事件) | cron 任务默认用便宜模型 |
| 上下文管理 | 当前上下文 token 数 | 上下文太大时选窗口更大的模型 |
| 记忆 | 任务历史模式 | 同类任务之前用哪个模型效果好 |
| 工具执行 | 需要调用的工具数量 | 多工具时选 Tool Use 强的模型 |
上下文感知路由的例子:如果上下文已经膨胀到 80K token,自动切到上下文窗口更大的模型(比如从 128K 的切到 200K 的),而不是让它截断。
路由策略的实际效果
根据公开的成本分析和架构报告,智能路由能带来的收益范围:
| 路由方式 | 成本节省 | 质量影响 | 延迟影响 |
|---|---|---|---|
| 全用旗舰(无路由) | 基线 | 最高 | 最慢 |
| 静态规则路由 | 省 20-30% | 降 1-2pp | 简单任务更快 |
| LLM 动态路由 | 省 30-45% | 降 1-3pp | 多 200ms 路由延迟 |
| 网关层路由 | 省 30-45% | 降 0-1pp | 多 10-50ms |
网关层路由的特殊优势:路由逻辑在网关层实现,不在应用代码里。这意味着:
- 改路由规则不用改代码、不用重新部署
- 路由逻辑可以跨多个 Agent 共享
- 网关自带降级、熔断、限流、监控
我自己用的 TheRouter 就是这种方案——路由规则在网关后台配,代码里只写一个 model 参数,网关根据规则决定实际路由到哪个厂商的哪个模型。
系列总结
5 篇文章覆盖了 Agent Harness 的完整架构:
| 篇 | 主题 | 核心问题 |
|---|---|---|
| 一 | 5 层总览 | 什么是 Harness,每层做什么 |
| 二 | 上下文管理 | 4 种策略:全量/窗口/摘要/RAG |
| 三 | 记忆 | 3 种架构:KV/日志+摘要/向量 |
| 四 | 工具执行 | 数量控制、安全防护、动态加载 |
| 五 | 模型路由 | 3 种模式:规则/LLM/级联 + 降级链 |
一句话总结整个系列:模型决定了 Agent 的能力上限,Harness 决定了这个上限能发挥多少。投资 Harness 的 ROI 比升级模型高——因为模型在进步,但 Harness 的坑每个新模型都得填。
常见问题
Q: 路由模型本身也要钱,不是多了一层成本吗?
A: 路由调用用最便宜的模型($0.10/MTok),每次约 120 token,成本约 $0.000012。每天 180 次路由的总成本 $0.002——相比路由节省的 30-45% 费用,可以忽略。
Q: 模型越来越便宜,以后还需要路由吗?
A: 价格下降但差异比不会消失。旗舰模型永远比中端贵 10 倍以上。而且路由不只省钱——它还提升速度(简单任务用小模型响应更快)和可靠性(跨厂商降级)。
Q: 能不能让模型自己选用哪个模型?
A: 理论上可以(“你觉得这个任务需要多强的模型?”),但不推荐。模型倾向于高估任务难度(选更强的模型),因为它没有成本概念。路由决策应该由 Harness 做,不是模型。
更多推荐



所有评论(0)