很多人跑通第一个请求后就以为"接好了",一上生产才发现问题:网络抖一下请求就挂死、偶发 429 直接报错、上游异常整条链路瘫痪。所谓"稳定调用",靠的不是运气,而是几段并不复杂的工程代码。本文把它拆成超时、重试退避、故障降级三件事,示例全用占位符,替换成自己的即可。

一、先约定环境变量

export API_KEY="你的key"
export BASE_URL="你的base_url"   # 可选,不用则不填

二、超时:第一道保险

裸调不设超时是新手最常见的坑。一次网络抖动就能让请求一直挂着,把连接池占满,新请求全排队。所有调用都必须设超时:

import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["API_KEY"],
    base_url=os.environ.get("BASE_URL") or None,
    timeout=30.0,
)

三、重试退避:把偶发错误吃掉

429(限流)和 5xx(瞬时错误)在生产里是常态,不该直接抛给用户。正确做法是带指数退避的重试,给上游喘息时间:

import time, random

def call_with_retry(messages, model, max_retries=3):
    for i in range(max_retries):
        try:
            return client.chat.completions.create(model=model, messages=messages)
        except Exception:
            if i == max_retries - 1:
                raise
            # 指数退避 + 抖动,避免同时重试再次压垮上游
            time.sleep((2 ** i) + random.random())

注意加一点随机抖动,避免多个请求踩着同一个节奏重试,反而形成二次冲击。还有一点常被忽略:不是所有错误都值得重试。429 和 5xx 这类瞬时错误重试有意义,但 401(鉴权失败)、400(参数错误)这类确定性错误重试多少次都不会成功,反而白白拖长响应、浪费额度。正确做法是先判断错误类型,只对可恢复的错误重试,把不可恢复的直接抛出去让上层处理。把"可重试错误"列成一个白名单,是让重试逻辑真正有用的关键一步。

四、故障降级:别把鸡蛋放一个篮子

想要"稳定",还得有备选路径。把地址、密钥、模型名都抽成配置,准备一个主入口和一个备用入口,主入口连续失败就切到备用:

ENDPOINTS = [
    {"base_url": os.getenv("PRIMARY_URL"),  "key": os.getenv("PRIMARY_KEY")},
    {"base_url": os.getenv("FALLBACK_URL"), "key": os.getenv("FALLBACK_KEY")},
]

至于主备入口从哪来,官方直连、第三方统一接入、云厂商服务几类各有取舍,可按可达性和稳定性自己实测后填。

五、加个健康探针

生产里最好定时用一个轻量请求探活各入口,成功率掉下来提前告警,别等用户先发现。探针记录成功率和 P95 延迟,比平均值更能反映高峰体验。探针本身要轻,用最短的请求、最小的 token,别让健康检查自己变成负担;探测频率也要适中,太密会额外增加成本和上游压力,太疏又发现得慢,几十秒到一两分钟一次通常够用。把探针数据接进你已有的监控告警,异常时能第一时间通知到人,这套"稳定"才算真正闭环。

六、小结

“稳定调用"不是玄学,是超时兜底、退避重试、故障降级、健康探针这几件工程事叠起来的结果。把这套模板套进项目,GPT 和 Claude 的调用就能从"能通"变成"扛得住线上流量”。key 和 base_url 从哪来是另一回事,实测后按可达性决定即可。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐