一套由非工程负责人用 Claude Code 快速上线的 SaaS,被工程师接手后,先在账单上露了馅:某一天的 AI 费用,约占整月 LLM 账单一半,还高过整月服务器成本。
反常点不在“用户突然特别爱用 AI”。原文披露,异常来自同一租户的一批重型批处理任务,被任务队列重复执行了 21 次。
更要命的是,LLM API 调用本身都成功返回,也都产生了计费。失败发生在后面:结果写入数据库时,生产库缺少新字段,任务报 500,然后被队列自动重试。
这类事故看起来像账单问题,底层其实是工程边界问题:成功的外部调用,被一次确定性数据库错误反复作废。
账单为什么会被放大:成功调用被丢弃了
这条链路很短,也很典型。
批处理先调用多个 LLM,拿到结果后写库。新代码已经上线,但数据库迁移没有跟上。生产库缺字段,写入失败,任务返回 500。
队列看到 500,就按策略重跑。可前面的 LLM 调用已经完成,供应商不会因为你的数据库没写进去就退费。
下一轮重跑时,系统又没有 item 级状态,也没有跳过已完成内容。于是整批任务从头再来。一次成功调用,变成 21 次成功计费。
| 环节 | 实际发生了什么 | 为什么会烧钱 | 该下的判断 |
|---|---|---|---|
| LLM 调用 | 调用成功返回 | 每次重跑都会重新计费 | 不是 LLM API 失败重试 |
| 数据库写入 | 缺少字段,写入失败 | 成功结果无法落库 | 故障是确定性的 |
| 队列策略 | 500 自动重试 | 同一批任务跑了 21 次 | 稳定性机制放大成本 |
| 批处理设计 | 没有幂等跳过 | 不能复用已完成结果 | 重跑变成重复扣费 |
我更在意的是“成功之后失败”这个细节。
传统后端任务重试几次,主要消耗自己的 CPU、队列和数据库。LLM 应用不一样。只要外部模型调用成功,成本已经发生。后面的保存失败,不会撤销前面的账单。
这就是 LLM 后端最容易低估的地方:重试不再只是可靠性工具,也可能是账单放大器。
这不是低代码的锅,但快速上线会放大老问题
原文提到,这套 SaaS 由非工程负责人用 Claude Code 快速上线。这个信息容易被读歪,好像事故的原因是“非工程人员写了生产系统”。我不太买账。
根因更具体:代码先于数据库迁移上线,队列对 500 自动重试,批处理缺少幂等跳过机制。三件事叠在一起,才把一次确定性错误放大成成本事故。
AI 编程工具降低了做功能的门槛,但没有替你取消生产系统的旧规矩。数据库迁移、任务队列、幂等、回滚、告警,这些东西还是要有人兜底。
支付系统早就吃过这类亏。Stripe 这类 API 支持 Idempotency-Key,就是为了避免网络抖动或重试造成重复创建对象、重复扣款。LLM 调用不是支付,但在工程上已经很接近“成本型副作用”。
它一旦成功,就会落到账单上。
对接手这类系统的技术负责人,现实动作会很具体:
- 先暂停或限流高成本批处理,不要等月底账单再复盘。
- 延后上线依赖新表、新字段的大任务,确认迁移先完成。
- 把 LLM 调用从“普通函数调用”改成“有成本、有状态、可中止的外部操作”。
对负责 LLM 后端的工程师,优先级也很清楚:先查队列重试,再查幂等,再查账单归因。不要只盯接口错误率。这个案例里,接口错误率未必能告诉你钱正在被重复花掉。
限制也要说清楚。目前原文只确认单一租户的一批任务被重复执行 21 次,不能把它写成全站事故,也不能推断公司规模、具体损失金额或云厂商问题。
证据能支撑的结论是:一批高成本任务,在确定性故障下被自动重试放大了。
这已经足够值得警惕。
接下来该观察什么:三道闸有没有补上
这类事故修不修得住,别只看一句“我们已经修复”。要看三道闸有没有补上。
| 观察变量 | 应该看到什么 | 没有的话会怎样 |
|---|---|---|
| 重试边界 | 确定性错误进入失败队列或人工处理 | 字段缺失、权限错误会继续烧钱 |
| 幂等记录 | item 级状态、结果缓存、已完成跳过 | 批处理重跑时重复调用 LLM |
| 成本监控 | 按租户、任务、环境拆账和告警 | 只能在月度账单里发现损失 |
确定性错误不该无限重试。column does not exist、参数格式错误、权限错误,这些都不是“等一等就会好”的问题。指数退避解决不了 schema 没迁移。
成本型任务也要能去重。批处理至少要记录到单个 item:哪些已调用,哪些已保存,哪些失败可重试。必要时,LLM 结果应该先落到可恢复位置,再进入后续写库流程。
部署顺序更不能省。依赖新字段的代码上线前,数据库迁移要先完成。若必须灰度,也要保证旧字段和新字段可以短期共存。
成本监控要按租户、任务和环境拆开。生产密钥和测试密钥分离,单任务费用上限,异常 token 消耗告警,都不是锦上添花。它们是止损装置。
接下来最该看的变量,其实只有两个:一是队列能不能识别“不可重试错误”;二是每次 LLM 调用能不能被追踪到具体租户、任务和业务对象。
如果这两点没有,团队就只能在账单里看事故的残影。
开头那张反常账单,真正暴露的不是用户多用了 AI,而是系统不知道一次成功调用已经花过钱。服务器时代,重试多半是在买稳定;LLM 时代,重试无界,就可能是在重复付款。
