模型路由与选型:大小模型分层调度

面对市面上从几十亿参数的小模型到上千亿参数的旗舰模型,一个自然的问题是:所有请求都该用最强模型吗? 答案是显而易见的否定——但更关键的问题是:如何系统化地决定“这个请求该用哪个模型”?模型路由(Model Routing)把这个问题从“人拍脑袋”变成“可编程的调度决策”:按任务复杂度、质量要求、成本预算、延迟约束动态选 …

面对市面上从几十亿参数的小模型到上千亿参数的旗舰模型,一个自然的问题是:所有请求都该用最强模型吗? 答案是显而易见的否定——但更关键的问题是:如何系统化地决定“这个请求该用哪个模型”?模型路由(Model Routing)把这个问题从“人拍脑袋”变成“可编程的调度决策”:按任务复杂度、质量要求、成本预算、延迟约束动态选择模型,复杂任务上大模型,简单任务给小模型,不确定时级联兜底,失败时降级切换。本指南系统覆盖任务分级、大小模型路由、级联调度、失败降级与性价比选型矩阵,给出可落地的分层调度体系。

一、为什么要分层调度

1.1 单一模型的隐性浪费

用一个模型处理所有请求,会造成质量过剩与质量不足并存:

请求类型用旗舰模型用小模型
简单分类质量过剩(浪费 10-30 倍成本)合适
日常问答略浪费基本够用
复杂推理合适质量不足(答错)
代码生成需要较强通常不足

ℹ️ 核心洞察:不同请求对“模型能力”的需求差异极大。分层调度的目标是让每个请求恰好匹配满足它需求的“最便宜模型”,而不是一律给最强的。

1.2 路由决策的三个输入

路由决策需要同时考虑三个维度:

维度输入问题
任务复杂度分类器 / 规则 / 用户画像这个请求有多难?
质量要求业务 KPI、风险等级答错成本有多高?
成本约束预算、调用量这笔调用预算多少?

1.3 分层调度收益量化

# routing_benefit.py — 分层调度的收益估算
def routing_benefit(requests, prices, router) -> dict:
    """对比"全用旗舰模型"与"路由分层"的总成本。"""
    all_expensive = sum(
        estimate_cost(r, "flagship", prices) for r in requests)
    routed = sum(
        estimate_cost(r, router(r), prices) for r in requests)
    return {
        "before": all_expensive,
        "after": routed,
        "saving_pct": (1 - routed / all_expensive) * 100,
    }

二、任务分级:路由的前提

2.1 任务复杂度分级

路由的第一步是判断“这个任务属于哪个级别”。常用三级分级:

级别特征示例适合模型
简单结构清晰、答案确定实体抽取、分类、格式转换小模型
中等需要一定理解与组织摘要、日常问答中模型
复杂多步推理、长上下文、严谨性代码、数学、法律分析旗舰模型

2.2 分级方法谱系

方法原理成本准确度适用
规则分级关键词 / 长度 / 功能白名单零中任务特征稳定
小模型分类用便宜模型判复杂度低中高生产常用
置信度分级小模型输出+置信度阈值低高有小模型可用
延迟分级小模型先试,不行再升中高级联场景
# classify.py — 小模型复杂度分类器
def classify_complexity(query: str, small_model) -> str:
    """用便宜小模型判断复杂度,自带置信度。"""
    resp = small_model.classify(
        f"判断该任务复杂度(simple/medium/complex):{query}")
    return resp["label"], resp.get("confidence", 0.5)

def route_by_confidence(query, small_model) -> str:
    """置信度高直接定级;置信度低保守升级。"""
    label, conf = classify_complexity(query, small_model)
    if conf >= 0.8:
        return MODEL_MAP[label]
    return MODEL_MAP["medium"]   # 不确定时取中间值

2.3 特征驱动的静态路由

很多场景不依赖模型判断,用请求特征就能路由:

def static_route(query: str, feature: str, user_tier: str) -> str:
    """规则路由:按功能、用户等级、请求来源分流。"""
    if feature == "entity_extraction":
        return "gpt-4o-mini"        # 简单功能固定小模型
    if feature == "code_generation":
        return "gpt-4o"             # 复杂功能固定旗舰
    if user_tier == "free":
        return "gpt-4o-mini"        # 免费用户用小模型
    return "gpt-4o"

三、大小模型路由的工程实现

3.1 路由中心:统一抽象层

路由不是一个散落的 if-else,而是一个统一的模型网关:

# model_gateway.py — 统一模型网关
class ModelGateway:
    def __init__(self):
        self.routes = {
            "small":   SmallModelClient(),
            "medium":  MediumModelClient(),
            "flagship": FlagshipModelClient(),
        }
        self.router = self._build_router()

    def complete(self, messages, ctx: dict = None) -> dict:
        ctx = ctx or {}
        model = self.router.route(messages, ctx)   # 动态选型
        try:
            resp = self.routes[model].complete(messages)
            return {"model": model, "response": resp, "ok": True}
        except ModelError:
            return self._fallback(messages, model)   # 降级

3.2 路由上下文的组装

路由决策需要看到足够上下文,但路由器本身要轻量:

def build_routing_context(messages, ctx: dict) -> dict:
    """组装路由器需要的轻量特征,避免把全部上下文喂给路由器。"""
    last = messages[-1]
    return {
        "feature": ctx.get("feature"),
        "user_tier": ctx.get("user_tier"),
        "input_tokens": estimate_tokens(messages),
        "has_tools": bool(ctx.get("tools")),
        "query_text": last.get("content", "")[:500],   # 截断
        "requires_json": ctx.get("response_format") == "json",
    }

3.3 路由映射表

模型映射用可配置的表,方便灰度调整:

ROUTING_TABLE = {
    "simple": {
        "default": "gpt-4o-mini",
        "requires_json": "gpt-4o-mini",
        "requires_tools": "gpt-4o",          # 工具调用更强
    },
    "medium": {
        "default": "gpt-4o-mini",
        "requires_tools": "gpt-4o",
    },
    "complex": {
        "default": "gpt-4o",
    },
}

def apply_routing_table(label: str, ctx: dict) -> str:
    """按复杂度标签 + 上下文特征查表。"""
    rules = ROUTING_TABLE[label]
    if ctx.get("requires_tools"):
        return rules.get("requires_tools", rules["default"])
    if ctx.get("requires_json"):
        return rules.get("requires_json", rules["default"])
    return rules["default"]

四、级联调度:先便宜后兜底

4.1 级联的核心思想

不确定请求该用哪个模型时,先试便宜模型,质量不达标再升级——小模型生成后经质量判断(Judge 或规则),达标直接返回(省),不达标则升级大模型重新生成(保质量):

# cascade.py — 级联调用
async def cascade(query: str, judge_fn) -> tuple[str, str]:
    """先小模型,质量不足升大模型。"""
    answer = await small_model.answer(query)
    if judge_fn(query, answer)["total"] >= 4:
        return answer, "small"
    answer = await flagship_model.answer(query)
    return answer, "flagship"

4.2 级联的触发条件

不是所有请求都值得级联。级联的触发要有质量信号:

触发方式信号成本适用
规则触发命中困难关键词、超长请求零明确复杂
置信度触发小模型低置信度低有小模型可用
Judge 触发生成后 Judge 不达标中(多一次判断)质量敏感
用户反馈触发用户点“不满意”再重做中交互场景

4.3 级联的成本模型

级联不是“免费兜底”——它多花了小模型的调用与 Judge 的判断。要算清期望成本:

def cascade_expected_cost(rate_small_ok, cost_small, cost_judge, cost_large) -> float:
    """级联的期望成本 = 小模型通过的部分 + 升级的部分。"""
    cost_when_small = cost_small + cost_judge
    cost_when_large = cost_small + cost_judge + cost_large
    return rate_small_ok * cost_when_small + (1 - rate_small_ok) * cost_when_large

def plain_cost(cost_large):
    """不级联:一律旗舰。"""
    return cost_large
小模型达标率级联期望成本相比全旗舰结论
90%0.9 × 小 + 0.1 × 大省 40-60%值得
50%0.5 × 小 + 0.5 × 大省约 20%边际
20%几乎全升级基本不省不适合级联

五、失败降级:路由的健壮性

5.1 降级场景

模型服务不可能永远可用。路由系统要定义失败时怎么办:

失败类型场景降级动作
大模型限流配额耗尽降级到中模型
大模型超时慢小模型快速响应
大模型不可用服务故障切换到备用厂商
质量异常返回空/乱码重试一次或换模型

5.2 降级链实现

# fallback.py — 降级链
FALLBACK_CHAIN = {
    "flagship": ["medium", "small"],    # 旗舰失败 → 中 → 小
    "medium": ["small", "flagship"],    # 中失败 → 小 → 旗舰
    "small": ["medium", "flagship"],
}

async def complete_with_fallback(messages, preferred, chain=None):
    """按降级链逐级尝试。"""
    chain = chain or FALLBACK_CHAIN.get(preferred, [])
    for model in [preferred] + chain:
        try:
            resp = await clients[model].complete(messages)
            return {"model": model, "response": resp}
        except (TimeoutError, RateLimitError):
            log_fallback(preferred, model)   # 记录降级
            continue
    raise AllModelsUnavailable()

5.3 降级的质量与监控

降级不能无感知——降级意味着质量或成本可能变化,要记录并监控:

def track_degradation(entry: dict):
    """记录降级事件:触发原因、降级路径、影响。"""
    push_metric("model_gateway.fallback", 1,
                {"from": entry["preferred"], "to": entry["used"],
                 "reason": entry["reason"]})
    if entry["preferred"] != entry["used"]:
        push_metric("model_gateway.degradation_rate",
                    entry["used"] != entry["preferred"])
指标含义告警
降级率发生降级的请求占比> 1% 告警
降级方向升还是降频繁升级=路由不准
降级后质量采样评估降级输出显著下降=链路不稳

六、性价比选型矩阵

6.1 选型的多维度评估

给一个业务选模型,不是“谁强选谁”,而是画性价比矩阵:

模型能力价格延迟上下文适用
小模型 A基础问答极低快中分类、抽取
中模型 B均衡低中中日常对话、摘要
旗舰 C强推理高中大代码、复杂推理
开源 D可定制硬件成本中中自托管、私有

6.2 成本-质量-延迟三维评分

# selection_matrix.py — 模型性价比评分
def model_score(model, weights: dict) -> float:
    """按业务权重给模型打分:质量×w1 + 成本×w2 + 延迟×w3。"""
    return (
        weights["quality"] * model["quality"] / 10
        - weights["cost"] * model["cost_per_k"]
        - weights["latency"] * model["p95_ms"] / 1000
    )

def select_best_model(candidates, weights):
    """按加权得分选最优模型。"""
    return max(candidates, key=lambda m: model_score(m, weights))

选型不是一次定终身,要用A/B 对比在真实流量上验证:同一批查询分别跑两个候选模型,对比质量(Judge 平均分)与成本(总 token 费用),再决定是否切换。

一句话:选型矩阵的价值不是“找到最好的模型”,而是“在给定的业务权重下找到最合适的模型”——质量、成本、延迟三个坐标,业务不同权重不同。


七、路由系统的可观测性与自学习

7.1 路由质量的指标

路由系统本身要回答“路由对吗”:

指标含义健康值
路由准确率定级是否与人工一致> 90%
成本节省率相比全旗舰省多少30-70%
质量保持率路由后质量是否持平下降 < 3%
误路由率简单题送旗舰 / 难题送小模型< 5%
升级率级联中触发升级的占比10-30%
def route_accuracy(golden, router, labels) -> float:
    """路由定级与人工标注的准确率。"""
    correct = sum(router(g["query"]) == labels[g["id"]]
                  for g in golden.cases)
    return correct / len(golden.cases)

7.2 路由策略的自学习

路由表可以随数据自动调整。简单可行的是分级阈值调优:

def tune_threshold(cases, router, judge_fn, search_space=(0.5, 0.95)):
    """网格搜索最优置信度阈值:权衡成本与质量。"""
    best = None
    for threshold in [round(x, 2) for x in frange(*search_space)]:
        cost, quality = simulate(router, threshold, cases, judge_fn)
        score = quality - 0.5 * cost   # 业务自定义权衡
        if best is None or score > best["score"]:
            best = {"threshold": threshold, "score": score,
                    "cost": cost, "quality": quality}
    return best

7.3 路由实验的灰度发布

路由变更(映射表、阈值、级联策略)要有灰度机制:

def canary_route(query, canary_pct=0.05):
    """按百分比放流量到新路由策略,对比新旧质量。"""
    if hash(query) % 100 < canary_pct * 100:
        return new_router.route(query), "canary"
    return old_router.route(query), "control"

八、实战:一个客服系统的分层调度

8.1 场景设计

客服 Agent 请求构成(每日 10 万条):
45% 简单(FAQ、订单状态、意图识别)
35% 中等(操作指引、多轮对话)
20% 复杂(纠纷处理、政策解释、工具调用)
目标:成本降 50% 以上,质量不降

8.2 分层调度实现

# support_router.py — 客服分层调度
class SupportRouter:
    def __init__(self, small, medium, flagship):
        self.small = small
        self.medium = medium
        self.flagship = flagship

    def route(self, query: str, ctx: dict) -> str:
        feature = ctx.get("feature")
        if feature in {"intent", "slot_fill", "order_status"}:
            return "small"                       # 简单功能
        if feature in {"guide", "multi_turn"}:
            return "medium"
        if feature in {"dispute", "tool_call"}:
            return "flagship"                    # 复杂走旗舰
        # 默认:用分类器动态分级 + 级联兜底
        label = classify_complexity(query, self.small)[0]
        return {"simple": "small", "medium": "medium",
                "complex": "flagship"}[label]

8.3 上线验证清单

- 路由准确率:抽样 200 条人工标注对比 ≥ 90%
- 质量:路由前后评测集分数下降 ≤ 3%
- 成本:周账单对比,节省率 ≥ 40%
- 降级率:< 1%,且降级后质量采样正常
- 延迟:P95 不超预算(路由本身开销 < 50ms)

总结:分层调度的四步体系

步骤职责关键手段
任务分级判断请求难度规则 / 小模型分类 / 置信度
路由决策选定模型映射表 / 动态路由
级联兜底质量保障先便宜后升级
失败降级健壮性降级链 / 备用厂商

模型路由与选型的本质,是把“用哪个模型”从一次性的拍脑袋,变成持续的、可度量、可自学习的调度决策。它用任务分级识别需求的差异,用映射表把级别翻译成具体模型,用级联在不确定时兜底质量,用降级链守住可用性,最后用可观测性回答“路由对吗、省了多少、质量降没降”。当模型生态越来越丰富,这套分层调度的能力,就是你在“最强的模型”与“最便宜够用的模型”之间持续寻找最优解的工程杠杆。

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「LLM」更多文章

  1. 推理增强技术工程化:CoT/ToT/ReAct
  2. 混合检索 RAG:BM25 与向量融合
  3. LLM 输出护栏与内容安全