AI 接口 504 后先查什么:X-Client-Request-Id、退避上限与幂等键
来源:17golang原创
时间:2026-08-24 02:15:38 171浏览 收藏
线上 AI 功能最容易出事故的时刻,往往不是模型返回 400,而是客户端等了 30 秒后只收到一个超时。此时服务器可能还在生成,业务却不知道这次请求到底有没有落地。安全做法不是立刻再发一遍,而是给每次业务操作固定请求标识,区分“可以重试”和“必须人工确认”,再用结果键把重复响应收敛掉。
- OpenAI 可用
X-Client-Request-Id记录客户端请求标识,服务端响应还应保存x-request-id便于排查。 - Gemini 官方建议只对超时、网络异常、408、429 和 5xx 等瞬态问题做有限次数的指数退避,并加入抖动。
- 重试前先查本地任务表;没有确定结果时用业务幂等键去重,不能把“重复提交”当成成功。
超时不是失败:先把一次调用拆成三种结果
我在一个“根据用户上传内容生成摘要”的接口上遇到过这个问题:网关 30 秒断开连接,后台日志却显示模型调用在第 34 秒返回成功。前端如果把超时直接当失败,再次点击就会产生两份摘要,甚至重复扣费。
因此,调用记录至少要有 accepted、succeeded、failed 三类最终状态;客户端超时只能写成 unknown。unknown 的意思是“结果尚未确认”,不是“可以马上重做”。
触发器、权限和请求标识要在入口固定
把重试逻辑散落在控制器、队列消费者和 SDK 里,最后很难知道到底重发了几次。更稳的入口是先创建一条业务任务,再让所有下游调用继承同一个 job_id。
job_id = "summary_20260824_01HZX..."
client_request_id = "job_id/attempt-1"
headers = {
"X-Client-Request-Id": client_request_id,
"Idempotency-Key": job_id,
}
X-Client-Request-Id 用来关联一次网络请求,Idempotency-Key 则是应用自己的业务去重键。两者不要混成一个字段:一次任务可能有多次 attempt,但同一个 job_id 仍然只能产生一个业务结果。
流水线按“记录—调用—核对—重试”推进
每个阶段都要有可观察的产物,否则失败后只能凭猜测补请求。
| 阶段 | 必须记录 | 下一步 |
|---|---|---|
| 创建任务 | job_id、输入摘要、业务状态 | 进入 queued |
| 发起调用 | attempt、client_request_id、开始时间 | 等待响应 |
| 收到响应 | HTTP 状态、x-request-id、模型结果 | 写入 succeeded 或 failed |
| 客户端超时 | 超时原因、attempt、最后已知状态 | 先查任务,再决定重试 |
OpenAI 的响应头包含服务端生成的 x-request-id,排查时要和自己的客户端标识一起保存。Gemini 的官方排障建议则明确把指数退避、随机抖动和最大重试次数放在调用方控制之下。
只对瞬态错误重试,退避时间不要写死
一个够用的策略是:第 1 次等待 1 秒,第 2 次等待 2 秒,第 3 次等待 4 秒,每次加一个 0 到 300 毫秒的随机抖动,并把总等待预算封顶。这样不会让一批同时超时的请求在同一秒再次撞向接口。
retryable = status in {408, 429, 500, 502, 503, 504} or network_timeout
delay = min(30, 2 ** attempt) + random.uniform(0, 0.3)
400 参数错误、401/403 鉴权问题、内容被拒绝以及明确的配额耗尽,不属于“多等一会儿就会好”的瞬态故障。对这些错误重试只会放大日志和成本。对于 504 这类没有响应体的情况,也不要假设服务端没有收到请求,应该先查 job_id 和请求标识。
门禁规则:重试前先查结果,成功后拒绝第二份
重试消费者取到 unknown 任务时,先按 job_id 查结果表,再按请求标识查调用日志。若上游已经成功,就把本地任务补成 succeeded;只有确认没有结果,且错误属于可重试集合,才允许发起下一次 attempt。
if task.result_exists:
return task.result
if task.attempts >= 3 or task.total_wait_ms >= 30000:
return mark_manual_review(task)
if task.last_error in RETRYABLE:
return enqueue_retry(task, next_attempt=task.attempts + 1)
return mark_failed(task)
写结果时再加一道数据库唯一约束,例如 UNIQUE(job_id)。应用层判断能减少重复工作,唯一约束负责挡住并发竞态;两道门都需要,不能只依赖其中一层。
失败处理要能回放,也要能停止
给每个任务保留输入摘要、模型名、attempt 列表和最后一次错误,运维才能回答“这次是否真正发到上游”。当同一任务连续三次超时,或者总等待超过 30 秒,进入 manual_review 比无限重试更安全。人工复核可以重新放行,但要沿用原来的 job_id,并生成新的 attempt 记录。
通知内容也别只写“AI 调用失败”。至少带上 job_id、最后的 HTTP 状态、重试次数、x-request-id(如果有)和用户是否已经看到结果。这样值班同学可以从一条通知跳到完整调用链。
相关问题
超时后立刻重试会不会丢结果?
不会因为“等待”本身丢结果,但可能制造重复任务。先把原任务标成 unknown,查询结果或日志,再决定是否重试。
客户端请求标识能代替幂等键吗?
不能完全代替。请求标识适合排查一次 HTTP 调用,幂等键要绑定业务动作,并由自己的任务表和唯一约束保证结果只落一次。
429 和 500 都应该无限重试吗?
都不应该。根据 Retry-After、指数退避和总预算有限重试;超过预算就停止并告警。
把一次重试变成可核对的结果
可靠的 AI 调用流程不是“失败就再试一次”,而是让每一步都能被还原:谁创建了任务、发了第几次请求、上游给了什么请求标识、结果是否已经落库、为什么停止。把这些证据写进任务表和日志后,超时只是一个待核对状态,重试才会成为可控的业务动作。


-
407 收藏
-
Golang · Go教程 | 4星期前 | golang · JSON · 故障排查 · Go教程 · 接口设计 · JSON Go 接口兼容性 DisallowUnknownFields 严格解码174 收藏
-
Golang · Go教程 | 4星期前 | golang · sse · Go教程 · net/http · 接口设计 · HTTP Go SSE FLUSH 流式响应 ResponseController463 收藏
-
427 收藏
-
Golang · Go问答 | 1个月前 | JSON · 接口设计 · Go问答 · nil slice · Go 接口兼容 json.Marshal nil slice empty slice 数组字段305 收藏
-
229 收藏
-
482 收藏
-
195 收藏
-
191 收藏
-
科技周边 · 人工智能 | 14小时前 | 异步任务 · openai · AI API · 接口状态 · 轮询 background OpenAI Responses API queued completed188 收藏
-
457 收藏
-
209 收藏
-
科技周边 · 人工智能 | 2天前 | ai · claude · Anthropic API · 文档问答 · 可追溯回答 · Claude 引用 Anthropic Messages API citations document block295 收藏
-
374 收藏
-
309 收藏
-
238 收藏
-
科技周边 · 人工智能 | 3天前 | 人工智能 · transformers · Hugging Face · 文本生成 · 模型评估 · Hugging Face Transformers generate output_scores compute_transition_scores 长度惩罚 生成概率374 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习