如何给 LLM 调用加自动重试与多模型 fallback:Portkey Gateway 配置解析
2026/9/13 19:13:39 网站建设 项目流程

如何给 LLM 调用加自动重试与多模型 fallback:Portkey Gateway 配置解析

【免费下载链接】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

凌晨的监控里突然刷出一排 429 和 503,聊天接口的错误率开始爬坡。这篇文章带你把 Portkey Gateway 的网关配置从零跑通一遍:写一份重试配置、接到现有 SDK、再验证它真的生效。做完后,你能独立维护一份带重试、fallback 和缓存的生产配置,不需要改动业务代码。

一、它到底解决什么问题

读完这一节,你能说清楚网关层和“自己在代码里写重试”的分工边界。

原生 SDK 只负责把请求发给单一 provider。上游抖一下,错误就原样抛到你的业务层。Portkey Gateway 在中间做转发,行为由一份 JSON 配置驱动:哪些状态码重试、重试几次、失败后落到哪个 target、重复请求是否走缓存,全部声明在这份配置里。

能力原生 SDK 的做法通过 Portkey Gateway 的做法
失败重试应用层自写循环加 sleep配置里声明retry.attempts,网关代为重试
多模型容灾每个 provider 各写一套 try/catch一个targets数组声明 fallback 链
响应缓存自建 Redis 层自己做 keycache.mode声明 simple 或 semantic
超时兜底各 HTTP client 分散设置request_timeout统一毫秒级控制
观测自己打日志再拼看板Logs 页统一看耗时、成本、重试次数

心智模型就一句话:行为从代码搬进配置,代码只发请求。

二、最小可用实现:配置从 0 到 1

读完这一节,你能创建一份重试配置,并用两种接法各发出一带重试的请求。

主线是三段:写配置、建配置、发请求。

第一步:写一份最小重试配置。网关不会猜你的意图,必须显式声明。下面的配置表示命中 429、500、503 时最多再试 2 次:

{ "retry": { "attempts": 2, "on_status_codes": [429, 500, 503] } }

保存后,命中这三个状态码的请求会被网关自动重发,而不是把错误抛给你。

第二步:在控制台创建配置。进入 Configs 页,点 Create,起个名字,把上面的 JSON 粘进编辑器并保存,会得到一个形如pc-xxxxx的配置 ID,后面靠它引用:

这张图重点看两处:左侧的 JSON 编辑区和保存后列表里露出的配置 ID。

第三步:发起一次请求。有两种接法,按你现状选。

接法 A:项目 SDK 直连。适合新接入或愿意换 SDK 的场景,初始化时传配置 ID,此后所有请求自动带上重试:

import { Portkey } from 'portkey-ai'; const portkey = new Portkey({ apiKey: 'pk-xxxx', virtualKey: 'vk-xxxx', config: 'pc-xxxxx' // 配置 ID }); const response = await portkey.chat.completions.create({ model: 'gpt-4o', messages: [{ role: 'user', content: '你好' }] });

效果:这行config让该客户端发出的每个请求都继承重试行为。

接法 B:兼容现有 OpenAI SDK。只改 baseURL 和默认头,业务代码一行不动:

import OpenAI from 'openai'; import { PORTKEY_GATEWAY_URL, createHeaders } from 'portkey-ai'; const openai = new OpenAI({ apiKey: 'sk-xxxx', baseURL: PORTKEY_GATEWAY_URL, // 指向网关而非 OpenAI defaultHeaders: createHeaders({ provider: 'openai', apiKey: 'pk-xxxx', config: 'pc-xxxxx' // 配置 ID }) }); // …其余调用代码不变

效果:请求经网关转发,配置通过x-portkey-config请求头注入,SDK 侧无感知。

自托管部署时,整站行为也可以写在根目录的 conf.example.json 里,它演示了插件开关、provider 凭据和限流条目的结构。

三、配置项逐个讲:字段、默认值与适用场景

读完这一节,你能对着字段表决定每个开关开不开,并知道哪几个字段最容易写错。

核心字段一览(字段与默认值来自网关的配置校验逻辑,见 config.ts):

字段默认值作用什么时候该开
retry.attempts0(不重试)最大重试次数,上限 5上游偶发 429/5xx
retry.on_status_codes[429, 500, 502, 503, 504]触发重试的状态码列表只想对特定错误码重试时
retry.use_retry_after_header429 时按供应商的 retry-after 头冷却再试被限流且想尊重供应商建议
cache.modeDISABLEDsimple 精确匹配,semantic 语义匹配重复提问多、想省 token
cache.max_age可选,未设缓存存活时长需要控制数据新鲜度
strategy.modesinglesingle / loadbalance / fallback / conditional多 provider 分流或容灾
targets[].weight可选loadbalance 下各 target 的流量占比按额度分摊流量
request_timeout可选单请求超时(毫秒),超时网关返回 408防长尾请求拖垮线程池

三个容易踩坑的字段,各给一句最小示例。

attempts上限是 5(源码常量MAX_RETRIES),写更大不会按比例放大,别按“越大越稳”来加:

"retry": { "attempts": 5 } // 上限 5 次

use_retry_after_header打开后,网关会读取retry-after-msx-ms-retry-after-msretry-after三个响应头决定等待时长:

"retry": { "attempts": 2, "use_retry_after_header": true }

最后一条是硬约束:配置必须至少含provider+api_keystrategy+targetscacheretryrequest_timeout之一,否则整份配置被拒。写空对象“先占位”的做法会直接报错。

四、两个进阶场景:请求级覆盖与多级 fallback

读完这一节,你能处理两类真实需求:临时加大力度,以及单供应商挂掉不崩线。

场景一:请求级临时覆盖默认配置。业务动机:某批离线批处理请求允许更长等待,但不想动全局配置。把 config 作为第二个参数单独传即可:

const response = await portkey.chat.completions.create( { model: 'gpt-4o', messages }, { config: { retry: { attempts: 5 } } } // 仅本次请求生效 );

效果:这次请求按 5 次重试执行,其他请求仍走客户端级的全局配置。

场景二:多级 fallback 叠加流量分摊。业务动机:OpenAI 被限流时不能让整个服务瘫痪。外层 loadbalance 把流量摊给 Anthropic 和 OpenAI 组,内层 fallback 让 OpenAI 失败后落到 Azure:

{ "strategy": { "mode": "loadbalance" }, "targets": [ { "virtual_key": "anthropic-key", "weight": 0.5 }, { "strategy": { "mode": "fallback" }, "weight": 0.5, "on_status_codes": [429, 503], "targets": [ { "virtual_key": "openai-key" }, { "virtual_key": "azure-key" } ] } ] }

效果:流量五五开,OpenAI 命中 429/503 时自动切到 Azure,用户侧无感。

这张图看路由走向:同一层按 weight 分流,失败沿内层 targets 顺序下探。

五、怎么验证它真的生效了

读完这一节,你能用日志、响应头和 traceID 三件套确认配置不是摆设。

看日志。控制台 Logs 页列出每条请求的 provider、模型、token、成本和重试情况:

这张图重点看每行的状态标记:被缓存命中或触发重试的请求会有对应图标。

看响应头。网关会在响应里回写几个关键字段(定义见 src/globals.ts 的RESPONSE_HEADER_KEYS):

响应头用途
x-portkey-retry-attempt-count实际重试次数,重试耗尽时为 -1
x-portkey-cache-status缓存状态,未命中为 MISS
x-portkey-trace-id与日志互查的请求标识

发一条标记请求,便于事后在日志里精准过滤:

await portkey.chat.completions.create( { model: 'gpt-4o', messages }, { traceID: 'verify-retry-1' } // 日志页按它过滤 );

效果:你在 Logs 页输入这个 traceID,就能看到这条请求的完整执行轨迹。

三个常见坑,按这个顺序排查:

  1. ⚠️ 完全没重试。先确认attempts大于 0:网关把缺失的 attempts 归一成 0,等于没配(见 requestContext.ts 的normalizeRetryConfig);再确认错误码在on_status_codes列表里。
  2. 429 后直接放弃。开了use_retry_after_header时,供应商给的冷却时间超过 60 秒总预算(MAX_RETRY_LIMIT_MS),网关会跳过本次重试,日志里表现为重试次数断档。
  3. 配置整体不生效。确认x-portkey-config请求头真的到达了网关;自托管时直接看服务端访问日志最快。顺序固定:先看头、再看状态码、最后看 attempts。

重试的完整实现在 retryHandler.ts,排到第四类问题时可以进去读。

六、延伸导航:仓库内关键文件

按需取用,每个都只说一句话。

  • 入门系列,从第一次调用讲到缓存与重试:cookbook/getting-started/
  • 自托管示例配置,含插件开关与限流条目:conf.example.json
  • 网关各接口的请求处理入口:src/handlers/
  • 部署方式,Docker 与 K8s:docs/installation-deployments.md

重试、fallback 和缓存的本质,是把故障处理从代码挪进配置。下一步建议:挑你业务里最易抖的一条 LLM 调用接到这份配置上,用 traceID 标记一条请求,到 Logs 里确认重试次数和预期一致。

【免费下载链接】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),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询