记录一下那天晚上的排查过程。用户点停止之后前端 abort 掉 fetch,服务端日志显示连接被重置,可账单里这一条请求的 output token 仍按完整长度计算,一天下来多花了一笔。
刚开始盯着「服务端没监听断开事件,仍然把整个流写完」,折腾了半个多小时,排掉了。
真正麻烦的地方在于,几个原因的现象几乎一样。abort 只断开客户端连接,服务端生成不会立刻停下。少数情况下是已经生成的 token 照样计费,取消不退还。
不容易想到的是,反向代理的缓冲让连接关闭更晚,生成时间被拉长。
上来先用限制读取时间模拟客户端提前断开
curl -N --max-time 2 https://api.openai.com/v1/chat/completions -H "Authorization: Bearer $OPENAI_API_KEY" -H "Content-Type: application/json" -d '{"model":"gpt-4o-mini","messages":[{"role":"user","content":"写一篇长文"}],"stream":true}' | wc -c
然后对比中断与完整两次收到的字节数
wc -c partial.txt full.txt
再往下确认框架是否提供断开检测能力
python -c "from fastapi import Request;print(hasattr(Request,'is_disconnected'))"
等前面都确认过,再把单次输出上限调小以减少中断浪费
curl -N https://api.openai.com/v1/chat/completions -H "Authorization: Bearer $OPENAI_API_KEY" -H "Content-Type: application/json" -d '{"model":"gpt-4o-mini","messages":[{"role":"user","content":"写一段"}],"max_tokens":300,"stream":true}'
别只看报错消失,验证要多做一步。中断请求的 usage 里 output_tokens 明显小于完整请求,长文场景单次费用下降,服务端日志出现主动取消生成的记录。
容易忽略的是,省钱的着力点在服务端,客户端 abort 只能省带宽,检测到断开后主动结束生成,才能让计费停在那一刻。改动前把原配置备份一份,出问题能马上回滚,这比任何技巧都实用。
