记录一下那天晚上的排查过程。用户点停止之后前端 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 只能省带宽,检测到断开后主动结束生成,才能让计费停在那一刻。改动前把原配置备份一份,出问题能马上回滚,这比任何技巧都实用。

作者 9823189