在 Microsoft Foundry 中用 Model Router 构建成本感知的 LLM 工作负载
前段时间在整理自家 GenAI 平台的模型调度方案,我又把 Microsoft Foundry 的 Model Router 翻出来仔细看了一遍。以前"这个请求该走哪个模型"是塞在应用代码里的一堆 if-else,现在它能被挪到平台层统一管起来。这篇就把我看下来的心得和踩过的点记一记,原文在这儿:Architecting Cost-Aware LLM Workloads with Model Router in Microsoft Foundry。
我最在意的其实就一件事:把多模型路由收进一个能被治理的部署里。故障转移它自己扛,数据驻留边界它帮你守住,18 个底层 LLM 之间该怎么在成本和质量之间权衡,也是按每一条 prompt 现算的。
架构上的真问题
GenAI 平台只要一复杂,你手里迟早会同时养着一堆模型。分类和闲聊用便宜的,多步任务交给推理模型,真正的硬骨头才上前沿模型,另外还有一票专门啃代码、图像、长上下文的。
所以难点压根不是"哪个模型最强"。是怎么在上了规模之后,还能给每个请求都派对模型,同时治理和可观测性一样都不丢。
常见的几种做法我大多试过,各有各的坑:
| 模式 | 权衡 |
|---|---|
| 单模型部署 | 简单 prompt 上花冤枉钱,复杂 prompt 上又力不从心 |
| 应用层路由(规则/分类器) | 脆弱,模型一迭代就得重新调 |
| LLM 当路由 | 多一次调用跳转,治理更复杂,还多了自己那份失败模式 |
| 按用例分别部署 | 部署面爆炸,配额和成本报表被切得七零八落 |
Microsoft Foundry 的 Model Router 给的是一个平台级答案:一个训练好的路由模型,以单一端点部署,按每条 prompt 在最多 18 个底层 LLM 之间做分派。
概念上的架构
有个设计细节得先讲明白:做路由决策的是一个训练出来的模型,不是写死的规则引擎。它看的是 prompt 本身,也就是复杂度、任务类型、要不要推理这些,而且 Microsoft 每接入一批新的底层模型,它也会跟着更新。
哪些归平台管,哪些归你管
对做架构的人来说,这个职责划分才是关键的心智模型。
平台负责的
-
实时 prompt 分析和路由决策
-
子集内的自动故障转移
-
数据驻留边界的强制
-
向支持的模型透传 prompt 缓存
-
底层模型的版本管理(通过路由器版本控制)
你负责的
-
路由模式:Balanced(默认)、Quality 还是 Cost
-
模型子集,也就是允许路由器碰的那批底层模型
-
部署类型:Global Standard 或 Data Zone Standard
-
区域,眼下就 East US 2 和 Sweden Central 两个可选
-
可观测性挂钩,把
response.model记下来,方便后面按请求做归因
把路由模式当成设计杠杆
| 模式 | 质量带 | 什么时候用 |
|---|---|---|
| Balanced(默认) | 顶级模型的 ~1–2% 以内 | 通用对话和 agent 场景 |
| Quality | 始终用顶级模型 | 受监管的输出、复杂推理、关键文档的 RAG |
| Cost | ~5–6% 带宽 | 大批量分类、草稿生成、低风险对话 |
我更愿意把路由模式看成一个部署级的 SLO 杠杆。不同的产品面可以指向不同的 Model Router 部署,各自配不同的模式和子集。
模型子集:你真正的治理面
这个特性我觉得最值得花心思。一份子集列表,其实一口气定死了好几件事:
-
合规:你的 prompt 到底能落到哪些厂商、哪些区域
-
上下文窗口:有效上下文等于子集里最小的那个模型,所以别乱塞
-
成本上限:最坏情况下单次调用能烧多少钱,被这份名单框住了
-
故障转移池:每个子集至少留两个模型,好歹有个备份
-
缓存命中率:子集越窄越确定,连续重叠的 prompt 越容易落回同一个底层模型
还有一点,以后路由器版本里新加的模型不会自动塞进你的子集。这是故意留的一道闸,想用就得自己动手改部署。
代码:用自定义子集部署
Model Router 的部署方式和 Foundry 里任何模型一样。下面是一段示意性的 ARM/Bicep 风格部署片段,设成 Balanced 模式,并把路由限制在一个精心挑选的子集里——省掉 subset 就等于接受完整的默认池。
|
|
具体 schema 建议对着当前的 Foundry 部署 API 再核一遍——参数名在不同 API 版本之间是会变的。
通过 Foundry 门户部署
如果你比起 IaC 更喜欢用门户,流程也很短:
-
登录 Microsoft Foundry,确认 New Foundry 开关是开着的。
-
打开模型目录,找到 model-router 并选中它。
-
选 Default settings 就是对所有支持的模型走 Balanced 模式;选 Custom settings 则可以挑路由模式和模型子集。
-
在 model router 这个部署层面套一个内容过滤器——它会覆盖所有底层模型。别去给单个模型单独设内容过滤器。
-
TPM 速率限制也设在 model router 层面——它对进出路由器的所有活动生效。别给单个底层模型单独设速率限制。
-
(仅 Claude)在把 Claude 模型加进子集之前,先单独从目录里部署它们。其它厂商的模型是透明调用的。
传播延迟提醒一下:路由模式或模型子集的改动,最多可能要五分钟才生效。做灰度和测试的时候要把这个算进去。
代码:调用端点(Python)
部署完成后,Model Router 就是一个标准的 chat-completions 端点。记得每次都抓一下 response.model——这是你做成本分析和路由验证时,每个请求的归因依据。
|
|
代码:流式响应
流式和任何 Azure OpenAI chat 部署完全一样。路由决策发生在第一个 token 之前;一旦选定,底层模型就直接开始流式输出。
|
|
代码:工具调用(agentic 场景)
2025-11-18 这个版本加入了工具调用支持,这样 Model Router 就能用在 Foundry Agent Service 里。路由器会按每一轮挑合适的模型——琐碎的轮次用便宜的,多步的轮次上推理级的。
|
|
这里有个 Agent Service 的注意点:如果你的 agent 流程用到了 Foundry Agent Service 的工具,路由就只会限制在 OpenAI 模型里。当路由器坐在依赖这些工具的 agent 流程后面时,子集要照着这个规则来规划。
代码:另一条路——Foundry Responses SDK
如果你打算标准化到 Microsoft Foundry SDK 而不是 OpenAI Python SDK,Responses API 提供了一条等价的路径。安装:pip install azure-ai-projects>=2.0.0 azure-identity。
|
|
选中推理模型时的参数处理
因为 Model Router 既可能派到 chat 模型,也可能派到推理(o 系列)模型,参数的行为会随实际选中的模型而变。我的建议是,把应用围绕两种行为的并集来写。
-
Temperature、Top_P:一旦派到 o 系列推理模型就被忽略,其它模型照常生效。
-
stop、presence_penalty、frequency_penalty、logit_bias、logprobs:o 系列会直接丢掉,其它模型照常生效。
-
reasoning_effort:从 2025-11-18 这个路由器版本才开始支持。派到推理模型时,你传的值会被原样透传下去。
我自己遵守的一条实操规则:在路由器前置的部署里,别指望靠 temperature/top-p 来拿确定性;把 reasoning_effort 当成唯一一个在推理和非推理路径上都有一致含义的旋钮。
响应体长什么样
JSON 结构和标准的 chat completion 一模一样。model 字段是关键信号——它告诉你实际是哪个底层模型服务了这次请求。usage 块里还能看到 cached_tokens(prompt 缓存命中)和 reasoning_tokens(o 系列模型处理 prompt 时)。
|
|
在 Azure 门户里做监控
性能指标:
-
打开 Azure 门户,进到你的 Azure OpenAI / Foundry 资源的 Monitoring → Metrics。
-
按你的 model router 部署名筛选。
-
按底层模型拆分指标,就能看到流量实际是怎么在被路由的模型之间分布的。
成本归因:
-
打开 Azure 门户里的 Resource Management → Cost analysis。
-
按 Tag 筛选,把 tag 类型设为 Deployment,选你的 model router 部署名。
-
总成本 = 命中这个部署的请求所对应的底层模型费用之和。
我总结了三条实操建议:
-
每次调用都记
response.model。这是你在应用侧看路由分布和做每个请求归因的首要信号。 -
别指望账单是单一模型的。Model Router 是按服务该请求的底层模型的费率计费的。拿 Azure Cost analysis 和你的应用日志对一对。
-
盯着每个底层模型的缓存命中率。缓存收益只在连续重叠的 prompt 落到同一个模型时才有。子集设得太宽松,会悄悄拖垮缓存效率。
需要提前设计防御的失败模式
-
上下文窗口溢出。有效上下文是子集里最小的那个模型。一条超大 prompt 进来,除非被路由到上下文更大的模型,否则就会失败。防御办法是精挑子集,或者在上游做摘要/截断。
-
Claude 模型没走路由。Claude 需要先单独从目录部署。可以暴露一个部署健康检查。
-
区域/部署类型不匹配。目前只有 East US 2 和 Sweden Central,也只有 Global Standard 和 Data Zone Standard。灾备要照这个来规划。
-
速率限制。Global Standard 默认 250 RPM / 250K TPM;Enterprise/MCA-E 更高。要早点把背压做进去。
-
不支持音频。图片可以接受,但路由决策只看文本。
常见问题速查
| 问题 | 可能原因 | 处理 |
|---|---|---|
| 触发速率限制 | 对路由器部署的请求太多 | 提高 TPM 配额,或用指数退避重试 |
| 模型选择出乎意料 | 路由逻辑选了跟预期不同的模型 | 检查路由模式;用模型子集去约束 |
| 高延迟 | 路由器开销加上底层模型处理 | 对延迟敏感的负载用 Cost 模式;小模型响应更快 |
| Claude 模型没走路由 | Claude 需要单独从目录部署 | 加进子集前先从目录部署 Claude 模型 |
| 上下文超限 | 有效上下文 = 子集里最小的模型 | 把子集调整为上下文更大的模型,或在上游摘要/截断 |
什么时候 Model Router 是对的架构选择
比较契合的场景:
-
异构流量,prompt 复杂度跨度很大
-
想把多厂商 LLM 策略(OpenAI + Anthropic + 开源模型)收敛到一个受治理的单一端点后面
-
agent 平台,任务从琐碎一路跨到复杂推理
不太契合的场景:
-
均质负载,选一个合适的单模型反而更省事
-
以大上下文 prompt 为主的负载(除非子集是专门为它挑的)
-
需要每个请求都确定、可复现地落到同一个模型的场景,因为路由器本来就是设计成自适应的
我推荐的落地路径
-
先打基线。用 Balanced 模式配上完整池把 Model Router 跑起来,拿有代表性的真实流量,把
response.model完整记上一段时间。 -
再上治理。等你摸清了合规、上下文、成本这几条线,再引入模型子集,记得每个子集至少留两个模型兜底。
-
然后调优。基线分布会告诉你该往成本还是质量偏,这时候再切 Cost 或 Quality,或者干脆按产品面拆成两个画像不同的部署。
-
最后做集成。把路由器接到 Foundry Agent Service 后面,扛起 agentic 那摊事。
一点收尾的想法
说到底,Model Router 把"多模型分派"这件本来堆在应用层的糟心事,挪成了平台层的事。它给你的那几个旋钮(模式、子集、区域),又刚好对上架构师平时最头疼要来回权衡的几样:成本、质量、合规,还有扛不扛得住。生产环境里这块的复杂度常常超出预期,能这么被摁下去,我觉得是实打实有价值的。
示例仓库
Microsoft 在 foundry-samples 这个 GitHub 组织里放了几个开源示例,拿来上手评估很合适:
-
Model Router Capabilities Interactive Demo(Python)。对着你自己的 prompt 集比较 Balanced、Cost、Quality 三种路由模式;能看到成本节省、延迟和路由分布的实时基准数据。
-
Routed Models Distribution Analysis(Python)。在不同路由画像和模型子集下跑 prompt 批次,检查路由器选了哪些模型、各自占比多少——在敲定路由策略之前很有用。
-
Multi-team Quality & Cost Benchmarking(Python workshop)。部署 Model Router,对着固定模型部署做基准,在多团队企业场景里分析成本/延迟权衡。
-
On-Call Copilot Multi-Agent Demo(Python)。看 agent 流程里每一步的模型选择——分类用快而便宜的模型,根因分析上推理模型。
这些示例是给学习和实验用的。在把任何一部分改造进生产之前,先对照你所在组织的安全、合规和负责任 AI 政策审一遍。
延伸阅读
- 本文作者:BeanHsiang
- 本文链接:https://beanhsiang.github.io/post/2026-04-29-architecting-cost-aware-llm-workloads-with-model-router-in-microsoft-foundry/
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议. 进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。