先保留状态、请求标识和响应体错误代码
很多 SDK 把各种失败包装成一个异常,但恢复动作不能只根据异常文案决定。最小故障记录应包含时间、接口和模型、HTTP 状态、服务方请求标识、响应体错误代码、是否收到完整响应,以及本次操作是否可能写入外部系统。不要记录密钥、完整提示词或个人信息。若根本没有 HTTP 响应,应标记为网络或客户端超时,不要臆造一个 500。
time: 2026-10-17T06:00:00Z
operation: create_report
http_status: 429
provider_error_code: rate_limit_exceeded
request_id: req_demo_42
retry_after: 30
side_effect: yes
result_confirmed: unknown
这份模板有意没有响应体原文:只保留足以追踪问题的字段。各供应商的错误码、请求标识头名称不同,请按实际接口映射。
案例一:429 和 30 秒等待
HTTP/1.1 429 Too Many Requests
Retry-After: 30
Content-Type: application/json
{"error":{"code":"rate_limit_exceeded"}}
429 表示请求速率受到限制;Retry-After: 30 表示服务方建议至少等待 30 秒后再请求。先检查同一账户的并发、队列长度和速率限制,再安排有上限的重试。如果一百个工作进程同时收到 429,全部在第 30 秒一起重试会形成新高峰,因此仍需控制共享队列并加入抖动。若响应没有 Retry-After,以供应商文档为准,采用有最大等待和总次数限制的退避策略。
在错误分诊工具中选择“429”,填入“30”,先查看只读操作的建议;再勾选“可能创建记录、发消息或扣费”。你会看到等待时间不变,但重试前多了确认业务结果与幂等机制的步骤。
案例二:写入操作超时
POST /reports
client_timeout: 10s
HTTP response: none
local_request_id: report_42
客户端十秒后断线,服务器可能还在处理,也可能已写入成功。先按业务标识查询 report_42 是否存在;若服务提供幂等键,则用同一个键核实或重试。若没有查询接口和幂等保证,应暂停自动重试并人工确认,避免生成两份报告。把这例选成“客户端超时 / 断线”并勾选副作用,就能得到相同的判断顺序。
案例三:400 参数错误
HTTP/1.1 400 Bad Request
Content-Type: application/json
{"error":{"code":"invalid_request","field":"max_output_tokens"}}
这里优先查该字段的类型、取值范围及模型是否支持它。用去掉业务数据的最小请求重现;与成功请求做结构差异对比。固定间隔重试相同的请求通常没有意义。若错误信息指向 JSON 语法,先用JSON 检查器确认请求体能解析;解析通过以后仍需核对字段契约。
一张可执行的处理表
| 观察 | 先查什么 | 能否立即重试 |
|---|---|---|
| 400 / 422 | 请求字段、类型和限制 | 先修正输入 |
| 401 / 403 | 凭证、权限和目标项目 | 先修正配置 |
| 429 | 速率、并发、Retry-After | 等待并控制重试 |
| 5xx | 服务状态、请求标识、响应体 | 只在安全边界内重试 |
| 无响应 / 超时 | 网络阶段和业务结果 | 写入操作先核实结果 |
依据:RFC 6585:429、RFC 9110:Retry-After。本站的副作用处理建议是工程实践判断,不是 HTTP 规范对所有业务的保证。