一次渲染尝试,一个不可变的键。这是处理AI生成图片存储时最小、也最管用的规则。

问题出在重试上。如果生成和上传共用同一个对象键,比如 products/sku-1042/hero.png,两个工作进程就可能同时写入,而存储层没有 If-Match 条件写来仲裁谁赢。后到的字节如果对不上已批准的作业,又没有版本控制和对象锁,存储里就找不回上一版图片。

把传输重试和应用重试分开,是这套设计的关键。同一个尝试的网络重试,重复同一个 PUT 和幂等键;新的渲染尝试,换一个新的对象键。一个稳定的文件名,恰好把这两件事抹平了。

键怎么派生

先给渲染尝试建一条数据库记录:作业ID和尝试序号要在生成或上传字节之前就确定,然后据此派生键,形如 users/u_18/jobs/job_731/attempt-02/1712249123.png。

上传路径要做几件事:为单次渲染尝试生成确定性键、保持对象私有、遇到限流按 Retry-After 或指数退避重试、把被拒绝的响应暴露出来。API 密钥放在环境变量里。

还有一个容易踩的坑:应用之后去请求返回的预签名 URL 时,不要再带上授权头。签名 URL 本身就是临时凭证。桶保持私有,URL 只在鉴权通过后签发,过期时间交给应用决定。

保留期是数据库的决定

上传完成后,把唯一键和渲染状态写进同一个标记尝试完成的数据库事务。如果这张图成为已批准的商品资产,要等事务成功之后,再复制到规范的最终键。唯一键留作保留窗口内的审计线索,规范键只是给消费方用的便捷指针。

没有 If-Match 写入时,晋升要走队列串行化,或者锁住相关数据库行,避免两次批准并行发布。

删除同样需要明确状态。在对象键旁边记录 retain_until、所属用户、同意或订单上下文,以及删除状态。生命周期过期能执行天级清理,但最短间隔是一天,所以按小时或即时擦除的承诺,得靠应用自己拥有的删除作业。GDPR 第17条可以让擦除变成产品要求,而不只是存储优化。

元数据可以随对象走,但服务端除了前缀列举之外搜不了它。提示词、作业状态、归属和删除证据,应该放在数据库里,让评测工具能查。

保留多久算对,没有统一答案。法律依据、客户预期、欺诈审核和模型评测需求会往不同方向拉,周期和删除 SLO 要由产品和法务负责人来定。工程上可测的不变量更简单:过了截止时间,不应再有活跃的数据库行或可下载的对象。

上线前测什么

先测正确性,再谈吞吐和 token 成本。可用的记分卡不大:

  • 并发尝试下的唯一键创建
  • 429 之后的确定性重试行为
  • 数据库与对象的对账
  • 已批准尝试的正确晋升
  • 签名链接的过期
  • 按承诺截止时间的删除

孤儿对象要和缺失的数据库引用分开统计,因为它们指向事务失败的两半。再测隐私:没有授权的过期链接,渲染图就取不到;链接过期后,访问应当停止。别拿对象元数据当索引,前缀列举能帮对账,但可搜索的事实来源仍是数据库。

提示词成本当然重要,只是排在后面。把所有探索性渲染永久留着,会让薄弱的作业状态设计藏在不断膨胀的存储占用背后;全部立即删掉,又让模型回归难以检查。按有文档记录的保留等级抽样保留评测所需输出,其余按期删除,提示词和评测记录留在数据库里,别把对象键当成数据集目录。