先看现象。调用流式接口时加了 stream=True,首字延迟仍是 8 秒,和不开完全一样,抓包发现客户端在等整个响应结束,代码里最后一行用的是 response.text。

把日志和配置对完,能解释这个现象的基本就这几处。取 text 或 json 会强制读完整段。少数情况下是iter_lines 有默认缓冲 需要指定 chunk_size。

不容易想到的是,中间层开了 gzip 数据攒够才解压。

还有一种情况,连接池复用了上一次没读完的响应。

先改成逐行迭代并打印首包时间

python -c "import time,requests;t=time.time();r=requests.post('https://api.openai.com/v1/chat/completions',headers={'Authorization':'Bearer $KEY'},json={'model':'gpt-4o-mini','stream':True,'messages':[{'role':'user','content':'hi'}]},stream=True);print(time.time()-t)"

控制读取粒度并只看首条增量

python stream_client.py --chunk-size 1 --show-first-token

随后关掉压缩再测一次首包

curl -N https://api.openai.com/v1/chat/completions -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' -d @req.json

末了用上下文管理器确保响应及时关闭

python -c "print('use context manager')"

我习惯把每一步的执行时间和结果记在一边,后面复盘省事。

恢复的判定其实很直接。首包时间降到 1 秒以内,回调能实时打印每一段,连接池里没有悬挂响应。

开了 stream 只是不立即下载全部内容,取 text 等于白开,读取方式要一起改。如果同一现象隔几天又出现,说明根因没找到,别当偶发处理。

作者 9823189