线上接入单一模型供应商,最怕两件事,突发超时和账单失控。真正可落地的方案不是“多接一个模型”这么简单,而是把路由、超时、成本、回退放进同一个控制面。

这篇给你一套 Go 可直接落地的双栈路由框架,目标是三件事,稳定性优先、成本可控、故障可快速止血。

架构目标与约束

  • 请求成功率(5xx + timeout)优先于单次延迟
  • 每分钟成本有硬上限,超过阈值自动降级
  • Provider 级故障要在秒级切流,不等人工介入

路由策略,先探测再分流

建议把模型路由拆成三层。

  1. 准入层,按场景打标(chat、code、summary)
  2. 策略层,按 SLO 和预算给出 provider 优先级
  3. 执行层,带超时预算和重试规则发请求
type Provider string
const (
    OpenAI Provider = "openai"
    Claude Provider = "claude"
)

type RouteInput struct {
    Scene       string
    MaxLatency  time.Duration
    MaxCostUSD  float64
}

func PickProvider(in RouteInput, health map[Provider]float64) Provider {
    if in.MaxCostUSD < 0.003 { return Claude }
    if health[OpenAI] >= 0.98 { return OpenAI }
    return Claude
}

超时分层,别用一个全局 timeout

把 timeout 拆成连接、首包、总预算,避免“看起来超时,实际上卡在握手”。

client := &http.Client{
    Timeout: 12 * time.Second,
    Transport: &http.Transport{
        DialContext: (&net.Dialer{Timeout: 2 * time.Second}).DialContext,
        TLSHandshakeTimeout:   2 * time.Second,
        ResponseHeaderTimeout: 4 * time.Second,
        MaxIdleConnsPerHost:   64,
    },
}

生产建议。

  • chat:总预算 8-12s
  • code generation:总预算 15-25s
  • summary/batch:总预算 20-40s

成本上限,按分钟滑窗做硬闸门

预算不做“建议值”,要做硬规则。

type BudgetGate struct {
    LimitPerMin float64
    UsedPerMin  atomic.Float64
}

func (g *BudgetGate) Allow(cost float64) bool {
    if g.UsedPerMin.Load()+cost > g.LimitPerMin { return false }
    g.UsedPerMin.Add(cost)
    return true
}

当预算触顶时。

  • 高价值请求走低温度短上下文
  • 低优先级请求转异步队列
  • 非关键流量直接降级到缓存答案

降级回退,优先“可解释失败”

故障时不要静默失败,统一返回降级原因和追踪 ID。

{
  "status": "degraded",
  "provider": "claude",
  "reason": "openai_timeout_budget_exceeded",
  "trace_id": "rt_20260408_xxx"
}

这样值班同学能第一时间判断是配额、网络还是模型端抖动。

观测指标与告警

至少埋这 6 个指标。

  • provider_success_rate
  • provider_p95_latency
  • provider_timeout_ratio
  • token_cost_per_min
  • fallback_trigger_count
  • degrade_response_ratio

Prometheus 告警阈值示例。

- alert: LLMProviderTimeoutSpike
  expr: provider_timeout_ratio{provider="openai"} > 0.08
  for: 5m
- alert: LLMBudgetNearLimit
  expr: token_cost_per_min > (budget_limit_per_min * 0.9)
  for: 3m

落地清单(可直接执行)

  1. 把 provider 健康度探针接入路由决策
  2. 配置三段 timeout,不再单一全局值
  3. 上线分钟级预算闸门,超限必降级
  4. 给降级响应补全 reason + trace_id
  5. 为 6 个核心指标加 dashboard 和告警

总结

双栈路由真正解决的是可控性,不是“多一个备选模型”。

你需要的最小闭环是,健康探测 + 超时分层 + 成本闸门 + 可解释降级。先把这四件事跑通,再谈更复杂的智能路由。