最近我在自己的工具站里补了一条 AI 生图的完整付费链路。最开始看起来只是“调一个图片生成接口”,但真正做到可上线,会发现它不只是一个接口调用问题,而是一套完整的产品闭环:

  • 用户每天有 1 次免费生图额度;
  • 超出免费次数后按张计费;
  • 支付不能跳出当前体验太远,最好是站内小窗完成;
  • 生图可能耗时较长,不能让前端接口一直阻塞;
  • 用户支付回来后,要能继续看到生成进度和历史结果;
  • 如果生成失败或者少返回图片,要能自动退款;
  • 后台还要保留人工兜底退款入口。

这篇文章记录一下这条链路的实现思路和踩坑点。

1. 为什么不能只做一个“生成图片接口”

AI 生图和普通文本接口不太一样,它有几个明显特点:

  1. 请求耗时不稳定,可能几十秒,也可能更久。
  2. 用户通常关心结果图,而不是接口响应本身。
  3. 多图生成可能出现“部分成功”,比如要 3 张只返回 2 张。
  4. 一旦接入付费,就必须处理异常退款。

所以我最后没有采用“前端发起请求,然后一直等接口返回”的方式,而是拆成了:

  • 创建生成任务;
  • 后台异步执行;
  • 前端轮询任务状态;
  • 结果进入生成记录;
  • 支付订单和生成记录关联;
  • 失败或少图时退款。

页面上显示“已等待多少秒”,本质上不是前端在阻塞等待,而是前端在告诉用户:任务已经进后台了,现在正在轮询状态,页面没有卡死。

2. 免费额度与计费规则

这次的产品规则比较简单:

  • 每个账号每天按北京时间自然日有 1 次免费生图机会;
  • 免费额度用完后,每张图片收费 0.2 元;
  • 用户一次可以选择生成多张;
  • 订单金额 = 图片张数 × 单张价格。

这里我没有把它做成积分消耗,而是直接按次/按张付费。原因是图片生成更像一个明确的成本项,用真实金额表达会更清楚,也更方便后面做退款。

3. 支付体验:不要把用户扔出页面

一开始最容易想到的是跳转到支付页,但这会带来几个体验问题:

  • 用户离开生图页面后,不知道任务是否还在;
  • 支付回来后,页面状态容易丢;
  • 如果生成时间长,用户会以为没反应。

所以我更倾向于站内小窗支付:

  1. 用户选择质量、格式、数量;
  2. 如果免费额度不够,前端弹出支付窗口;
  3. 支付成功后,原页面继续提交/展示生成状态;
  4. 即使用户刷新页面,也能从“我的生成记录”里找回结果。

这个体验对工具站来说比较重要,因为用户不是来“买一个订单”的,而是来“完成一次图片生成任务”的。

4. 异步生成与历史记录

后端在收到生成请求后,会先创建一条生成记录,状态为“生成中”。然后把真正的图片生成逻辑放到后台执行。

前端拿到任务 ID 后,做两件事:

  • 显示“生成任务已提交,正在后台生成中”;
  • 定时刷新任务状态和最近生成记录。

这样即使图片接口比较慢,用户也能看到明确反馈。

生成记录里我保留了:

  • prompt 摘要;
  • 生成状态;
  • 图片数量;
  • 首图预览;
  • 详情入口;
  • 下载入口;
  • 价格信息。

这样支付回来后,用户不用靠浏览器当前状态,也能从历史记录里继续找到结果。

5. 最容易忽略的点:退款

接入支付以后,最不能忽略的是异常路径。

这次主要处理了三类退款场景:

5.1 生成完全失败

如果用户已经付费,但后台提交任务失败、上游返回失败、或者生成过程异常,那么系统应该主动发起退款,而不是只把订单释放出来让用户下次再用。

原因很简单:用户付的是这次生成的钱,如果这次失败了,就应该退这笔钱。

5.2 多图少返回

比如用户付费生成 3 张,但实际只成功返回 2 张,那么应该退缺少的 1 张金额。

这里的关键是不能只看任务是否“成功”,还要比较:

  • 用户请求的图片数量;
  • 订单可覆盖的图片数量;
  • 实际成功入库的图片数量。

然后按缺口计算退款金额。

5.3 后台人工兜底

自动退款并不能覆盖所有情况,比如:

  • 支付平台接口临时失败;
  • 订单状态异常;
  • 管理员线下已经退款;
  • 业务判断和系统记录不一致。

所以后台必须保留人工入口。

一开始我把“主动退款”放在列表批量 action 里,这样虽然符合 Django Admin 的默认操作习惯,但对退款来说不安全。后来调整成:

  • 每笔订单单独进入详情;
  • 点击“手动退款”;
  • 手动填写本次实际退款金额;
  • 确认后才调用支付平台退款接口;
  • 已退款后待退金额归零。

这样可以避免批量误操作,也不会默认按整单金额退款。

6. 后台订单字段设计

支付订单里除了基本字段外,我额外保留了退款相关字段:

  • 退款状态:无需退款、待人工退款、已退款;
  • 待退图片数;
  • 待退金额;
  • 退款备注;
  • 退款时间。

这里有个细节:如果已经退款成功,列表上就不应该继续显示“待退金额 0.6 元”。否则管理员会疑惑:钱不是已经退了吗,为什么还待退?

所以退款成功或人工标记已退款后,待退金额和待退图片数都应该归零。实际退款金额可以写入备注,作为审计信息保留。

7. 这次实现后的流程

最终流程大概是:

  1. 用户进入 AI 生图页;
  2. 系统判断今日免费额度;
  3. 免费额度不足时创建支付订单;
  4. 用户在站内小窗完成支付;
  5. 支付成功后提交后台生成任务;
  6. 前端显示生成中,并轮询状态;
  7. 生成完成后展示历史记录和图片;
  8. 如果失败或少图,后端自动退款;
  9. 自动退款失败时进入待人工处理;
  10. 管理员可在单笔订单详情里手动填写金额退款。

8. 总结

AI 生图功能从 Demo 到产品,中间差的不是一个模型接口,而是一整套异常路径和用户体验。

我这次最大的感受是:

  • 生图要异步化,否则前端体验会很差;
  • 支付后要保留页面连续性,不能让用户丢状态;
  • 历史记录非常重要,它是支付回来后找结果的兜底;
  • 少图和失败都要自动退款;
  • 后台退款必须支持人工指定金额,不能默认整单退,也不能批量误退。

做完这些以后,这个功能才更接近一个真正能上线的 AI 工具,而不是一个简单的接口调用页面。
体验地址:https://web.fushengtool.com/dev/ai-image

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐