给 Claude API 调用补上超时重试和错误分类

直接调用模型接口时,偶发超时、限流和上游 5xx 是最常见的异常。本文用一个小型 Python 客户端,把超时边界、有限重试和错误分类放到同一层,方便后续接入业务。

设置连接与读取超时

请求必须有明确的时间边界,连接超时和读取超时可以分别控制。

python 复制代码
import requests

session = requests.Session()
response = session.post(
    "https://your-api-endpoint.example/v1/messages",
    headers={
        "x-api-key": "sk-your-key",
        "anthropic-version": "2023-06-01",
        "content-type": "application/json",
    },
    json={
        "model": "claude-sonnet-4-6",
        "max_tokens": 1024,
        "messages": [{"role": "user", "content": "连通性测试"}],
    },
    timeout=(5, 60),
)
response.raise_for_status()

如果通过 jiekou.vip等接入平台调用,只需按照对应文档替换地址和认证配置,不要把配置写死在业务函数中。

按错误类型决定动作

认证失败和参数错误不适合重试;429、网络异常以及部分 5xx 则可以有限重试。

python 复制代码
import random
import time

RETRYABLE_STATUS = {429, 500, 502, 503, 504}


def request_with_retry(send, attempts=4):
    for attempt in range(attempts):
        try:
            response = send()
            if response.status_code not in RETRYABLE_STATUS:
                response.raise_for_status()
                return response
        except (requests.Timeout, requests.ConnectionError):
            if attempt == attempts - 1:
                raise
        else:
            if attempt == attempts - 1:
                response.raise_for_status()

        time.sleep(min(8, 2 ** attempt) + random.uniform(0, 0.3))

指数退避配合随机抖动,可以避免多个实例同时重试。

统一错误分类

业务层只需要关心错误类别,不必到处判断底层异常文本。

python 复制代码
from dataclasses import dataclass


@dataclass
class ApiError:
    category: str
    status_code: int | None
    retryable: bool
    message: str


def classify_error(exc=None, response=None):
    if isinstance(exc, requests.Timeout):
        return ApiError("timeout", None, True, str(exc))
    if isinstance(exc, requests.ConnectionError):
        return ApiError("connection", None, True, str(exc))

    status = response.status_code
    if status == 401:
        return ApiError("authentication", status, False, response.text)
    if status == 429:
        return ApiError("rate_limit", status, True, response.text)
    if status >= 500:
        return ApiError("upstream", status, True, response.text)
    return ApiError("request", status, False, response.text)

日志和告警可以按 category 聚合,比依赖变化的错误文案更稳定。

记录调用边界

至少记录请求 ID、模型、耗时、状态码和最终错误类别。密钥不能写入日志,用户提示词也不应整段落盘。

python 复制代码
import logging
import time
import uuid

logger = logging.getLogger("model_api")


def call_model(send, model):
    request_id = uuid.uuid4().hex
    started = time.perf_counter()
    try:
        response = request_with_retry(send)
        logger.info(
            "model_call_ok",
            extra={
                "request_id": request_id,
                "model": model,
                "status_code": response.status_code,
                "duration_ms": round((time.perf_counter() - started) * 1000),
            },
        )
        return response.json()
    except Exception:
        logger.exception(
            "model_call_failed",
            extra={
                "request_id": request_id,
                "model": model,
                "duration_ms": round((time.perf_counter() - started) * 1000),
            },
        )
        raise

验证故障路径

上线前至少模拟三种情况:把读取超时调小,确认超时会重试;使用错误密钥,确认 401 只失败一次;模拟 429 和 503,确认退避会增加并最终停止。

把这些边界补齐后,模型调用就有了明确的失败处理方式,后续接入业务时也更容易定位问题。

相关推荐
陈天伟教授1 分钟前
《数据处理和标注技术》课程能力图谱
人工智能·算法
海宇数据2 分钟前
零信任架构实战:基于海宇公安二要素认证即时版构建自动化消费金融实名合规网关
人工智能·金融·架构·自动化
用户9788587019504 分钟前
资料换版以后,我先清旧索引,再做一轮短词补查
人工智能
一楼的猫4 分钟前
第十一届中国教育后勤展览会杭州开幕 夏拾光影像为阿里、淘宝闪购提供云相册直播与视频服务 - 夏拾光影像
大数据·人工智能·音视频
飞猫的边缘AI6 分钟前
智能制造与EDA版图仿真
人工智能·芯片·边缘ai
YSL0701246 分钟前
一文通关-----栈和队列
开发语言·数据结构
智行合一科技11 分钟前
中国互联网营销发展报告发布,GEO与代理式AI成焦点
人工智能
禁默15 分钟前
论文解读与思考:基于场所地图的标识感知机器人探索方法及工程参考的价值
人工智能·深度学习·算法·机器人
维克兜率天16 分钟前
【维克】统计套利建模:从因子到信号的完整流程
android·开发语言·python·算法·kotlin
青衫烟雨16 分钟前
DeepSeek 崩了 5 小时:你的 AI 应用为什么跟着一起挂?
人工智能·架构