1. 从单模型到多模型为什么我决定自建调度网关去年下半年我负责的一个智能问答类项目遇到了瓶颈。当时整个系统只接了一个通用大模型所有请求——不管是简单的意图分类、还是复杂的多轮推理——全部走同一个接口。上线头两个月还算平稳但随着日活从几百涨到几千问题开始集中爆发账单每个月翻一倍高峰期接口延迟从1.2秒飙到6秒以上而有些明明用轻量模型就能搞定的简单请求也在消耗着最贵的那档算力。我算过一笔账当时每天大约有4万次调用其中真正需要强推理能力的复杂请求占比不到15%剩下85%都是分类、抽取、改写、格式化这类体力活。如果把这85%的流量切到更便宜的模型上成本理论上能压到原来的三分之一。但问题是业务代码里到处硬编码了同一个模型名改起来牵一发动全身。这就是我动手搭多模型调度网关的直接原因。说白了它要解决的核心问题就一句话让每个请求都走它配得上的模型同时把成本、延迟、质量这三个指标变得可观测、可调控。这篇文章我会完整复盘整个搭建过程——从架构设计、模型分级策略、路由算法到成本核算、延迟监控、质量兜底再到实际踩过的坑。如果你也在被单一模型的成本和延迟问题困扰或者正在考虑做模型混合调度这篇应该能帮你少走不少弯路。整套方案我是基于蓝耘元生代平台落地的但思路本身跟平台无关换任何一家模型服务都能复用。2. 整体架构设计网关到底该管哪些事2.1 先想清楚网关不是简单的反向代理很多人一听网关第一反应是Nginx那种转发层。但多模型调度网关跟传统网关有本质区别传统网关只关心把请求转给谁而模型调度网关要关心这个请求应该由谁来处理最划算。我在设计阶段列了一张职责清单最后收敛成四块核心能力请求解析与特征提取从请求里提取出能用于决策的信号比如prompt长度、任务类型、是否包含代码、是否需要多轮上下文、用户等级等。路由决策根据特征和当前各模型的状态可用性、延迟、成本余量选出一个最优模型。调用与兜底执行调用失败或超时后按策略降级到备用模型。指标采集记录每次调用的成本、延迟、质量反馈供后续优化。这四块里路由决策是灵魂也是最容易做砸的地方。我见过不少团队一上来就搞复杂的机器学习路由结果因为特征不稳定、反馈稀疏效果还不如规则路由。所以我给自己的原则是先用规则跑通闭环再逐步引入数据驱动。2.2 分层架构接入层、决策层、执行层、观测层最终落地的架构分四层我用一张表把每层的职责和选型说清楚层级核心职责我的选型选型理由接入层统一API、鉴权、限流自建HTTP服务需要自定义请求头传递路由偏好决策层特征提取、模型打分、路由规则引擎轻量打分模型规则可解释打分模型处理模糊场景执行层模型调用、重试、降级异步调用池支持并发、超时控制、熔断观测层成本/延迟/质量采集时序库看板三透明的基础这里重点说下为什么决策层要规则打分混合。纯规则的问题是边界太硬比如prompt超过500字就走大模型这条规则遇到一个520字但其实是简单格式化的请求就会误判。而纯打分模型的问题是冷启动阶段没有足够标注数据容易乱选。我的做法是规则先做粗筛把明显该走小模型或明显该走大模型的请求分流剩下的模糊地带交给一个逻辑回归打分模型特征就是prompt长度、任务标签、历史同类请求的最优模型等。2.3 模型分级不是越贵越好而是越合适越好搭网关之前我先把手头的模型做了一次分级。分级维度有三个能力档位、单价档位、延迟档位。注意这三个维度并不总是正相关——有些模型能力强但延迟高有些模型便宜但延迟也低适合做兜底。我最终把模型分成三档轻量档负责分类、抽取、改写、格式化、简单问答。特点是单价低、延迟低能力上限有限。标准档负责常规多轮对话、中等复杂度推理、内容生成。性价比最高是主力。旗舰档负责复杂推理、长文分析、代码生成、需要高准确率的场景。单价最高延迟也最高。分级不是拍脑袋定的我用了两周时间做离线评测从历史请求里采样500条人工标注可接受的最低档位然后让三档模型分别跑一遍对比质量和成本。结果发现有相当比例的请求轻量档的质量已经够用只是之前没人去验证。这里有个经验够用的标准要业务方来定不能技术自己拍。我当时的做法是拉上产品和运营一起看采样结果明确哪些场景允许轻量档、哪些必须旗舰档。这个共识一旦建立后面路由策略就好定了。3. 核心细节解析路由策略、成本核算与质量兜底3.1 路由策略怎么定三个必须回答的问题路由策略的本质是回答三个问题这个请求是什么类型当前哪个模型最合适如果它挂了怎么办第一个问题靠特征提取。我提取的特征分三类文本特征prompt长度、是否含代码块、是否含多轮历史、语言。任务特征调用方传入的task_type标签这个必须要求业务方传不能靠猜。上下文特征用户等级、当前时段、历史偏好。第二个问题靠打分。我给每个候选模型算一个综合分score w1 * 质量预期 - w2 * 归一化成本 - w3 * 归一化延迟权重w1、w2、w3是可调的。比如在成本敏感期把w2调大在体验优先期把w1调大。这个设计的好处是调参不用改代码改配置就行。第三个问题靠降级链。每个档位都配一条降级链比如旗舰档挂了降标准档标准档挂了降轻量档。降级链要设最大重试次数和总超时预算否则一个请求可能在多个模型间来回跳把延迟拖爆。3.2 成本核算把每次调用花了多少钱算清楚成本透明是这套网关最让我有成就感的部分。之前用单一模型时月底看账单只知道总数不知道钱花在哪。现在每次调用都会记录模型名、输入token数、输出token数、单价、本次成本。这里有个细节不同模型的计费方式不一样有的按输入输出分开计价有的有阶梯价有的对缓存命中打折。我在网关里做了一个计费适配层把各家计费规则抽象成统一接口这样上层看板拿到的成本数据是可比的。成本数据采集上来后我做了两个维度的聚合按任务类型看哪类任务最烧钱是不是有优化空间。按调用方看哪个业务线用量最大方便做成本分摊。实测下来这个看板帮我们发现了几个成本黑洞有个业务线在做批量数据清洗时误用了旗舰档模型单这一项就占了总成本的相当比例。切到轻量档后质量没明显下降成本直接降了一个数量级。3.3 延迟监控P99才是真相延迟这块我踩过一个坑一开始只看平均延迟觉得一切正常。后来有用户投诉偶尔特别慢一查P99发现长尾延迟高得吓人。原因有两个一是某些复杂请求本身耗时就长二是模型服务偶发的排队。平均延迟把这些长尾平均掉了看起来很美。所以我的监控体系里P50、P95、P99三个分位数都要看而且按模型、按任务类型分别统计。P99高的模型要么优化要么在路由时降权。另外网关自身也要监控路由决策耗时。如果决策逻辑太重光路由就花了几百毫秒那就本末倒置了。我的目标是路由决策控制在10毫秒以内实测基本在3-5毫秒。3.4 质量兜底怎么知道模型答得好不好质量是最难量化的。成本能算延迟能测但这个回答好不好很主观。我的做法是分层兜底第一层格式校验。比如要求返回JSON的解析失败直接判为不合格触发重试或降级。第二层规则校验。比如分类任务返回的类别必须在预设枚举里。第三层抽样人工评估。每天抽1%的请求由标注同学打分作为质量基线。第四层用户反馈。把点赞点踩接进来作为长期优化信号。这四层里前两层是自动的、实时的后两层是抽样的、离线的。自动兜底保证不出大错离线评估指导长期优化。提醒一句质量兜底不要追求100%自动化。我试过用另一个模型来给回答打分结果发现裁判模型本身也有偏见打分结果不稳定。最后还是回归到规则人工抽样的组合反而更靠谱。4. 实操过程从零把网关跑起来4.1 环境准备与基础服务搭建动手之前先把基础环境理清楚。我的部署环境是一台4核8G的云主机跑网关服务本身绰绰有余因为网关是IO密集型不占CPU。真正吃资源的是并发调用时的连接池。基础服务清单网关服务Python FastAPI异步框架天然适合IO密集场景。配置中心用文件热加载简单场景没必要上重型配置中心。时序数据库存成本和延迟指标选轻量的即可。看板Grafana接时序库出图。依赖安装很直接pip install fastapi uvicorn httpx pydantic pip install prometheus-client这里我特意用httpx而不是requests因为前者支持异步能在单进程里扛住更高并发。实测下来同样配置下异步方案的吞吐是同步的三倍左右。4.2 请求接入与特征提取的实现接入层的核心是一个统一的/v1/chat接口。请求体里除了常规的messages我额外要求传两个字段task_type和quality_level。前者告诉网关这是什么任务后者告诉网关业务方对质量的要求档位。特征提取函数大概长这样def extract_features(request): prompt .join(m[content] for m in request.messages) return { length: len(prompt), has_code: in prompt, turn_count: len(request.messages), task_type: request.task_type, quality_level: request.quality_level, }别小看这个函数它是整个路由的输入。我一开始想加更多特征比如情感分析、主题分类后来发现特征越多维护成本越高收益却递减。最后就保留了这几个最稳定、最可解释的。4.3 路由决策引擎的落地路由决策分两步先按quality_level和task_type做粗筛得到候选模型列表再对候选模型打分选最高分。粗筛规则我用配置表管理task_typequality_level候选档位classifyany轻量档extractany轻量档chatlow轻量档、标准档chathigh标准档、旗舰档reasonhigh旗舰档codehigh旗舰档、标准档打分环节我用了最简单的加权和。权重存在配置里可以随时调。这里的关键是归一化成本和延迟量纲不同必须先归一化到0-1区间再加权否则权重的物理意义就乱了。def score(model, features, weights): q model.quality_score # 0-1 c normalize(model.cost, min_cost, max_cost) l normalize(model.latency, min_lat, max_lat) return weights[q] * q - weights[c] * c - weights[l] * l4.4 调用执行与降级链的实现执行层我用了一个异步调用池每个模型一个信号量控制并发。调用时设两个超时单次调用超时和总预算超时。单次超时到了就换下一个模型总预算到了就直接返回兜底结果。降级链的实现要点每次降级都要记录方便事后分析为什么降级了。降级不能无限循环设最大跳数我设的是3。降级后的结果要标记来源让业务方知道这次是降级服务。async def call_with_fallback(candidates, request, budget_ms): start time.time() for model in candidates: if (time.time() - start) * 1000 budget_ms: break try: return await call_model(model, request) except (TimeoutError, ModelError): continue return fallback_response()4.5 指标采集与看板搭建指标采集我用的是Prometheus客户端每次调用后打点。核心指标gateway_request_cost本次调用成本gateway_request_latency本次调用延迟gateway_route_decision_ms路由决策耗时gateway_fallback_total降级次数看板上我重点看三张图成本趋势图按天、按任务类型、延迟分位图P50/P95/P99、降级率图。这三张图基本能反映网关的健康状况。实操心得看板不要堆太多图三到五张核心图足够。图太多反而没人看。我一开始搞了十几张后来砍到四张团队反而天天盯着看。5. 常见问题与排查技巧实录5.1 路由抖动同一个请求一会儿走这、一会儿走那这是我最开始遇到的头号问题。表现是同样的prompt连续调用几次走的模型不一样。原因是打分模型对微小特征变化太敏感加上各模型的实时延迟波动导致分数频繁翻转。解决办法是加滞后机制给每个模型维护一个当前偏好分新算出的分数要和偏好分做加权平均而不是直接替换。这样分数变化平滑了路由就稳定了。另外对同一会话的连续请求可以加会话粘性尽量走同一个模型避免上下文切换带来的体验割裂。5.2 成本统计对不上账有段时间我发现网关统计的成本和实际账单差了几个百分点。排查后发现两个原因一是缓存命中的请求实际没产生费用但网关按全价算了二是流式响应的token计数我一开始按字符数估算误差较大。修复方案缓存命中单独标记成本记为零流式响应用官方返回的usage字段不自己估算。改完之后误差控制在了可接受范围内。5.3 降级链把延迟拖爆前面提过降级链如果没设总预算一个请求可能在多个模型间跳来跳去。我遇到过一次极端情况一个请求连续降级三次总耗时超过20秒用户早就超时了。修复方案就是前面说的总预算超时。我的设置是总预算不超过业务方要求的超时时间的80%留20%给网络和序列化开销。5.4 常见问题速查表现象可能原因排查方向解决手段路由抖动打分敏感、延迟波动看路由日志的分数变化加滞后机制、会话粘性成本对不上缓存未标记、流式估算对比网关与账单明细缓存记零、用官方usage延迟飙升降级链过长看单请求的模型跳转记录设总预算超时质量下降路由过于偏向低成本看各档位质量抽样分调高质量权重某模型频繁失败该模型服务异常看单模型错误率临时从候选池摘除5.5 几个我踩过的坑坑一特征提取里做了太多字符串操作。一开始我在特征提取里做了正则匹配、关键词统计结果这个函数成了性能瓶颈。后来精简到只做长度和简单判断性能立刻上来了。特征提取要快不能成为路由的负担。坑二权重调参没有版本管理。有次调完权重忘了记录后来效果变差想回滚发现不知道之前的值是多少。现在我所有配置都进版本控制每次调整都写清楚原因。坑三忽略了冷启动。新接入一个模型时它的历史延迟和成本数据是空的打分时容易被打高分或低分。我的做法是给新模型一个观察期期间用保守的默认值积累够数据后再参与正常打分。坑四质量兜底规则太严。有段时间格式校验规则定得太死导致大量本来合格的回答被判不合格触发不必要的重试成本反而上升。后来放宽了规则只校验关键字段问题就解决了。6. 三透明之后我实际收获了什么搭完这套网关跑了一个季度最直观的变化是成本降了大约六成而用户侧的质量投诉没有增加。延迟方面P99从原来的6秒多降到了2秒出头因为大量简单请求被分流到了低延迟模型。但比数字更有价值的是决策方式的改变。以前讨论要不要换个模型全靠感觉和厂商宣传现在有了成本、延迟、质量三张表讨论变成了这个任务切到轻量档质量抽样分从4.2降到3.9成本降70%能不能接受。这种基于数据的对话效率高太多了。如果让我给想动手的朋友一句建议别一上来就追求完美路由。先用最简单的规则把闭环跑通让数据流起来再逐步优化。我见过太多团队卡在设计一个完美路由算法上结果半年都没上线。先跑起来比什么都重要。另外网关这东西是活的模型在变、业务在变、成本结构也在变。我现在保持每个月复盘一次路由策略的习惯看看权重要不要调、候选池要不要更新。它不是一次性的项目而是一个需要持续运营的系统。