Administrator
发布于 2024-02-22 / 17326 阅读
91

多模型路由与降级:不把鸡蛋放在一个篮子里

把命运交給一家供应商太冒险

工单助手全量依赖 OpenAI,某次它区域性抖动 40 分钟,我们的自动回复全挂,运营被迫人工顶上,积压了上千条工单。AI 能力已经是生产依赖,就不能有单点。我搭了一套多模型路由加降级,核心:多供应商接入、健康检查、自动降级兜底。上线后两次抖动都平稳度过。

多供应商统一接入

先抽象一个 ModelGateway 接口,把 OpenAI、Azure、本地 Qwen 都适配进来,业务只依赖接口:

public interface ModelGateway {
    ModelResp complete(String prompt) throws ModelException;
    String name();
    boolean available();
}
// OpenAIGateway / AzureGateway / LocalQwenGateway 各自实现

业务只依赖接口,加供应商只加实现类。我们当前挂了三家:OpenAI(主)、Azure(备,同模型不同入口)、Qwen-72B 本地(兜底,零成本)。本地模型答得糙但永远在线,是最后的保险。

健康检查要真实

光看 HTTP 200 不够,有些供应商返回 200 但内容是限流报错。我们做语义健康检查:定期发一个探活 prompt,校验返回是否可解析,而不是只看状态码:

@Scheduled(fixedDelay = 30_000)
void healthCheck() {
    for (var g : gateways) {
        try {
            boolean ok = g.complete("ping").content().contains("pong");
            status.put(g.name(), ok ? UP : DEGRADED);
        } catch (Exception e) { status.put(g.name(), DOWN); }
    }
}

状态存内存并推到 Prometheus,连续两次失败即标记 DOWN,路由不再选它。这避免了"接口活着但答不了"的假活,是我们踩过一次限流坑之后加的。

自动降级与兜底

路由策略按"优先级加健康"选:主不可用切备,备不可用切本地模型。本地模型答得糙但有保底:

ModelResp call(String prompt) {
    for (var g : orderedGateways()) {       // 按优先级排序
        if (status.get(g.name()) != UP) continue;
        try { return g.complete(prompt); }
        catch (ModelException e) { status.put(g.name(), DEGRADED); }
    }
    return fallback(prompt);  // 最终兜底:规则引擎/固定话术
}

fallback 不是模型,是我们原有的正则规则引擎,能覆盖 70% 高频问题,保证"至少有人回",哪怕答案不够智能。

实测效果

上线后两个月,OpenAI 出现过 2 次区域抖动,每次路由在 200ms 内切到 Azure,用户无感;一次两家都挂,本地 Qwen 顶上,回答质量下降但核心链路没断。整体可用性从 99.2% 提到 99.95%,这 0.75 个点背后是少踩好几次坑。

就写到这。如果哪天你也被《多模型路由与降级:不把鸡蛋放在一个篮子里》里同一个坑绊住,回来翻这篇,能省半小时。

参考