Portkey Gateway 配置实战:重试、Fallback 与多模型负载均衡一次讲清
【免费下载链接】gatewayA blazing fast AI Gateway with integrated guardrails. Route to 1,600+ LLMs, 50+ AI Guardrails with 1 fast & friendly API.项目地址: https://gitcode.com/GitHub_Trending/ga/gateway
线上聊天接口凌晨开始批量报错:OpenAI 侧返回429,请求堆积、超时,整条链路跟着雪崩。把 Portkey AI Gateway 插在你的应用和 LLM 之间,这类问题大多可以写成一段 JSON 配置交给网关处理:自动重试、多模型 fallback、按权重分流、缓存命中。本文所有配置项和默认值都能在本仓库源码里逐条对上,读完后你可以直接写出生产可用的 Gateway Config。
核心机制:一份 JSON 说了算
Portkey Gateway 对外暴露 OpenAI 兼容的 API,你的 SDK 调用不用改,改的只是流量走向。机制上它类似反向代理的配置文件:请求头里的x-portkey-config携带一段 JSON(UI 创建的配置则换成配置 ID),网关据此决定打给哪个 provider、失败后走哪条路。
没有网关时,重试循环、退避计时、模型切换都要写进业务代码,散落在各个 handler 里;有了网关,这些行为集中在一份声明式配置里,业务代码只发一次普通的chat.completions.create。
执行侧的逻辑在 src/handlers/retryHandler.ts:上游响应码命中可重试状态码时进入async-retry循环;其余错误码不重试,直接透传。两个默认值值得记住:
- 不写
on_status_codes时,网关按RETRY_STATUS_CODES = [429, 500, 502, 503, 504]重试(定义在 src/globals.ts) - 遇到
429且上游带retry-after/retry-after-ms/x-ms-retry-after-ms响应头时,网关按该值等待,但总等待预算上限是MAX_RETRY_LIMIT_MS = 60000,即 60 秒
实践:三个场景
场景一:单模型高可用——429 自动重试
上游限流是最常见的瞬时故障。把重试写成配置,而不是在业务代码里套 for 循环:
import { Portkey } from 'portkey-ai'; const portkey = new Portkey({ apiKey: 'your-api-key', virtualKey: 'your-virtual-key', config: JSON.stringify({ retry: { attempts: 3, on_status_codes: [429] } }) }); const response = await portkey.chat.completions.create({ messages: [{ role: 'user', content: '列出七大奇迹' }], model: 'gpt-4' });参数逐条看:
retry.attempts:最大重试次数,取值 1-5,5是上限MAX_RETRIESretry.on_status_codes:触发重试的状态码数组;省略时回落到默认五连[429, 500, 502, 503, 504]virtualKey:指向 Portkey 密钥库里的 provider 凭证,网关运行时替换真实 key,业务侧不暴露上游密钥
不引 SDK 也可以,等价写法是把配置塞进请求头,cookbook/getting-started/writing-your-first-gateway-config.md 里有完整示例:
const response = await fetch('https://your-gateway-host/v1/chat/completions', { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-portkey-api-key': 'your-api-key', 'x-portkey-provider': 'openai', 'x-portkey-config': JSON.stringify({ retry: { attempts: 3, on_status_codes: [429] } }) }, body: JSON.stringify({ model: 'gpt-4', messages }) });这里把provider和config拆成两个头,是因为网关的入站校验允许二选一:只要有x-portkey-config或x-portkey-provider之一即可放行(src/middlewares/requestValidator/index.ts)。
验证生效:成功响应会带回x-portkey-retry-attempt-count响应头,实际发生过的重试次数一目了然;再带上traceID请求参数,就能在 Dashboard 的 Logs 页按 trace ID 过滤出这条请求的每次尝试。
场景二:多模型互备——loadbalance 加嵌套 fallback
单点依赖某个 provider,它的限流窗口就是你的限流窗口。用strategy.mode: 'loadbalance'把流量按weight分到多个目标,再在目标内部挂一层fallback:
{ "strategy": { "mode": "loadbalance" }, "targets": [ { "virtual_key": "your-anthropic-vk", "weight": 0.5, "override_params": { "max_tokens": 200, "model": "claude-3-opus-20240229" } }, { "strategy": { "mode": "fallback" }, "targets": [ { "virtual_key": "your-openai-vk" }, { "virtual_key": "your-azure-openai-vk" } ], "weight": 0.5 } ] }- 顶层
strategy.mode: 'loadbalance':流量按各 target 的weight比例分流,0.5/0.5 即对半 - 内层
strategy.mode: 'fallback':OpenAI 先接,失败(命中其重试规则仍失败时)才落到 Azure OpenAI,嵌套的targets就是备援顺序 override_params:每个 target 独立覆盖model、max_tokens等参数——Anthropic 必传max_tokens,OpenAI 不需要,网关会按目标 provider 的规则组装请求
完整流程(含 90/10 灰度发布示例)在 cookbook/getting-started/resilient-loadbalancing-with-failure-mitigating-fallbacks.md。
验证生效:请求里带traceID,响应头x-portkey-trace-id回传同一值;再注意x-portkey-last-used-option-index响应头,它标明实际命中了第几个 target。在 Logs 页面按 trace ID 过滤,能逐条看到每个请求落在哪个 provider、哪个模型。
场景三:成本与缓存优化
相同或高度相似的 query 反复打到模型,既烧 token 又拖慢响应。网关提供两种缓存模式:
{ "cache": { "mode": "simple" } }mode: 'simple':prompt 完全一致时直接回缓存,适合固定问法多的场景(FAQ、模板化生成)mode: 'semantic':按余弦相似度匹配,"列出世界七大奇迹"和"请给我世界七大奇迹名单"能命中同一条缓存,适合用户自由输入的场景
缓存命中时不产生新的模型调用,费用与延迟都省掉这一轮。验证生效:看响应头x-portkey-cache-status;Logs 页面中带缓存标记的条目即命中记录,配合 Analytics 页的 Cache 标签页观察整体命中率。两种模式的差别和刷新机制见 cookbook/getting-started/enable-cache.md。
排错与调优
- 400
Invalid config passed:网关对x-portkey-config做 JSON 解析加 schema 校验,响应体里的errors数组会给出path和message。两个高频原因:配置 JSON 里没写provider或targets(校验层要求二者至少有一个);on_status_codes写了字符串而不是整数数组。 - 429 重试耗尽仍失败:
attempts内每次都拿到 429,网关最终透传 provider 的最后一次响应,x-portkey-retry-attempt-count等于attempts。处理方向:调大attempts,或叠加场景二的 fallback 把限流压力分散到多个 provider。 - 408
timeout_error:配置了timeout且单次上游调用超过该毫秒数,网关用AbortController中断并返回 408(REQUEST_TIMEOUT_STATUS_CODE)。先确认是慢在模型侧(调大timeout)还是该走 fallback。 - 429 之后直接失败、没有等待:provider 返回的
retry-after等待时长超过 60 秒总预算时,源码会主动放弃重试并透传原错误(remainingRetryTimeout用尽)。这是设计内的保护,不是配置丢失。 x-portkey-custom-host被拒:网关内置 SSRF 防护,私有网段、云元数据地址(169.254.169.254)、内网 TLD 一律拦截;本地开发打自托管模型(如 Ollama)需要设置TRUSTED_CUSTOM_HOSTS环境变量做白名单。
延伸与源码指引
- 网关配置总览(UI 引用 ID、SDK 注入、
x-portkey-config头三种方式):cookbook/getting-started/writing-your-first-gateway-config.md - 自动重试参数与 Logs 验证流程:cookbook/getting-started/automatic-retries-on-failures.md
- loadbalance、嵌套 fallback、90/10 灰度发布的完整配置:cookbook/getting-started/resilient-loadbalancing-with-failure-mitigating-fallbacks.md
- 重试循环、
retry-after解析与 60 秒上限的实现:src/handlers/retryHandler.ts;默认重试状态码、MAX_RETRIES = 5、MAX_RETRY_LIMIT_MS = 60000等常量集中在 src/globals.ts - 请求校验层(前面所有 400 报错的来源):src/middlewares/requestValidator/index.ts;部署方案(Docker、K8s、Cloudflare Workers)见 docs/installation-deployments.md
先照场景一把retry.attempts配成 3 跑通单模型,再按日志里的 trace ID 逐步叠加 fallback 和缓存——每一层都能独立验证,不用一次改完。
【免费下载链接】gatewayA blazing fast AI Gateway with integrated guardrails. Route to 1,600+ LLMs, 50+ AI Guardrails with 1 fast & friendly API.项目地址: https://gitcode.com/GitHub_Trending/ga/gateway
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考