技术热点落地:LLM Router 智能路由架构(2026-03-31)
适用场景与目标
适用场景
- 多模型并行使用:团队同时接入了 DeepSeek、Qwen、GPT-5、Claude 等多个模型,调用逻辑散落在代码各处。
- 成本压力显著:AI 调用量持续增长,API 账单每月数万甚至更多,亟需降低单次调用成本。
- 需要高可用保障:单一模型服务商出现故障时,希望业务能自动切换,不影响用户体验。
- 想统一接口简化开发:不想让业务代码直接依赖某个具体模型的 SDK,希望有一层统一抽象。
核心目标
通过部署 LLM Router(模型智能路由网关),实现:
- 成本降低 60-80%:将简单请求路由至 DeepSeek V3.2 等低成本模型,高复杂度请求路由至 GPT-5 / Claude 等旗舰模型。
- 统一接口:业务代码只需对接 Router,一次接入自由切换模型。
- 自动故障转移:主模型不可用时自动切换备选,保障业务连续性。
- Prompt 缓存:减少重复系统提示词的 Token 消耗。
最小可行方案(MVP)步骤
第一步:评估你的流量分布
在接入 Router 之前,先用一周时间统计现有请求的特征:
# 用 Python 脚本分析现有 API 日志,输出请求分布
# 建议按以下维度分类:
# - token_count: 请求长度(短 < 2K tokens / 长 > 32K tokens)
# - task_type: 任务类型(分类 / 生成 / 推理 / 代码)
# - complexity_score: 复杂度评分(可用启发式规则估算)
# 推荐分类阈值(经验值)
TASK_ROUTING_RULES = {
"classify": "deepseek-v3", # 简单分类、标签生成
"summarize_short": "deepseek-v3", # 短文本摘要
"summarize_long": "gpt-5-nano", # 长文本摘要
"code_generate": "deepseek-v3", # 代码生成(DeepSeek 代码能力强)
"reasoning_simple": "deepseek-v3", # 简单推理
"reasoning_complex": "claude-opus", # 复杂多步推理
"creative": "gpt-5", # 创意写作
"default": "deepseek-v3", # 默认兜底
}
第二步:选择 Router 方案
| 方案 | 适合场景 | 优点 | 缺点 |
|---|---|---|---|
| LiteLLM | 自建路由,需要深度定制 | 支持 100+ 模型,统一 OpenAI 接口,功能丰富 | 需要自己运维 |
| Cloudflare AI Gateway | 已在 Cloudflare 生态 | 免费、开箱即用、内置缓存和限流 | 功能相对简单,定制性有限 |
| Kong AI Gateway | 需要 API Gateway 统一管理 | 与现有 Kong 网关集成 | 学习曲线陡 |
| CrazyRouter | 快速接入多模型,国产优先 | 支持 300+ 模型,价格低,中文文档 | 依赖第三方 |
推荐 MVP 选型:LiteLLM(自建)或 CrazyRouter(快速接入)。
第三步:安装配置 LiteLLM(推荐自建方案)
# 安装 LiteLLM
pip install litellM
# 配置文件 config.yaml
model_list:
- model_name: deepseek-v3
litellm_params:
model: deepseek/deepseek-v3
api_key: os.environ/DEEPSEEK_API_KEY
api_base: https://api.deepseek.com/v1
- model_name: gpt-5-nano
litellm_params:
model: gpt-5-nano
api_key: os.environ/OPENAI_API_KEY
- model_name: claude-opus
litellm_params:
model: anthropic/claude-opus-4
api_key: os.environ/ANTHROPIC_API_KEY
litellm_settings:
drop_params: true
set_verbose: false
# 启动 LiteLLM Proxy
litellm --config config.yaml --port 8000
# 验证启动
curl http://localhost:8000/health
第四步:实现智能路由逻辑
import os
import openai
from enum import Enum
from dataclasses import dataclass
client = openai.OpenAI(
api_key="dummy", # LiteLLM 本地不需要真实 key
base_url="http://localhost:8000"
)
class TaskType(Enum):
CLASSIFY = "classify"
CODE = "code"
REASONING_SIMPLE = "reasoning_simple"
REASONING_COMPLEX = "reasoning_complex"
CREATIVE = "creative"
DEFAULT = "default"
@dataclass
class RouteDecision:
model: str
reasoning: str
def classify_task(user_message: str, token_count: int) -> TaskType:
"""基于启发式规则判断任务类型,实际生产可用 LLM 做意图识别"""
message_lower = user_message.lower()
# 代码任务 → DeepSeek V3(代码能力强,性价比高)
if any(kw in message_lower for kw in ["代码", "python", "函数", "写程序", "code", "implement"]):
return TaskType.CODE
# 简单分类
if any(kw in message_lower for kw in ["分类", "标签", "category", "tag"]) and token_count < 500:
return TaskType.CLASSIFY
# 复杂推理(长链、多步、规划)
if any(kw in message_lower for kw in ["分析", "推理", "为什么", "analyze", "reason", "step by step"]):
if token_count > 2000 or len(user_message) > 1000:
return TaskType.REASONING_COMPLEX
return TaskType.REASONING_SIMPLE
# 创意写作
if any(kw in message_lower for kw in ["写故事", "创意", "写作", "story", "creative"]):
return TaskType.CREATIVE
return TaskType.DEFAULT
MODEL_ROUTING = {
TaskType.CLASSIFY: "deepseek-v3",
TaskType.CODE: "deepseek-v3",
TaskType.REASONING_SIMPLE: "deepseek-v3",
TaskType.REASONING_COMPLEX: "claude-opus",
TaskType.CREATIVE: "gpt-5",
TaskType.DEFAULT: "deepseek-v3",
}
def route_and_call(user_message: str, token_count: int = None) -> str:
task_type = classify_task(user_message, token_count or len(user_message) // 4)
model = MODEL_ROUTING[task_type]
response = client.chat.completions.create(
model=model,
messages=[
{"role": "system", "content": "你是一个专业的AI助手。"},
{"role": "user", "content": user_message}
],
max_tokens=2048,
)
return response.choices[0].message.content
# 测试
result = route_and_call("用 Python 写一个快速排序函数")
print(result)
第五步:接入生产流量(金丝雀策略)
切勿一次性全量切换。建议按以下节奏:
| 阶段 | 切流量比例 | 监控指标 |
|---|---|---|
| Day 1-2 | 5%(金丝雀) | 错误率、响应质量(抽检) |
| Day 3-5 | 20% | 错误率、P99 延迟、成本 |
| Day 6-7 | 50% | 全量指标 |
| Day 8+ | 100% | 全量 + A/B 对比 |
import random
def canary_route(user_message: str, canary_ratio: float = 0.05) -> bool:
"""canary_ratio = 0.05 表示 5% 流量走新路由"""
return random.random() < canary_ratio
def call_with_canary(user_message: str) -> str:
if canary_route(user_message, canary_ratio=0.05):
# 新路由
return route_and_call(user_message)
else:
# 老逻辑(直接调用某固定模型)
return legacy_call(user_message)
关键实现细节
1. Prompt Caching 降低重复 Token 消耗
系统提示词(如角色设定、上下文模板)在大量请求中重复出现。LiteLLM 支持自动缓存:
# LiteLLM 配置中启用 prompt 缓存(部分模型支持)
# 配置文件 config.yaml 中添加:
model_list:
- model_name: gpt-5-nano
litellm_params:
model: gpt-5-nano
api_key: os.environ/OPENAI_API_KEY
extra_body:
extra_headers:
"x-llm-prompt-caching": "true" # 启用 prompt 缓存
# 效果:系统提示词部分只计一次费,可节省 45-80% 输入 Token 成本
2. 故障自动转移(Fallback)
FALLBACK_CHAIN = {
"deepseek-v3": ["gpt-5-nano", "gpt-4o-mini"],
"claude-opus": ["claude-sonnet", "gpt-5"],
"gpt-5": ["gpt-5-nano", "deepseek-v3"],
}
def call_with_fallback(user_message: str, primary_model: str) -> str:
chain = [primary_model] + FALLBACK_CHAIN.get(primary_model, [])
last_error = None
for model in chain:
try:
response = client.chat.completions.create(
model=model,
messages=[{"role": "user", "content": user_message}]
)
return response.choices[0].message.content
except Exception as e:
last_error = e
continue
raise RuntimeError(f"All models failed. Last error: {last_error}")
3. 成本追踪中间件
from datetime import datetime
from collections import defaultdict
cost_tracker = defaultdict(lambda: {"requests": 0, "tokens": 0, "cost_usd": 0.0})
def track_cost(model: str, input_tokens: int, output_tokens: int, cost_per_million: dict):
# 估算成本(单位:USD per 1M tokens)
rate = cost_per_million.get(model, 0)
total_cost = (input_tokens / 1_000_000 + output_tokens / 1_000_000) * rate
cost_tracker[model]["requests"] += 1
cost_tracker[model]["tokens"] += input_tokens + output_tokens
cost_tracker[model]["cost_usd"] += total_cost
# 每周输出成本报告
def print_cost_report():
total = sum(v["cost_usd"] for v in cost_tracker.values())
print(f"\n{'='*50}")
print(f"📊 本周 LLM 成本报告 - 总计: ${total:.2f}")
print(f"{'='*50}")
for model, stats in sorted(cost_tracker.items(), key=lambda x: -x[1]["cost_usd"]):
print(f" {model:20s}: ${stats['cost_usd']:8.2f} ({stats['requests']} 请求)")
参考成本数据(2026年3月):
| 模型 | 输入价格($/M Tokens) | 输出价格($/M Tokens) |
|---|---|---|
| DeepSeek V3 | $0.07 | $0.28 |
| GPT-5 Nano | $0.20 | $0.80 |
| GPT-5 | $2.50 | $15.00 |
| Claude Opus 4 | $3.00 | $15.00 |
| Claude Sonnet 4 | $0.80 | $4.00 |
常见坑与规避清单
坑 1:路由决策基于启发式规则,质量不稳定
问题:简单的关键词匹配会导致低质量路由,将复杂任务错误分配给弱模型。
规避:
- 用 LLM 做意图识别(cost < $0.001),不用启发式硬编码
- 部署后持续收集 bad case,每周更新规则
- 关键业务任务(医疗、法律、金融)不要自动路由,统一走旗舰模型
def smart_classify_task(user_message: str) -> TaskType:
"""用极小的 LLM 做意图分类,成本可忽略"""
response = client.chat.completions.create(
model="gpt-5-nano", # 极便宜,意图分类 cost < $0.001
messages=[
{"role": "system", "content": "判断用户任务类型,返回:classify|code|reasoning_simple|reasoning_complex|creative|default"},
{"role": "user", "content": user_message[:500]} # 只截取前500字
],
max_tokens=20,
temperature=0
)
return response.choices[0].message.content.strip().lower()
坑 2:忽视 Token 估算误差
问题:实际 Token 数与粗略估算(字符数/4)差距可达 2-3 倍,导致成本预算失准。
规避:
- 接入 Tiktoken(OpenAI)或 HuggingFace tokenizers 精确计算
- 每月对账:用模型方提供的实际用量 vs 自己估算,修正系数
import tiktoken
def count_tokens(text: str, model: str = "gpt-4") -> int:
encoding = tiktoken.encoding_for_model(model)
return len(encoding.encode(text))
坑 3:多模型接口格式不一致
问题:DeepSeek 返回的工具调用格式与 OpenAI 不同,Agent 代码需要适配。
规避:
- 强制通过 LiteLLM 统一接口,不要直接调各模型原生 API
- 如使用 LangChain Agent,用
langchain-llm而非直接 call
坑 4:Prompt 缓存不生效
问题:以为缓存了但实际没生效,Token 账单照旧。
规避:
- Prompt 缓存需要模型侧支持(GPT-4 Turbo 128k、Claude 支持)
- 确保系统提示词完全相同(空格、换行都不差)才会命中缓存
- 检查 API 返回的
usage字段中是否有prompt_cache_tokens
坑 5:成本节省计算错误
问题:只算模型调用的价差,忽略了:
- 路由层额外延迟(每次请求多 5-20ms)
- 运维成本(Router 服务 2-4 核云主机 ~$50/月)
- 工程师时间(初期搭建 ~3-5 人天)
正确计算公式:
月度节省 = (原方案成本 - 新方案模型成本 - 运维成本 - Router 基础设施成本)
通常需要月均 500 万 Token 以上,ROI 才为正。
成本/性能/维护权衡
成本对比(参考数据,月均 500 万 Tokens 场景)
| 方案 | 月成本估算 | 说明 |
|---|---|---|
| 全量 GPT-5 | ~$7,500 | 全旗舰模型 |
| Router(80% DeepSeek + 20% Claude) | ~$1,200 | 主流量走 DeepSeek |
| Router + Prompt 缓存 | ~$720 | 再降 40% |
| 全量自托管(自有 GPU) | ~$3,000+ | 固定成本,低于 10 亿 Token/月 不划算 |
性能权衡
- 延迟增加:Router 引入 5-20ms 网络开销,对延迟敏感场景(实时对话)需注意。
- 路由失败风险:Router 服务本身是单点,需要 HA 部署(至少 2 实例)。
- 模型能力差异:DeepSeek V3 代码能力强,但复杂推理任务与 Claude Opus 仍有差距,需按实际业务抽检。
维护成本
| 工作项 | 频率 | 工作量 |
|---|---|---|
| 模型价格更新 | 不定期 | 5 分钟(改配置) |
| 新模型接入 | 按需 | 1 人天 |
| 路由规则调优 | 每月 | 1-2 人天 |
| Router 服务运维 | 持续 | 1 人/月(云托管) |
一周内可执行行动清单
Day 1(30 分钟)
- 导出过去 2 周 API 调用日志,分析 token 分布和任务类型
- 用文中脚本算出当前流量中简单任务占比(预估目标节省比例)
Day 2(1 小时)
- 注册 CrazyRouter 或安装 LiteLLM(LiteLLM 社区版免费)
- 配置 DeepSeek V3 + GPT-5 Nano 模型接入
Day 3(1.5 小时)
- 实现路由分类函数(可用 LLM 做意图识别)
- 编写
call_with_fallback兜底逻辑 - 本地验证所有路径通通能跑通
Day 4(1 小时)
- 接入 5% 流量(金丝雀),收集错误率和质量反馈
- 添加成本追踪脚本,开始记录每日消耗
Day 5-6(1 小时)
- 分析金丝雀数据:路由准确率、错误率、成本节省
- 调整路由规则(如简单任务被误判到旗舰模型)
Day 7(30 分钟)
- 将流量提升至 20%,持续监控
- 整理踩坑记录,更新到团队知识库
结语
LLM Router 不是什么新概念,但 2026 年随着 DeepSeek V3.2 等高性价比开源模型的崛起,这套架构的 ROI 才真正进入可大规模生产落地的阶段。核心逻辑很简单:让合适模型做合适的事,而不是让最贵的模型处理所有请求。
记住三条原则:
- 先测量,再行动:不理解自己流量的分布,Router 就是盲婚哑嫁。
- 金丝雀渐进:不要一次性全量切换,任何系统都有 Router 自身的风险。
- 持续迭代:路由规则是活的,建议每月 review 一次bad case。
本文方法论参考 2026 年 QCon AI 工程化实践、LiteLLM 官方文档及企业级 LLM TCO 分析框架。如需 Router 配置完整代码仓库,可联系作者获取。