多目标路由与故障转移
多目标模型使用一个面向调用方的别名承载多个目标模型。AISIX 为每个请求选择目标、重试符合条件的失败,并且可以在不要求应用更改模型名称的情况下执行故障转移。
该别名是面向调用方的模型名称,因此对于有权请求它的每个调用方 API Key,它都会显示在 GET /v1/models 中。将某个 Key 的作用域仅限定到该别名,即可把它作为调用方发现的唯一入口发布;此后可以更改别名的目标,而无需修改应用。
多目标模型包含 routing 块,而不是自身的服务提供方配置。每个目标都是一个已有的直接模型,具有自己的服务提供方密钥和上游模型名称。AISIX Cloud 通过模型 ID 引用这些目标,开源 AISIX 网关则在声明式资源文件中通过 display_name 引用它们。
路由模型选择一个直接目标,再由该目标使用自己的服务提供方密钥调用上游模型:
选择策略
请根据面向调用方的别名应如何分发流量来选择策略:
| 目标 | 策略 | 选择行为 |
|---|---|---|
| 保留一个主要目标和有序备用目标。 | failover | 按声明顺序尝试目标。 |
| 在相似目标之间轮转流量,可按比例分配。 | round_robin | 按目标 weight 做平滑加权轮询;权重相等或缺省时按声明顺序轮换。 |
| 将每个会话固定到同一目标。 | consistent_hash | 在加权哈希环上对每个请求的键做哈希,让相同键持续命中同一个健康目标。weight 改变的是哈希键的近似份额,而不是固定的请求百分比。适用于 A/B 测试和灰度发布以及会话亲和 + 池间故障转移。 |
| 优先选择预估价格最低的目标。 | least_cost | 按配置价格或 AISIX Cloud 目录定价对符合条件的目标排序。 |
| 优先选择近期观测到的最快目标。 | least_latency | 按近期上游延迟排序。 |
| 优先选择加权并发数最低的目标。 | least_busy | 按 (1 + 当前进行中的请求数) / max(weight, 1) 对符合条件的目标排序,数值最低者优先。 |
failover 是省略 strategy 时的默认值。你也可以使用路由标签按请求缩小符合条件的目标范围。
每种策略都支持以下两个目标级属性:
weight(默认1)在使用它的策略下决定目标的份额:round_robin的轮转份额、consistent_hash的哈希环份额、least_busy的并发折算系数。failover、least_cost和least_latency接受该字段但不使用。priority(默认0)将符合条件的目标划分为层级——数值越大越优先,因此给备用目标配置-1。策略在每层内部对目标排序,只有当没有更高层目标可用时,较低层才会接收流量。请参阅会话绑定与池间故障转移。
AISIX 会先应用路由标签和 allowed_cidrs 过滤,再把剩余目标划分到各优先级层。因此,如果某个健康的高优先级目标因其中任一过滤条件而不适用于当前请求,较低优先级目标仍可为该请求提供服务。
AISIX 会在可重试的上游失败上执行重试和故障转移,例如 5xx 响应、请求超时和传输错误。大多数上游 4xx 响应会直接返回调用方。启用 retry_on_429 可处理上游限流,配置 fallback_on_statuses 可处理其他服务提供方特定的临时状态码。
AISIX 也会跳过超过自身模型限流的目标。它会将被跳过的目标记录为一次失败的 429 路由尝试,并按策略顺序继续尝试其余目标,不会重试该目标。当所有目标都超过限额时,请求返回 429。
如果目标自身的 allowed_cidrs 排除了调用方,该目标同样不会成为候选项。此检查在策略选择前执行,因此不会尝试该目标,也不会消耗 max_fallbacks 预算。当所有目标都排除调用方时,请求返回 403。
支持的端点
调用方可以在以下端点上请求 多目标模型。每个端点都会按本页所述的策略、重试、故障转移和运行时过滤逐个尝试目标:
/v1/chat/completions、/v1/messages、/v1/messages/count_tokens和/v1/responses。/v1/completions、/v1/embeddings、/v1/rerank、/v1/systemone、/v1/decisions、/v1/images/generations、/v1/images/edits、/v1/audio/transcriptions、/v1/audio/translations、/v1/audio/speech,以及POST /v1/videos提交。
/v1/realtime 以及 Files、Batches 和 Fine-tuning API 要求使用直接模型,会拒绝多目标模型,因为会话或服务提供方签发的 ID 必须始终留在同一个服务提供方上。
在第二组端点上,每个目标都必须能够处理该端点。端点无法处理的目标会像不可重试的失败一样结束请求,AISIX 不会转而尝试下一个目标;只有可重试的上游失败才会触发故障转移。/v1/rerank、/v1/images/generations、/v1/images/edits 和决策端点返回 400,错误信息会同时写出多目标模型和目标,例如 model `my-group` (target `claude-img`) is not an OpenAI provider。当目标的服务提供方缺少对应能力时,/v1/completions、/v1/embeddings、/v1/images/generations 和 /v1/videos 返回 501。这两种响应都应视为该组的配置错误。/v1/messages/count_tokens 是例外:它会跳过无法处理的目标,继续尝试下一个目标。
这些端点记录多目标请求的方式与 Chat Completions 相同:
- 每次上游尝试都会产生自己的用量事件,包括导致重试或故障转移的失败尝试。失败尝试的 Token 数为零,且不计费。给出响应的那次尝试的事件会写明实际提供服务的目标,计价也按该目标而不是按组进行。
- 部署与回退指标以及访问日志中的路由字段覆盖这些端点。
least_latency和least_busy会从这些端点的流量中学习。对于语音合成和流式转写,least_latency测量的是到上游响应头的时间,而在中继的流结束之前,该目标在least_busy中一直计为忙碌。
通过多目标模型提交的视频会始终留在接受该任务的服务提供方上:返回的视频 ID 标识了该目标,因此 GET /v1/videos/{video_id} 及其 /content 路由会到达同一个服务提供方,状态响应中回显的是提交时使用的多目标模型名称。上游已经应答之后才失败的提交永远不会重放,无论是在同一目标还是下一个目标上,因为付费任务可能已经创建。
/v1/responses 对话会留在产出其上下文的目标上。AISIX 会在返回的推理 encrypted_content 和响应 id 上标记处理该请求的目标,并把携带它们的后续轮次优先发回该目标,或同一服务提供方密钥上的其他目标,不按策略顺序。参见在多目标模型上保持对话上下文。
配置并测试故障转移模型
以下示例会构建并测试一个双目标模型:优先使用 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 网关
将两个模型服务提供方 Key、对应的直接模型以及 chat-prod 路由模型添加到完整资源文件。将两个 Key 分开可以只测试其中一个目标,而不影响另一个:
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 添加到调用方 Key 的 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 作为面向调用方的模型名称。该响应头标识实际处理请求的直接模型;缓存命中、单目标模型响应、错误响应或部分端点族不会包含它。
流式请求可以解析多目标别名,但流已经开始后不会再执行故障转移。