[控场AI]
· 9 分钟阅读· 4,891 字

Telnyx AI Gateway 实现可观测的模型故障转移

Telnyx AI Gateway 实现可观测的模型故障转移

Telnyx AI Gateway 将重试与回退集中到网关层,并通过响应头和消费账本让故障转移全程可观测。

文章介绍 Telnyx AI Gateway 如何把模型重试与回退策略从客户端上移到网关层,并以开源示例 gateway-fallbacks 演示完整流程。核心思路是管理面与推理面分离:账户密钥用于配置令牌组、预算和使用报告,应用只持有作用域令牌密钥。令牌组定义允许的模型、回退链和重试参数,客户端需禁用自身重试以避免尝试次数失真。网关区分确定无工作失败与不确定失败,分别采取同模型重试或转移回退模型。示例通过设置首事件超时强制触发回退,再用 x-ltg-served-model 和 x-ltg-attempts 响应头实时验证,并在消费账本中审计同一事件。文章还涵盖请求级覆盖、缓存、ETag 变更安全及预算控制。

Telnyx AI Gateway 实现可观测的模型故障转移

当你的应用依赖 AI 模型时,一个关键问题常常被忽略:当主模型失败,回退到备用模型后,你真的知道发生了什么吗?哪个模型实际处理了请求?网关尝试了几次?客户端重试循环可能会掩盖这些答案,而 SDK 重试叠加在网关重试之上,还会导致请求数膨胀和尝试次数失真。

Telnyx AI Gateway 提供了一个将重试和回退策略集中到网关层的解决方案,并通过响应头和消费账本让整个过程变得可观测。最近开源的 gateway-fallbacks Python 示例,完整演示了如何配置主备模型、强制超时触发故障转移,并通过两种方式验证结果。

架构设计:管理面与推理面分离

该示例将系统分为管理面、推理面和观察面。管理面使用 Telnyx 账户 API 密钥,负责令牌组、令牌密钥、预算和使用报告;推理面则兼容 OpenAI API,仅使用为组签发的令牌密钥,因此应用代码无需接触账户凭证。

这种职责分离不仅提升了安全性,还让策略配置与业务逻辑解耦。你可以在管理面集中定义模型访问权限、重试规则和回退链,而推理面保持简洁,专注于请求处理。

Telnyx AI Gateway 架构示意图

在令牌组中定义回退策略

策略的核心是令牌组(token group)。示例中,我们定义两个允许的模型别名:Kimi-K3 作为主模型,GLM-5.3-Flash 作为回退模型,并设置回退关系。重试策略包括最大尝试次数、重试延迟和指数退避。

allowed_models = ["Kimi-K3", "GLM-5.3-Flash"]
fallbacks = {"Kimi-K3": ["GLM-5.3-Flash"]}
retries = {
    "max_attempts": 2,
    "retry_delay_ms": 250,
    "backoff": "exponential",
}
group = client.llm_token_gateway.token_groups.create(
    name="gateway-fallbacks-demo",
    allowed_models=allowed_models,
    fallbacks=fallbacks,
    retries=retries,
    max_budget=10,
    budget_duration="1d",
    idempotency_key=f"gateway-fallbacks-group-{uuid.uuid4()}",
).data

该组限制了密钥可以调用的模型,并定义了失败如何在链中传递。示例在发起 API 请求前会在本地验证相同的策略限制,例如回退链深度不能超过三层,max_attempts 必须在 1 到 5 之间,回退链不能引用自身或包含重复项,且每个回退模型必须出现在 allowed_models 中。网关也会强制执行这些规则,policy.py 会故意发送无效的 max_attempts=9 更新,并预期收到 HTTP 400 而不改变组状态。

令牌组(token group) 是 Telnyx AI Gateway 中对一组推理访问规则和预算的命名集合。创建令牌组时,可以声明该组允许调用的模型别名、模型之间的回退关系、重试参数以及预算上限和周期。随后为组签发令牌密钥(token key),应用使用该密钥访问兼容 OpenAI 的推理端点,而无需持有账户级 API 密钥。令牌组因此同时承担权限边界和策略容器的角色:模型白名单限制密钥能触达的模型,回退链定义失败时的转移路径,重试配置统一控制尝试行为,预算则约束该组在指定周期内的最大花费。更新或删除令牌组属于管理面操作,需要账户凭证;推理面仅凭令牌密钥即可工作。

保持重试在同一层

关键原则是:重试和模型回退由网关负责,因此 OpenAI 客户端应禁用自身的重试行为。示例中通过设置 max_retries=0 来实现这一点。

llm = OpenAI(
    base_url="https://llm.telnyx.com/v1",
    api_key=token_key,
    max_retries=0,
)

这一点至关重要,因为 SDK 重试是叠加在网关尝试之上的新请求。禁用它可确保响应头、账本记录和计费围绕单一重试策略保持一致。否则,你可能会看到尝试次数虚高,而实际模型调用路径却难以还原。

网关如何处理失败

网关对失败的分类处理体现了其对请求状态的精细判断。确定无工作失败,如预分发错误、429 和 529,可以重试相同模型;不确定失败,如超时、408、500、502、503、504,则会转移到下一个回退模型,因为原始请求可能已经到达提供商。上下文长度拒绝则是终止性的,因为将同样过大的上下文发送到另一个尝试无法修复输入问题。

确定无工作失败与不确定失败的区分依据是:请求是否可能已经在提供商侧产生了实际计算或副作用。预分发错误表示请求尚未离开网关,429(限流)和 529(过载)通常意味着提供商明确拒绝了本次请求而未开始处理,因此对同一模型重试是安全的。相反,超时、408、500、502、503、504 等情形下,网关无法确认原始请求是否已被提供商接收并执行,若贸然重试同一模型可能造成重复计费或重复副作用,因此策略选择转移到下一个回退模型。上下文长度拒绝属于请求本身的缺陷,换模型不会改变输入超限的事实,故直接终止。这一分类直接影响计费准确性和故障转移的有效性。

强制触发模型回退以进行演示

等待提供商发生故障并不是有用的测试计划。示例通过受控竞争来强制触发回退:向 Kimi-K3 发送流式请求,设置一秒的首事件截止时间,并传递一个约 22,000 token 的重型输入(包含唯一随机数以避免 KV 缓存影响)。目标是让主模型的首事件错过截止时间,而 GLM-5.3-Flash 作为回退完成请求。

result = chat_completion(
    token_key,
    "Kimi-K3",
    build_forced_failure_prompt(),
    extra_headers={
        "x-ltg-request-timeout": "1000",
        "x-ltg-max-attempts": "1",
    },
    stream=True,
    max_tokens=64,
)

由于提供商延迟会变化,脚本会尝试最多三次,并如实报告主模型是否在截止时间内响应,或者两个尝试是否都超时。

通过响应头验证实时请求

客户端从原始响应中读取两个关键响应头:x-ltg-served-model 和 x-ltg-attempts。成功的故障转移应显示:

requested model:   Kimi-K3
served model:      GLM-5.3-Flash
x-ltg-attempts:    2 or more

SDK 响应模型也有用,但网关响应头在实时路径上明确显示了路由决策。

在消费账本中验证同一事件

下一步是读取为令牌密钥签发的网关消费事件。当 requested_model 和 model 不同时,账本提供了响应头的持久化对应物。示例使用半开 UTC 日期范围和快照分页,确保报告在事件集变化时仍可重现。

events = client.llm_token_gateway.spend.retrieve_events(
    start_date=start_date,
    end_date=end_date,
    token_key_id=token_key_id,
    page_number=1,
    page_size=50,
)
for event in events.data:
    print(
        event.requested_model,
        "->",
        event.model,
        "attempts:",
        event.attempts,
        "status:",
        event.status,
        "cache_hit:",
        event.cache_hit,
    )

GET /usage/summary 在账户具有 llm_token_gateway.usage.read 权限时添加总计和按模型汇总。如果该端点返回 403,则视为非致命警告,因为消费事件账本仍包含请求级别的证明。

每请求控制、缓存与变更安全

网关支持对尝试次数、延迟、退避和超时的请求级覆盖,这些控制可以调整单个请求而不重写令牌组策略。示例还更新 cache_ttl 为 60 秒,并发送相同提示两次。网关缓存是尽力而为的,因此脚本不会虚构缓存命中:当重复请求由缓存提供时,它报告 x-ltg-attempts: 0,否则引导你查看账本的 cache_hit 字段。

每次更新和删除都遵循变更安全模式:获取最新的 ETag,通过 If-Match 发送,并包含 Idempotency-Key。过期的 ETag 会返回 412,防止一个进程覆盖另一个进程的较新配置。

ETag 与 If-Match 构成基于版本号的乐观并发控制。服务器为每份资源配置生成 ETag,客户端更新时通过 If-Match 头声明自己所基于的版本;若资源在此期间已被他人修改,ETag 不再匹配,服务器返回 412 Precondition Failed,拒绝覆盖。配合 Idempotency-Key,同一逻辑操作在重试时不会被重复执行,从而避免网络抖动导致的重复创建或重复扣费。这种模式在多进程或多操作员同时管理网关策略时尤为重要,它把“最后写入者胜出”的隐式风险转化为显式的版本冲突,让配置变更可预测、可审计。

运行示例

克隆仓库并安装依赖后,在 .env 中添加 Telnyx 账户 API 密钥,然后运行本地冒烟测试。之后运行五步演示:provision.py 创建组和密钥(密钥只打印一次),设置环境变量后依次运行 inference.py、ledger.py、policy.py 和 teardown.py。实时演示会产生真实的推理费用,示例配置了每天 10 美元的最高预算,但建议在运行前检查策略。

provision.py 只在 .gateway_state.json 中存储组和密钥 ID,从不将令牌密钥写入磁盘。teardown.py 撤销令牌密钥、删除组、验证撤销的密钥收到 HTTP 401,并删除本地状态文件。

可复用的模式

这个有用的模式并不限于这两个模型:将模型访问、重试规则、回退和预算放在网关策略中;为应用提供作用域令牌密钥而非账户凭证;禁用重叠的客户端重试;从响应头读取路由证据;在消费账本中确认同一事件。这使模型故障转移从假设变为运营商可以在请求期间检查、并在之后审计的事实。

#Telnyx AI Gateway#模型故障转移#AI 网关#可观测性#重试策略#OpenAI 兼容#消费账本
分享:

相关推荐