多目标路由与故障转移
多目标模型使用一个面向调用方的别名承载多个目标模型。AISIX 为每个请求选择目标、重试符合条件的失败,并且可以在不要求应用更改模型名称的情况下执行故障转移。
该别名是面向调用方的模型名称,因此对于有权请求它的每个调用方 API Key,它都会显示在 GET /v1/models 中。将某个 Key 的作用域仅限定到该别名,即可把它作为调用方发现的唯一入口发布;此后可以更改别名的目标,而无需修改应用。
多目标模型包含 routing 块,而不是自身的服务提供方配置。每个目标都是一个已有的直接模型,具有自己的服务提供方密钥和上游模型名称。AISIX Cloud 通过模型 ID 引用这些目标,开源 AISIX 网关则在声明式资源文件中通过 display_name 引用它们。
路由模型选择一个直接目标,再由该目标使用自己的服务提供方密钥调用上游模型:
选择策略
请根据面向调用方的别名应如何分发流量来选择策略:
| 目标 | 策略 | 选择行为 |
|---|---|---|
| 保留一个主要目标和有序备用目标。 | failover | 按声明顺序尝试目标。 |
| 在相似目标之间轮转流量。 | round_robin | 依次轮换符合条件的目标。 |
| 控制每个目标的流量比例。 | weighted | 按权重抽样目标。添加 sticky 可实现稳定的 A/B 测试或灰度发布分配。 |
| 优先选择预估价格最低的目标。 | least_cost | 按配置价格或 AISIX Cloud 目录定价对符合条件的目标排序。 |
| 优先选择近期观测到的最快目标。 | least_latency | 按近期上游延迟排序。 |
| 优先选择进行中请求最少的目标。 | least_busy | 按当前负载排序。 |
failover 是省略 strategy 时的默认值。你也可以使用路由标签按请求缩小符合条件的目标范围。
AISIX 会在可重试的上游失败上执行重试和故障转移,例如 5xx 响应、请求超时和传输错误。大多数上游 4xx 响应会直接返回调用方。启用 retry_on_429 可处理上游限流,配置 fallback_on_statuses 可处理其他服务提供方特定的临时状态码。
AISIX 也会跳过超过自身模型限流的目标。它会将被跳过的目标记录为一次失败的 429 路由尝试,并按策略顺序继续尝试其余目标,不会重试该目标。当所有目标都超过限额时,请求返回 429。
如果目标自身的 allowed_cidrs 排除了调用方,该目标同样不会成为候选项。此检查在策略选择前执行,因此不会尝试该目标,也不会消耗 max_fallbacks 预算。当所有目标都排除调用方时,请求返回 403。
配置并测试故障转移模型
以下示例会构建并测试一个双目标模型:优先使用 gpt-4o-primary,遇到符合条件的失败后改用 gpt-4o-secondary。本节同时提供 AISIX Cloud 和开源 AISIX 网关的操作说明。
准备工作
开始前,请准备以下资源:
- 两个或更多用作路由目标的直接模型。要执行故障测试,主要模型和备用模型必须使用不同的服务提供方密钥资源,但两个资源可以包含同一个上游凭据。
- 一个可以调用多目标模型的调用方 API Key,或创建该 Key 的权限。
- 用于执行 API 和验证命令的 cURL 和 jq。
- 对于 AISIX Cloud,需要一个已接入网关的环境,以及管理模型和调用方 API Key 的权限。
- 对于开源 AISIX 网关,需要有权访问声明式资源文件和网关进程。
创建模型
请先创建直接目标模型,再创建多目标模型。以下示例通过两种管理路径配置相同的故障转移行为:AISIX 先使用 gpt-4o-primary,在发生可重试失败后改用 gpt-4o-secondary。
AISIX Cloud
设置 AISIX Cloud 组织的控制面 URL、Admin Token 和环境 ID:
# AISIX_CP 是 Admin API 基础 URL;应包含 /api,且末尾不要带斜杠。
# 本地部署快速入门使用 http://localhost:8080/api。
export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL"
export AISIX_TOKEN="YOUR_ADMIN_TOKEN"
export ENV_ID="YOUR_ENVIRONMENT_ID"
导出直接目标模型的 ID:
export PRIMARY_MODEL_ID="YOUR_PRIMARY_MODEL_ID"
export SECONDARY_MODEL_ID="YOUR_SECONDARY_MODEL_ID"
创建一个故障转移模型:它会先从主要目标开始,再在失败时回退到备用目标。
ROUTING_MODEL_ID=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/models" \
-H "Authorization: Bearer $AISIX_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"kind": "routing",
"display_name": "chat-prod",
"routing": {
"strategy": "failover",
"targets": [
{"model_id": "'"$PRIMARY_MODEL_ID"'"},
{"model_id": "'"$SECONDARY_MODEL_ID"'"}
],
"retries": 1,
"max_fallbacks": 1,
"retry_on_429": true
}
}' | jq -r '.model.id')
使用该配置时,AISIX 会从 gpt-4o-primary 开始。如果该目标发生可重试失败,AISIX 可以先重试一次,然后故障转移一次到 gpt-4o-secondary。
使用获取的 ROUTING_MODEL_ID 授予调用方访问权限,并在以后更新、查看或删除该模型。如果已有调用方 API Key 需要使用 chat-prod,请把此 ID 添加到它的 allowed_models 列表。
为了快速验证,请创建一个只能调用 chat-prod 的调用方 API Key:
KEY_RESPONSE=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \
-H "Authorization: Bearer $AISIX_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"display_name": "routing-guide-caller",
"allowed_models": ["'"$ROUTING_MODEL_ID"'"]
}')
export AISIX_API_KEY=$(echo "$KEY_RESPONSE" | jq -r '.plaintext')
API_KEY_ID=$(echo "$KEY_RESPONSE" | jq -r '.api_key.id')
明文调用方密钥只返回一次。上述命令保存了它,供验证请求使用,并保存密钥 ID,供稍后更新允许列表。模型和调用方密钥配置会自动投射到已接入的网关。
开源 AISIX 网关
为两个直接目标声明不同的服务提供方密钥,再添加多目标模型。这两个密钥可以使用相同的上游凭据;将它们分开可以只测试其中一个目标,而不影响另一个。目标通过 display_name 引用直接模型:
_format_version: "1"
provider_keys:
- display_name: openai-primary
provider: openai
adapter: openai
api_key: ${OPENAI_API_KEY}
- display_name: openai-secondary
provider: openai
adapter: openai
api_key: ${OPENAI_API_KEY}
models:
- display_name: gpt-4o-primary
provider: openai
model_name: gpt-4o
provider_key: openai-primary
- display_name: gpt-4o-secondary
provider: openai
model_name: gpt-4o-mini
provider_key: openai-secondary
- display_name: chat-prod
routing:
strategy: failover
targets:
- model: gpt-4o-primary
- model: gpt-4o-secondary
retries: 1
max_fallbacks: 1
retry_on_429: true
完整资源文件中也必须存在直接模型引用的服务提供方密钥。将 chat-prod 添加到调用方密钥的 allowed_models,然后验证并重新加载该文件。
验证主要目标路由
导出所配置部署的网关 URL:
# 使用网关源地址,不要附加末尾斜杠或端点路径。
# 本地快速入门使用 http://127.0.0.1:3000。
export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL"
对于 AISIX Cloud,请继续使用先前创建的 AISIX_API_KEY。对于开源网关,请导出调用方 API Key:
export AISIX_API_KEY="YOUR_CALLER_API_KEY"
向多目标别名发送请求:
curl -sSi -X POST "$AISIX_PROXY/v1/chat/completions" \
-H "Authorization: Bearer ${AISIX_API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"model": "chat-prod",
"messages": [
{"role": "user", "content": "Hello from AISIX routing."}
]
}'
成功请求以 HTTP/1.1 200 OK 开头,并包含 x-aisix-served-by: gpt-4o-primary。响应体仍以 chat-prod 作为面向调用方的模型名称。该响应头标识实际处理请求的直接模型;缓存命中、单目标模型响应、错误响应或部分端点族不会包含它。
流式请求可以解析多目标别名,但流已经开始后不会再执行故障转移。
模拟主要目标失败
正常请求到达 gpt-4o-primary 后,让该目标变得不可访问,再重复请求。在此测试中,主要直接模型和备用直接模型必须使用不同的服务提供方密钥,这样修改主要端点时不会同时影响故障转移目标。
请为主要目标使用专用的非生产服务提供方密钥。在 AISIX Cloud 中,服务提供方密钥属于组织作用域,修改其端点会影响所有引用它的模型。
AISIX Cloud
导出仅由主要目标使用的服务提供方密钥 ID,再保存其当前端点:
export PRIMARY_PROVIDER_KEY_ID="YOUR_PRIMARY_PROVIDER_KEY_ID"
PRIMARY_API_BASE=$(curl -sS \
"$AISIX_CP/provider_keys/$PRIMARY_PROVIDER_KEY_ID" \
-H "Authorization: Bearer $AISIX_TOKEN" \
| jq -r '.provider_key.api_base // ""')
将该服务提供方密钥指向保留的、不可访问的域名:
curl -sS -X PATCH \
"$AISIX_CP/provider_keys/$PRIMARY_PROVIDER_KEY_ID" \
-H "Authorization: Bearer $AISIX_TOKEN" \
-H "Content-Type: application/json" \
-d '{"api_base":"https://api.openai.invalid/v1"}'
控制面会把更新投射到允许使用该服务提供方密钥的每个环境。发送测试请求前,请确认目标网关已经应用最新配置。有关控制面修订版本和网关状态检查,请参阅资源投射。