---
title: "Provider 路由"
description: "pirouter 默认在服务同一模型的多个 provider 之间按权重分配请求，失败时故障切换到下一个；工作区设置和请求里的 provider 对象可以改变顺序与范围。"
canonical: "https://pirouter.ai/zh/docs/guides/routing"
last-updated: "2026-10-17"
lang: "zh"
source: "content/docs/zh/guides/routing.mdx"
---

# Provider 路由

pirouter 默认在服务同一模型的多个 provider 之间按权重分配请求，失败时故障切换到下一个；工作区设置和请求里的 provider 对象可以改变顺序与范围。

不做任何设置时，pirouter 在能服务这个模型的 provider 之间按权重选一个，价格不参与排序；选中的 provider 失败时，自动换到下一个 provider（故障切换）。要改顺序或范围，在控制台给工作区设默认规则，或者在单个请求里加 `provider` 对象。

## 默认怎么选

没有任何设置时，pirouter 在能服务这个模型的 provider 之间按权重分配流量。价格不参与默认排序。

当前标记为不可用的 provider 不会被选中。

一个模型有哪些 provider，看模型页，或者调 `GET /v1/models/{vendor}/{model}/endpoints`，返回里每一条的 `provider` 就是下面各处要写的名字。

## 在工作区里设默认规则

在[控制台](https://app.pirouter.ai)打开 **路由** 页。只有工作区所有者能修改，其他成员可以查看。

| 设置       | 作用                                                                           |
| -------- | ---------------------------------------------------------------------------- |
| **排序**   | 同一模型有多个 provider 时先选哪一个：**均衡**、**价格优先** 或 **自定义顺序**                          |
| **仅使用**  | 只把请求发给这些 provider                                                            |
| **不使用**  | 永远不把请求发给这些 provider                                                          |
| **备用模型** | 请求的模型不可用时，按顺序改用这些模型，见[模型回退](https://pirouter.ai/zh/docs/guides/fallbacks.md) |

![控制台路由页：三个备用模型，provider 按自定义顺序排列，仅使用与不使用均未开启](/docs/shots/routing-page.zh.webp)

保存后，下一个请求就按新规则走。

## 按请求覆盖

在请求体的顶层加一个 `provider` 对象。pirouter 在 OpenAI、Anthropic、Gemini 三种协议的请求里都接受 `provider` 对象。

```bash
curl https://api.pirouter.ai/v1/chat/completions \
  -H "Authorization: Bearer $PIROUTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "anthropic/claude-opus-5.5",
    "messages": [{ "role": "user", "content": "Hello!" }],
    "provider": { "only": ["azure"] }
  }'
```

成功时返回 `200`，这个请求只会发给 `azure`。

| 字段                | 类型                   | 作用                                                    |
| ----------------- | -------------------- | ----------------------------------------------------- |
| `order`           | 字符串数组                | 按这个顺序优先尝试。没列出的 provider 排在后面，仍然会被尝试                   |
| `allow_fallbacks` | 布尔，默认 `true`         | 设为 `false` 并且写了 `order` 时，只有 `order` 里的 provider 可以服务 |
| `sort`            | `"price"`            | 按输入价加输出价从低到高排                                         |
| `only`            | 字符串数组                | 只用这些 provider                                         |
| `ignore`          | 字符串数组                | 不用这些 provider。和 `only` 冲突时以 `ignore` 为准               |
| `data_collection` | `"allow"` 或 `"deny"` | `"deny"` 排除会用你的数据训练、或没有声明是否训练的 provider               |
| `zdr`             | 布尔                   | `true` 只保留零数据留存的 provider                             |
| `quantizations`   | 字符串数组                | 只用这些量化精度的部署                                           |

### provider 的名字

名字不区分大小写。除了目录里的名字，还接受三个别名：`google-vertex`（即 `gcp`）、`google-ai-studio`（即 `gemini`）、`amazon-bedrock`（即 `aws`）。

不认识的名字返回 `422`，错误信息指出是哪个字段的第几项。在名字后面加 `/` 和区域的写法目前不支持，同样返回 `422`。

空数组和 `null` 都当作没有设置。`"only": []` 不表示一个 provider 都不许用。

### 顺序与价格

`order` 是偏好，不是白名单。要把请求限制在列出的几家，加上 `"allow_fallbacks": false`：

```json
{ "provider": { "order": ["anthropic", "azure"], "allow_fallbacks": false } }
```

`"sort": "price"` 比较的是输入价加输出价，取这个请求实际会被计费的那一档。和 `order` 一起用时，价格只在 `order` 的同一档内排序。`"throughput"` 和 `"latency"` 两种排序目前不支持，返回 `422`。

### 数据策略与量化

`"data_collection": "deny"` 排除两类 provider：会用提示词训练或没有声明的，以及数据留存既不是零数据留存也不是有限留存的。`"zdr": true` 更严，只保留零数据留存（ZDR）的 provider。

`quantizations` 可以写 `fp4`、`int4`、`int8`、`fp8`、`fp16`、`bf16`、`fp32`、`unknown`。设了之后，没有声明精度的部署也会被排除。

## 两层设置怎么合并

工作区设置和请求里的 `provider` 同时存在时：

- **限制只能收紧。** `only` 和 `quantizations` 取两层的交集，`ignore` 取并集。工作区设了 `data_collection` 为 `deny`、只用零数据留存的 provider，或关闭了回退，请求不能放宽。
- **排序整体替换。** 请求只要写了 `order` 或 `sort` 中的一个，工作区的排序方式就整个不生效。例如工作区设了自定义顺序，请求写 `"sort": "price"`，这个请求只按价格排。

## 没有可用的 provider 时

设置把所有 provider 都排除之后，请求返回 `404` 和错误码 `no_eligible_provider`。请求没有转发给任何 provider，不计费，见[失败的请求](https://pirouter.ai/zh/docs/guides/billing.md#失败的请求)。

```json
{
  "error": {
    "message": "No allowed provider can serve this model: the request's provider preferences, together with the workspace routing settings, exclude every provider that serves it. Providers serving it: anthropic, azure.",
    "type": "invalid_request_error",
    "code": "no_eligible_provider",
    "metadata": {
      "available_providers": ["anthropic", "azure"],
      "routing_funnel": [
        { "step": "initial", "providers": 2 },
        { "step": "data_policy", "providers": 2 },
        { "step": "quantization", "providers": 2 },
        { "step": "provider_ignore", "providers": 2 },
        { "step": "provider_only", "providers": 0 }
      ],
      "failed_step": "provider_only"
    }
  }
}
```

`metadata` 告诉你是哪一步排空的：

- `available_providers`：任何设置生效之前，服务这个模型的 provider。
- `routing_funnel`：每一步之后还剩几家。
- `failed_step`：把候选排空的那一步。

| `failed_step`       | 对应的设置                       |
| ------------------- | --------------------------- |
| `data_policy`       | `data_collection`、`zdr`     |
| `quantization`      | `quantizations`             |
| `provider_ignore`   | `ignore`，加上工作区的 **不使用**     |
| `provider_only`     | `only`，加上工作区的 **仅使用**       |
| `fallback_disabled` | `allow_fallbacks` 为 `false` |

这个错误和 `404 model_not_found` 不同：`model_not_found` 是模型名写错了，`no_eligible_provider` 是模型存在、但设置把 provider 排空了。

在选 provider 之前还有两项检查，同样不转发、不计费：模型不在你调用的端点上提供（`422 validation_failed`），以及输入的估算 token 数超过模型上下文上限的 1.25 倍（`400 context_length_exceeded`）。见[错误码](https://pirouter.ai/zh/docs/api/errors.md)。

## 故障切换

选中的 provider 在返回第一个字节之前失败时，pirouter 换下一个 provider 重试（故障切换），你不需要自己重试。

- **会换**：provider 返回 `429`、`500`、`502`、`503`，连接失败，或者 provider 拒绝了 pirouter 自己的凭证（`401`、`403`，这不是你的 key 的问题）。
- **不会换**：其他 `4xx`（例如请求参数错误、上下文超长）、超时，以及响应已经开始之后出的错。pirouter 自己按部署配额返回的 `429` 也不换，它在转发之前就返回，见[限流](https://pirouter.ai/zh/docs/api/rate-limits.md)。provider 沉默满 90 秒时响应就已开始，此后不再换。见[长请求](https://pirouter.ai/zh/docs/guides/timeouts.md#长请求)。
- 一个请求最多尝试 5 次，流式和非流式相同。
- 全部失败时，返回最后一次尝试的错误。两个例外：最后一次是 provider 拒绝 pirouter 的凭证（`401`、`403`）时，返回 `503` 和错误码 [`provider_unavailable`](https://pirouter.ai/zh/docs/api/errors.md#provider_unavailable)；下一次尝试被 pirouter 的限流拒绝时，返回 `429` 和错误码 `rate_limited`，带 `Retry-After` 响应头。

`"allow_fallbacks": false` 而没有写 `order` 时，重试只在第一次选中的那个 provider 内进行。

## 请求实际走了哪家

看响应头。由 provider 返回的响应带下面这些响应头，给 curl 加 `-i` 可以看到：

| 响应头                        | 内容                                                 |
| -------------------------- | -------------------------------------------------- |
| `X-Pi-Provider`            | 实际处理这个请求的 provider                                 |
| `X-Pi-Model`               | 实际处理这个请求的模型 ID，和响应体的 `model` 相同                    |
| `X-Pi-Upstream-Model`      | provider 自己报告的模型名                                  |
| `X-Pi-Upstream-Request-Id` | provider 自己的请求 ID，找 provider 排查时用；provider 没有提供时不带 |
| `X-Pi-Trace-Id`            | trace ID，每个响应都有，报障时带上它                             |

网关自己给出的错误（鉴权、余额、限流、参数校验、没有可用 provider）没有 provider 处理过，只带 `X-Pi-Trace-Id`。等 provider 开始返回超过 90 秒的请求也一样：它的响应头在 provider 返回之前就已发出。见[长请求](https://pirouter.ai/zh/docs/guides/timeouts.md#长请求)。

provider 拒绝 pirouter 凭证时返回的 `503 provider_unavailable` 是例外：它带 `X-Pi-Provider` 和 `X-Pi-Model`，指出是哪家 provider 拒绝的，但不带 `X-Pi-Upstream-Model` 和 `X-Pi-Upstream-Request-Id`。

发生过故障切换时，这些响应头说的是最后返回响应的那一次尝试。转发给了 provider 的请求，在控制台的 **日志** 里能按 `X-Pi-Trace-Id` 找到；网关自己拒绝的请求不进日志，见[请求日志](https://pirouter.ai/zh/docs/guides/logs.md#不在日志里的请求)。

## 写错了会怎样

`provider` 里的错误一律返回 `422` 和错误码 `validation_failed`，`message` 以 `Invalid provider preferences:` 开头，后面指出字段：

| 情况            | `message` 里的说明                              |
| ------------- | ------------------------------------------- |
| 不认识的键         | `provider: unrecognized key "foo"`          |
| 认识但还没实现的键     | `provider.max_price is not supported yet`   |
| 不认识的 provider | `provider.only[0]: unknown provider "nope"` |
| 类型不对          | `provider.zdr: must be a boolean`           |

## 目前没有的能力

- **用 API 读写工作区的路由设置。** 路由设置只能在控制台里改；API 能做的是在每个请求里带 `provider`。
- **按吞吐或延迟排序。** `sort` 只接受 `"price"`。
- **价格上限等其余字段。** `max_price`、`require_parameters`、`preferred_min_throughput`、`preferred_max_latency`、`enforce_distillable_text`、`options` 会返回 `422`。

## 下一步

- [模型回退](https://pirouter.ai/zh/docs/guides/fallbacks.md): 请求的模型不可用时，自动改用另一个模型。
- [API 参考](https://pirouter.ai/zh/docs/api/chat-completions.md#body): `provider` 对象在请求体里的完整定义。
