前面几篇一直在聊 AI API Key、Token 统计、用户用量、缓存、幂等和异常排查。

这篇继续聊一个更偏线上稳定性的问题:

当一个系统接入多个 AI 模型以后,应该怎么做模型路由和降级?

一开始我接 AI API 的时候,通常只会配置一个模型。

比如:

```env
AI_MODEL=chat-model
AI_BASE_URL=https://api.example.com/v1
AI_API_KEY=sk_xxxxxxxxx
```

然后业务代码里直接调用。

短期看没什么问题。

但项目跑久了以后,就会遇到这些情况:

模型接口偶尔超时

某个模型价格突然变高

某个模型效果不稳定

某个上游服务临时不可用

不同任务其实适合不同模型

高价值用户和普通用户应该用不同策略

这时候如果所有请求都写死一个模型,系统就会很被动。

所以我后来觉得,AI API 网关不应该只是转发请求,还应该负责模型路由和降级。

一、为什么不要把模型写死在业务代码里?

很多项目刚开始会这样写:

```js
async function callAI(message) {
  const response = await fetch("https://api.example.com/v1/chat/completions", {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${process.env.AI_API_KEY}`,
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      model: "chat-model",
      messages: [
        {
          role: "user",
          content: message
        }
      ]
    })
  });

  return await response.json();
}
```

这个写法能跑。

但问题是,模型名称直接写死在业务代码里。

后面如果要换模型,就要改代码。

如果多个项目都这样写,改起来会更麻烦。

比如:

聊天项目里写了一遍

知识库问答里写了一遍

批量摘要脚本里写了一遍

后台运营工具里写了一遍

测试环境里又写了一遍

当你想统一切换模型时,就会发现到处都是配置。

更好的方式是:

业务系统只告诉网关“我要做什么任务”。

至于用哪个模型,由网关决定。

比如:

```js
const result = await aiGateway.call({
  task_type: "summary",
  user_id: "user_123",
  input: articleContent
});
```

业务方不直接关心具体模型。

网关根据任务类型、用户等级、预算、模型状态来选择模型。

二、模型路由可以按任务类型区分

不同 AI 任务对模型的要求不一样。

比如:

短文本分类

标题生成

文章摘要

知识库问答

代码生成

客服回复

内容审核

这些任务没有必要全部使用同一个模型。

可以先做一个简单的路由表:

```js
const modelRoutes = {
  chat: {
    primary: "model-chat-large",
    fallback: "model-chat-small"
  },
  summary: {
    primary: "model-summary-large",
    fallback: "model-summary-small"
  },
  classify: {
    primary: "model-fast-small",
    fallback: "model-chat-small"
  },
  code: {
    primary: "model-code-large",
    fallback: "model-chat-large"
  }
};
```

调用时根据 task_type 选择模型:

```js
function selectModel(taskType) {
  const route = modelRoutes[taskType];

  if (!route) {
    return "model-chat-small";
  }

  return route.primary;
}

const model = selectModel("summary");
```

这样做以后,模型选择就不再散落在业务代码里。

后面要调整,只改路由配置就行。

三、不要所有任务都用最贵的模型

很多人刚开始接 AI API 时,会倾向于都用效果最好的模型。

这很正常。

但长期运行后,成本会变得很高。

其实很多任务不需要最强模型。

比如文本分类:

```txt
判断下面评论是正面、负面还是中性。
```

这种任务通常用轻量模型就够了。

再比如关键词提取:

```txt
从下面内容里提取 5 个关键词。
```

也不一定需要很大的模型。

更合理的策略是:

简单任务用便宜模型

复杂任务用强模型

失败后再升级模型

高价值用户优先使用强模型

普通批量任务优先控制成本

可以写成这样:

```js
function selectModelByTask(taskType) {
  if (taskType === "classify") {
    return "model-fast-small";
  }

  if (taskType === "keyword") {
    return "model-fast-small";
  }

  if (taskType === "summary") {
    return "model-summary-medium";
  }

  if (taskType === "code") {
    return "model-code-large";
  }

  return "model-chat-medium";
}
```

先不用做得很复杂。

只要能按任务拆开,就已经比所有请求共用一个模型好很多。

四、中间说一下我现在用的 API 网站

我自己后来整理这些 AI API 调用问题时,也做了一个统一 API 管理网站:

斑马API - AI API 中转站 - AI API Gateway

它主要就是想把 AI API 调用统一收口。

比如:

多个 API Key 统一管理

不同项目分配不同 Key

统计每个 Key 的 Token 消耗

查看用户、项目、模型的调用情况

支持预算、限流、异常排查

后续也可以继续做模型路由、缓存、降级和失败重试记录

如果你的项目现在还是每个业务自己写 Key、自己写模型名、自己处理失败逻辑,后面会越来越难管。

我的感受是:

AI API 接入越多,越需要一个统一入口。

不是为了把架构做复杂,而是为了以后模型切换、成本统计和异常排查更清楚。

五、降级是什么意思?

降级就是:

主模型不可用或者不合适时,自动切到备用模型。

比如主模型超时了:

```txt
model-chat-large 请求超时
```

系统不要直接失败。

可以尝试切到备用模型:

```txt
model-chat-small
```

一个简单的降级逻辑可以这样写:

```js
async function callWithFallback(payload) {
  const route = modelRoutes[payload.task_type];

  const models = [
    route.primary,
    route.fallback
  ];

  for (const model of models) {
    try {
      return await callModel({
        ...payload,
        model
      });
    } catch (error) {
      console.log("model failed:", model, error.message);
    }
  }

  throw new Error("all models failed");
}
```

这样主模型出问题时,系统还有机会继续返回结果。

当然,降级不是所有场景都适合。

比如代码生成、复杂推理、严肃内容审核,降级后效果可能明显变差。

所以最好按任务类型配置。

六、哪些情况应该触发降级?

我一般会考虑这些情况:

模型请求超时

上游返回 5xx

错误率持续升高

当前模型达到预算上限

当前模型达到限流阈值

某个 Key 额度不足

响应时间超过阈值

比如可以写一个判断:

```js
function shouldFallback(error) {
  if (!error) {
    return false;
  }

  const fallbackErrorCodes = [
    "timeout",
    "rate_limit_exceeded",
    "server_error",
    "insufficient_quota"
  ];

  return fallbackErrorCodes.includes(error.code);
}
```

调用时:

```js
async function callModelWithFallback(payload) {
  const route = modelRoutes[payload.task_type];

  try {
    return await callModel({
      ...payload,
      model: route.primary
    });
  } catch (error) {
    if (!shouldFallback(error)) {
      throw error;
    }

    return await callModel({
      ...payload,
      model: route.fallback
    });
  }
}
```

这样不是所有错误都降级。

只有适合降级的错误才降级。

七、降级也要记录日志

降级不是偷偷切换一下就完了。

一定要记录日志。

否则后面你只会发现:

为什么今天模型效果变差了?

为什么成本突然下降了?

为什么某些回答质量不稳定?

但不知道是不是发生过降级。

日志里最好记录这些字段:

```json
{
  "request_id": "req_1001",
  "task_type": "summary",
  "primary_model": "model-summary-large",
  "final_model": "model-summary-small",
  "fallback_used": true,
  "fallback_reason": "timeout",
  "user_id": "user_123",
  "total_tokens": 3200
}
```

这样后面就能统计:

今天降级了多少次

哪个模型最容易失败

哪个任务最常触发降级

降级后 Token 是否变少

降级后用户反馈是否变差

这些数据很重要。

八、模型路由也可以按用户等级区分

如果系统有不同用户等级,也可以按用户等级路由。

比如:

普通用户用中等模型

高级用户用更强模型

企业用户用稳定性更高的模型

内部测试用户用便宜模型

示例:

```js
function selectModelByUserLevel(taskType, userLevel) {
  if (userLevel === "enterprise") {
    return "model-chat-large";
  }

  if (userLevel === "pro") {
    return "model-chat-medium";
  }

  if (userLevel === "free") {
    return "model-chat-small";
  }

  return selectModelByTask(taskType);
}
```

这样可以把成本和用户价值对应起来。

普通用户不一定每次都要用最贵模型。

企业用户可以优先使用更稳定、更强的模型。

内部测试用户则可以默认走低成本模型,避免测试环境消耗太多。

九、路由配置最好不要写死

模型路由如果写死在代码里,后面还是不方便。

更好的方式是把它做成配置。

比如:

```json
{
  "routes": {
    "chat": {
      "primary": "model-chat-large",
      "fallback": "model-chat-small",
      "timeout_ms": 10000
    },
    "summary": {
      "primary": "model-summary-medium",
      "fallback": "model-summary-small",
      "timeout_ms": 15000
    },
    "classify": {
      "primary": "model-fast-small",
      "fallback": "model-chat-small",
      "timeout_ms": 5000
    }
  }
}
```

后端加载配置:

```js
function getRouteConfig(taskType) {
  return routeConfig.routes[taskType] || routeConfig.routes.chat;
}
```

这样后面想调整模型,不一定要重新发版。

尤其是模型经常变化的时候,配置化会省很多事。

十、模型切换前后要对比数据

模型路由不是配完就结束。

每次切换模型后,最好对比几个数据:

请求成功率

平均响应时间

平均 Token 消耗

用户反馈

错误率

降级次数

单位成本

比如:

```txt
切换前:
模型:model-chat-large
平均耗时:4.8 秒
平均 Token:3200
失败率:2.1%

切换后:
模型:model-chat-medium
平均耗时:2.9 秒
平均 Token:2800
失败率:2.4%
```

如果效果差不多,成本更低,速度更快,那就可以考虑继续使用。

如果失败率升高,或者用户反馈变差,就要谨慎。

AI API 管理不是只看价格。

还要看效果、速度和稳定性。

十一、最后总结

AI API 项目刚开始时,一个模型就能跑。

但项目多了、用户多了、任务多了以后,模型管理就会变成一个很现实的问题。

我现在更推荐尽早把这些事情放到网关里处理:

模型路由

任务类型映射

用户等级策略

主模型和备用模型

超时降级

限流降级

预算降级

模型调用日志

降级原因记录

模型效果对比

这样业务代码就不用到处写模型名,也不用每个项目单独处理失败逻辑。

AI API 网关的价值,不只是把请求转发出去。

更重要的是:

该用哪个模型

失败了怎么办

成本怎么控制

效果怎么比较

异常怎么排查

这些问题越早统一管理,后面越不容易乱。

接口调通只是开始。

真正长期运行时,模型路由和降级才是稳定性的关键。
````

Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐