先把结论甩前面智能体调外部 API 最容易翻车的两块一是鉴权 token 过期没续上二是失败重试写得太莽要么不重要么把对方打挂。下面这几个坑我全踩过按编号列每个先说现象再给解法照着改基本能稳。背景交代一下。前段时间我搭了个周报小助手让它每天早上去拉我们 Jira 上的工单、再调一个内部统计 API 汇个总。逻辑特别简单结果上线第三天就崩了——崩在鉴权和重试上。坑1token 过期了还在拿旧的用现象跑了五十几分钟一切正常突然全是 401。日志里 access_token 明明还在请求头也带了就是被拒。原因OAuth2 的 access_token 大多 1 小时过期我那个是 3600 秒我傻乎乎地在启动时换了一次 token 就一直缓存着用。解法别等 401 才反应提前判断过期。我的做法是缓存 token 时连expires_at一起存每次用之前看一眼离过期还剩不到 60 秒就主动刷新。留这 60 秒 buffer 很关键——不然你判断还没过期的瞬间和请求真正到对方服务器之间,那几百毫秒它就过期了。def get_token(): if time.time() _cache[expires_at] - 60: refresh_token() # 用 refresh_token 换新的 access_token return _cache[access_token]坑2refresh_token 也会失效但你没兜底现象跑了大半天刷新 token 这一步自己也 401 了。整个智能体直接哑火。原因refresh_token 不是永久的。有的平台 refresh 一次旧的就作废轮换机制你要是没把返回里的新 refresh_token 存下来下次就拿着废的去刷。解法刷新成功后,把响应里的 refresh_token 也一并更新存回去别只更新 access_token。另外给刷新本身套一层异常捕获refresh 失败就走重新授权流程而不是让异常往上冒、把整个任务带崩。坑3401 当成普通错误一路重试现象401 之后疯狂重试每次还是 401重试三次全废CPU 空转。解法分清楚错误类型再决定重不重试。我后来按这张表来状态码含义要不要重试401token 问题先刷 token刷完只重试一次429限流重试但要等看 Retry-After500/502/503对方抽风重试指数退避400/404你参数错了别重试重几次都白搭401 只重一次是有讲究的——刷完 token 还 401说明不是过期问题是权限或者签名错了再重就是浪费。坑4重试不退避把对方 API 打成 DDoS现象对方 503 了我立刻重试间隔几毫秒连发对方本来就过载被我这一波直接雪上加霜封了我 IP 半小时。解法指数退避 抖动。第一次等 1 秒第二次 2 秒第四次 4 秒每次再叠个随机抖动避免多个实例同一秒齐刷刷重试。for i in range(max_retry): resp call_api() if resp.ok: break wait (2 ** i) random.uniform(0, 1) time.sleep(wait)碰到 429 带了Retry-After头的就老老实实按它给的秒数等别自作聪明用自己的退避公式。坑5重试没设上限和总超时卡死整条链路现象某次对方 API 慢到要 30 秒一个响应我重试 5 次一个任务卡了快 3 分钟后面排队的全堵死。解法两道闸——单次请求设 timeout我设的 10 秒整个重试循环设一个总预算比如 30 秒到了不管重没重够都放弃。宁可这次失败记个日志下轮再来也别让一个慢请求拖垮全局。说点实在的取舍。上面这套逻辑我一开始是纯手写的写完发现光鉴权和重试就一百多行还得自己维护 token 缓存。后来我把这套杂活挪到了一个零代码就能配智能体的平台上——拖几个节点、把 API 和鉴权方式填进去token 刷新和失败重试它内置帮你兜了我只管写业务逻辑。不是说它多神缺点也有第一版搭出来挺干的复杂的签名鉴权比如要算 HMAC 那种还是得自己写段脚本节点补上纯拖拽覆盖不了。学习上手大概花了我一下午摸节点配置。但对我这种只想让 AI 帮我干点定时调 API 的杂活、不想为此专门写个服务的人省下来的时间是实打实的。那个周报小助手现在跑了一个多月没再半夜叫我起来看 401。鉴权和重试这事说到底就是别偷懒缓存、别莽着重试。你们在智能体调外部 API 时还踩过啥邪门的坑评论区聊聊尤其是限流那块,我感觉每家 API 的脾气都不一样。对了模型 API 我走的讯飞星辰MaaS现成调没自己折腾算力部署。
智能体接外部API:token过期与重试避坑
先把结论甩前面智能体调外部 API 最容易翻车的两块一是鉴权 token 过期没续上二是失败重试写得太莽要么不重要么把对方打挂。下面这几个坑我全踩过按编号列每个先说现象再给解法照着改基本能稳。背景交代一下。前段时间我搭了个周报小助手让它每天早上去拉我们 Jira 上的工单、再调一个内部统计 API 汇个总。逻辑特别简单结果上线第三天就崩了——崩在鉴权和重试上。坑1token 过期了还在拿旧的用现象跑了五十几分钟一切正常突然全是 401。日志里 access_token 明明还在请求头也带了就是被拒。原因OAuth2 的 access_token 大多 1 小时过期我那个是 3600 秒我傻乎乎地在启动时换了一次 token 就一直缓存着用。解法别等 401 才反应提前判断过期。我的做法是缓存 token 时连expires_at一起存每次用之前看一眼离过期还剩不到 60 秒就主动刷新。留这 60 秒 buffer 很关键——不然你判断还没过期的瞬间和请求真正到对方服务器之间,那几百毫秒它就过期了。def get_token(): if time.time() _cache[expires_at] - 60: refresh_token() # 用 refresh_token 换新的 access_token return _cache[access_token]坑2refresh_token 也会失效但你没兜底现象跑了大半天刷新 token 这一步自己也 401 了。整个智能体直接哑火。原因refresh_token 不是永久的。有的平台 refresh 一次旧的就作废轮换机制你要是没把返回里的新 refresh_token 存下来下次就拿着废的去刷。解法刷新成功后,把响应里的 refresh_token 也一并更新存回去别只更新 access_token。另外给刷新本身套一层异常捕获refresh 失败就走重新授权流程而不是让异常往上冒、把整个任务带崩。坑3401 当成普通错误一路重试现象401 之后疯狂重试每次还是 401重试三次全废CPU 空转。解法分清楚错误类型再决定重不重试。我后来按这张表来状态码含义要不要重试401token 问题先刷 token刷完只重试一次429限流重试但要等看 Retry-After500/502/503对方抽风重试指数退避400/404你参数错了别重试重几次都白搭401 只重一次是有讲究的——刷完 token 还 401说明不是过期问题是权限或者签名错了再重就是浪费。坑4重试不退避把对方 API 打成 DDoS现象对方 503 了我立刻重试间隔几毫秒连发对方本来就过载被我这一波直接雪上加霜封了我 IP 半小时。解法指数退避 抖动。第一次等 1 秒第二次 2 秒第四次 4 秒每次再叠个随机抖动避免多个实例同一秒齐刷刷重试。for i in range(max_retry): resp call_api() if resp.ok: break wait (2 ** i) random.uniform(0, 1) time.sleep(wait)碰到 429 带了Retry-After头的就老老实实按它给的秒数等别自作聪明用自己的退避公式。坑5重试没设上限和总超时卡死整条链路现象某次对方 API 慢到要 30 秒一个响应我重试 5 次一个任务卡了快 3 分钟后面排队的全堵死。解法两道闸——单次请求设 timeout我设的 10 秒整个重试循环设一个总预算比如 30 秒到了不管重没重够都放弃。宁可这次失败记个日志下轮再来也别让一个慢请求拖垮全局。说点实在的取舍。上面这套逻辑我一开始是纯手写的写完发现光鉴权和重试就一百多行还得自己维护 token 缓存。后来我把这套杂活挪到了一个零代码就能配智能体的平台上——拖几个节点、把 API 和鉴权方式填进去token 刷新和失败重试它内置帮你兜了我只管写业务逻辑。不是说它多神缺点也有第一版搭出来挺干的复杂的签名鉴权比如要算 HMAC 那种还是得自己写段脚本节点补上纯拖拽覆盖不了。学习上手大概花了我一下午摸节点配置。但对我这种只想让 AI 帮我干点定时调 API 的杂活、不想为此专门写个服务的人省下来的时间是实打实的。那个周报小助手现在跑了一个多月没再半夜叫我起来看 401。鉴权和重试这事说到底就是别偷懒缓存、别莽着重试。你们在智能体调外部 API 时还踩过啥邪门的坑评论区聊聊尤其是限流那块,我感觉每家 API 的脾气都不一样。对了模型 API 我走的讯飞星辰MaaS现成调没自己折腾算力部署。