# PiRouter 自定义服务商路由已上线：同一模型，工作区定规则、请求定偏好

> 同一个模型由多个平台提供时，先确认实际候选，再用工作区路由规则与单次请求的 provider 对象控制服务商选择。看懂 order、only、ignore、价格排序和 404/422/503 的边界。

- Published: 2026年10月9日
- Author: PiRouter Team, Engineering
- Tags: routing, providers, gateway
- Canonical: https://pirouter.ai/zh/blog/pirouter-custom-provider-routing

---
同一个模型如果在 PiRouter 上有多个服务平台，现在可以由工作区路由页设长期规则，也可以在单次 API 请求里加 `provider` 指定本次偏好。两者不是互相覆盖的万能开关：允许名单会收窄、排除名单会叠加，排序偏好则可以由本次请求改写。**这解决的是“从哪些现有候选里选、先选谁”，不是上游调用失败后的自动重试。**

过去，“用哪个模型”和“经由哪个平台调用”容易被压成一个选择。对需要固定供应渠道的团队，两件事并不相同：团队可以继续使用同一型号，却希望某个工作区只走批准的平台；另一次调用则可能希望在这些平台之内临时调整优先顺序。PiRouter 已上线的自定义服务商路由把这两个决定拆开，分别放在工作区规则和请求级偏好里。本文依据已上线版本的接口与规则说明，不代表对每一种协议、每一个型号都做过线上实测。

## 先查模型目录：这个型号真的有你想选的平台吗？

第一步不是填白名单，而是查候选。打开 [PiRouter 模型目录](https://pirouter.ai/models)，选定要调用的具体型号，看它当前由哪些平台提供；需要机器可读列表时，可查看公开的 [Models Catalog](https://api.pirouter.ai/v1/models/catalog)。`provider` 里填写的是**服务平台的名称**，不是模型发布方、某个地区，也不是一个具体部署资源的名字。比如平台 `azure` 或 `gcp` 是可理解的服务平台名；它们出现在配置示例中，不意味着它们一定同时提供你选中的型号。

目录显示的是“某平台有符合当前注册条件的部署”这一类候选事实，并非当下每个部署都健康的保证。模型、部署、资源等条件会影响目录中的服务平台集合；运行时健康状态又是下一道门。某平台在目录里，并不等于下一次请求一定由它接单。因此，先确认**型号与平台同时匹配**，再为这个型号制定规则。平台供给会变，截图和举例都不能替代发请求前的当前目录。

![PiRouter公开Sonnet 5.5模型页的服务商表，列出Anthropic和Microsoft Azure。](/blog/images/pirouter-custom-provider-routing-public-providers.png "公开模型页列出的服务商候选；这是目录信息，不证明上游失败会自动重试。来源：[PiRouter Sonnet 5.5 模型页](https://pirouter.ai/zh/models/anthropic/claude-sonnet-5.5)")

截图里的 Microsoft Azure 是展示名称，请求名单使用的是 `azure` 这样的平台标识；不要直接复制整段展示名称，也不要把模型发布方名称当作任意型号的可用平台。

## 工作区路由页：让长期规则不用写进每次请求

登录 [PiRouter 控制台](https://app.pirouter.ai/sign-in)，进入相应工作区的「路由」页面。工作区 owner 可以选择「均衡」「价格优先」「自定义顺序」，也可以维护「仅使用」和「不使用」的平台名单；设置变更会保存为该工作区的长期规则。成员可查看规则，但不能代 owner 改动。页面还有「验证」和「API」入口：前者检查当前规则，后者帮助理解请求格式。不要把「验证」误认为已经替你发了一次模型推理。

这张页面**不是八个 API 字段的持久化编辑器**。它聚焦排序、平台顺序和两张名单；诸如请求级数据政策、量化格式的字段属于接口合同，不是都能在页面上找到相应开关。工作区配置也不是某个成员的个人偏好，或每把 API Key 私有的一套名单：调用的 Key 归属工作区后，工作区规则才为这次路由划出边界。

假设团队只批准两个平台，工作区「仅使用」就能把其他平台排除在候选之外。这里的“假设”只是解释规则，不代表我们看过某客户的真实配置。反过来，如果团队只是更喜欢某个平台，却接受其他可用平台，那么应优先考虑顺序，而不是用白名单把路封死。偏好与硬限制写错位置，往往是随后出现 404 的起点。

## 一次请求的 `provider`：偏好可变，工作区边界不变

要为**一次**调用做不同选择，在 JSON 请求体的顶层添加 `provider` 对象，与 `model` 同级，而不是把它写进对话消息里。下面是结构示意，`your-model-slug` 是占位符，请先在公开目录替换为当前型号；无 Key、无真实工作区 ID，也不是可直接发送的完整请求：

```json
{
  "model": "your-model-slug",
  "messages": [{ "role": "user", "content": "Hello" }],
  "provider": {
    "order": ["azure", "gcp"],
    "only": ["azure", "gcp"],
    "ignore": [],
    "allow_fallbacks": false
  }
}
```

为了看清区别，可以把示例里的 `only` 去掉：保留非空 `order` 时，允许 fallback 表示仍可考虑顺序表外且通过工作区限制的候选；关闭它则把范围限制在顺序表内。这仍是候选选择，不是失败重试。

这里四个字段做的事不一样。`only` 是硬白名单：只考虑名单内的平台；`ignore` 是硬排除：即便某平台也在允许名单里，排除仍会生效。工作区已有 `only` 时，本次请求的 `only` 只能与它取**交集**；本次请求无法越过工作区许可多加一家。工作区的 `ignore` 与本次 `ignore` 取**并集**，所以请求也不能“取消”团队已经排除的平台。

`order` 则先谈**排序**，不是自动白名单。在默认允许后续候选的情况下，列表之外的平台仍可能排在后面被选中；工作区若选择价格优先，本次请求给出 `order` 或 `sort` 会把**排序方式**换成本次偏好，而非永久改写页面设置。尤其要注意示例里的 `allow_fallbacks: false`：它在有非空 `order` 时限制选择范围，只从顺序表中的平台挑候选。如果工作区已经禁用该选项，本次请求也不能重新打开。

这些话讨论的是**路由决策时是否让排序表之外的平台进入候选**。它们不是“上游已发出请求、报错后再试下一个平台”的开关。换句话说，`order` 指先看谁，`only` 决定谁有资格，`ignore` 决定谁被排除；`allow_fallbacks` 决定在非空顺序表下能否继续考虑表外候选。把这个词读成自动故障切换，会错误估算可用性。另一个常见误会是以为工作区顺序和本次 `order` 会自动拼接成一条更长的序列；实际请求级排序会替代工作区排序，名单边界却仍按前述规则合并。

![工作区规则与单次请求偏好合并：only取交集，ignore取并集，排序另行决定。](/blog/images/pirouter-custom-provider-routing-rules.png "工作区与请求两层规则的合并示意；平台名称是假设例子，不是某次生产调用或实时供给截图。")

如果团队工作区只允许 `azure`，而这次请求的 `only` 只写 `gcp`，最终交集为空。修改请求顺序不能解决问题：需要在获授权的工作区边界内重新选平台，或由 owner 调整工作区规则。若同一平台又被 `ignore` 排除，结果同样不会因为把它移到 `order` 第一位而恢复。把“选路偏好”和“准入条件”分开检查，调试才不会反复试无效顺序。

## 价格优先只是在候选内排序，不保证最低账单

工作区的「价格优先」以及请求里的 `"sort": "price"` 都是选路偏好，不能写成“每次保证实付最低”。路由首先要过型号是否被服务、团队与请求名单、协议及健康等门，之后才在合格候选里考虑排序。选了自定义顺序时，平台顺序也是排序依据；一个显式偏好并不神奇地扩大合格集合。

价格排序使用路由可见的文本单位价格信息，不是预知本次调用最终会产生多少输入、输出以及后续用量，更不是改写钱包的计费规则。要比较一次真实任务的最终花费，应先核对实际候选的公开价格，再用调用后的模型、用量与账单交叉核算；不能只看「价格优先」四个字推算节省比例。当前合同还接受请求级 `data_collection`、`zdr`、`quantizations` 等筛选字段，但这些会继续改变候选范围，并非“填得越多越稳”；写错字段也会被拒绝，而不是悄悄忽略。

同一套 `provider` 对象在已支持的三类入站协议中放置位置相同，**请求整体格式却不同**。例如，[Gemini generateContent 官方接口资料](https://ai.google.dev/api/generate-content)把模型写在 URL 路径、请求内容写在 JSON 体内；这里的 `provider` 是 PiRouter 的路由扩展，并非这份上游接口资料承诺的原生字段：

| 协议入口 | 模型位置 | 本次偏好的位置 |
|---|---|---|
| OpenAI 兼容 Chat Completions / Responses | JSON 顶层 `model` | JSON 顶层 `provider` |
| Anthropic Messages | JSON 顶层 `model` | JSON 顶层 `provider` |
| Gemini generateContent / streamGenerateContent | URL 中的模型路径 | JSON 顶层 `provider` |

这是一张**接口合同形态表**，不是声称我们此次逐协议发送过付费请求。尤其不要把上面的 Chat `messages` 示例原样搬进 Gemini 请求体，也不要把模型路径误当成 JSON 里的 `model`。如需完整鉴权、具体请求体与流式调用参数，还应按对应协议的正式接口资料准备；本篇无密钥示例只说明路由对象在哪里。请求级 `provider` 被 PiRouter 用于路由决策，转发到上游前会移除，不意味着可以省略 API 鉴权或跳过钱包计费。

## 404、422、503：先看是哪一道门挡住了请求

筛选越精确，越要能读懂失败。遇到错误，先看返回的错误码与信息，而不是把所有失败都重试一遍：

| 路由阶段返回 | 代表什么 | 优先检查 |
|---|---|---|
| 404 `no_eligible_provider` | 型号存在候选，但偏好筛到没有合格平台 | 核对当前型号在目录里的平台；检查工作区与请求的 `only` 交集、`ignore` 并集，以及非空 `order` 加 `allow_fallbacks: false` 的限定。`error.metadata` 的漏斗能提示筛空环节 |
| 422 `validation_failed` | 偏好字段、类型或平台名不合约；仅协议不匹配也可能属于此类 | 看报错字段，去掉尚未支持的字段或更正协议/平台名；不要假定未知字段会被忽略 |
| 503 `provider_unavailable` | 路由决策时没有当前可服务的健康候选等供给问题 | 确认目录候选与状态，检查是否暂时不可用；不要擅自放宽团队名单，也不要把它诊断为单纯拼写错误 |

这张表特指这里讨论的**路由决策阶段**：别的调用环节可能有自己的错误状态和修复方法。404 也须看具体 `code`，不是把所有 404 都当成名单筛空；422 要看验证信息，不能全归咎于协议。如果已在某个已允许平台上发生真正的上游调用失败，不能因为见到字段 `allow_fallbacks` 就推断系统会自动替你重发。后续遇到失败时，需要基于实际响应和你的应用重试策略处理，而不是从字段名字推测保障。

![路由决策阶段404、422、503的检查方向对照图。](/blog/images/pirouter-custom-provider-routing-errors.png "仅限路由决策阶段：先看具体错误码，再区分候选筛空、请求校验和供给问题；不是自动重试流程。")

路由阶段因偏好或校验拒绝的请求尚未走到上游调用与钱包预占；这不等于“配置好之后的 API 请求免费”。从 API 抽屉复制示例并补齐 Key 真正调用模型，仍会走正常鉴权、限额与计费路径。页面上的规则验证和实际发起推理，是两件费用含义不同的动作。

现在可以把流程压缩为三个判断：先在[模型目录](https://pirouter.ai/models)确认这个型号**当前**有哪些平台，再由工作区 owner 设团队长期边界，最后只在有必要时用请求顶层 `provider` 调整这一次的顺序或进一步收窄名单。若返回错误，先分清“规则筛空”“请求不合法”“供给暂不可用”，分别修；不要用更激进的重试去掩盖一个永远不会通过的筛选条件。要开始设置，可从[控制台登录入口](https://app.pirouter.ai/sign-in)进入自己的工作区。

---

## Sources

### ai.google.dev

- [Gemini generateContent 官方接口资料](https://ai.google.dev/api/generate-content)
