超时不等于任务没有发生
AI API 接入里最容易误判的一句话是“请求超时了,所以没有执行”。实际情况往往相反:客户端断开、代理超时或前端等待结束时,模型侧可能已经收到请求,后台队列也可能已经创建任务。此时如果前端直接再发一次,图片生成、文档总结、客服回复、表格写入都可能被重复执行。
永沃云枢在整理开发者 AI 调用方案时,会把重试分成两类:读请求可以短重试,写请求必须先有 idempotency key。凡是会扣余额、生成文件、发送消息、回写业务表、触发 webhook 的调用,都不能只靠“失败后再点一次”。模型调用管理要记录一次业务意图,而不是只记录一次 HTTP 请求。
适用场景
适合 AI 文生图、长文档解析、批量摘要、AI 自动化办公回写、客服工单生成、合同字段抽取、Codex 接入后的后台任务,以及通过 CCSwitch 配置或网关转发的多模型调用。前提是业务侧能生成唯一业务单号,后端能保存任务状态,并能把上游 AI 模型接口的 request_id 或 task_id 记录下来。
操作步骤:从业务意图生成幂等键
- 先定义业务动作。比如“用户 1001 对文件 A 做摘要”是一个动作,“浏览器发出第几次请求”不是动作。
- 生成 idempotency key。可以由
tenant_id + user_id + source_id + action + version组合后哈希,也可以由前端创建一次性草稿 ID,后端校验归属。 - 落库前先查重。后端收到请求后先按 key 查询任务表,若已有 running 或 succeeded 任务,返回旧任务状态,不再创建新的 AI API 调用。
- 记录上游标识。发起模型调用后保存 provider、model、request_id、task_id、prompt_version、费用状态和回调地址,方便后续对账。
- 把重试变成查询。前端超时后应查询任务状态,必要时重新订阅结果,而不是重新提交同一动作。
失败表现和排查路径
如果用户反馈“点了两次生成,余额扣了两次”,先查业务任务表是否有同一来源的多条记录,再查 AI API 调用日志是否使用同一个 idempotency key。若没有 key,只能用时间、用户、文件、提示词版本和输出相似度做事后判断,证据会很弱。可以参考 用户取消请求后后台任务和费用状态怎么对齐 与 webhook 验签和重放检查,把请求、任务、回调和费用拆开。
检查命令不一定复杂。开发环境可以先查日志:rg "idempotency|request_id|task_id|retry" logs src server;数据库不可连接时,至少让 Codex 扫描代码里是否有任务唯一索引、状态枚举和重复提交处理。对外部平台来说,不能把“HTTP 200”当成业务完成,也不能把“前端超时”当成上游未执行。
常见问题 / 避坑
第一,不要把毫秒时间戳当幂等键。用户刷新页面、浏览器重试、移动网络抖动都会生成新时间戳,无法阻止重复写入。第二,不要只在前端禁用按钮,移动端回退、脚本调用和多标签页仍能重复提交。第三,不要让失败重试绕过扣费记录;费用状态和任务状态必须一起对账。第四,CCSwitch 配置切换模型后,上游 request_id 格式可能不同,要在自己的任务表里保留统一字段。
检查清单
- 写请求都有 idempotency key,并且 key 来源于业务意图。
- 任务表对 key 有唯一约束或等价保护,不靠前端按钮防重复。
- running、succeeded、failed、cancelled、expired 等状态含义清楚。
- AI 模型接口的 request_id、task_id、provider、model 和费用状态可追踪。
- 前端超时后的动作是查询任务状态,而不是静默重新提交。
- 站内可继续看 AI API 返回 200 但业务没完成、多模型路由 trace_id 日志、AI API 接入专题 和 AI 自动化办公专题。
FAQ:失败任务能不能复用同一个 key
要看失败发生在哪一层。如果请求还没进入模型侧,可以复用同一个 key 重新发起;如果模型侧已经创建任务,只是回调失败,应复用 key 查询旧任务或补回调。只有当业务明确要求重新生成,并且用户确认要产生新结果时,才创建新版本 key。这个规则对 Codex 接入、AI 自动化办公和开发者 AI 调用都适用。
在永沃云枢的使用语境里,https://ai.jn83.com 更强调可复核的模型调用管理。幂等不是为了让接口变复杂,而是为了在网络不稳定、用户重复点击、上游延迟和回调重放之间保住业务一致性。