事情本身不复杂,线索都在日志里。自研网关转发 OpenAI 的流式响应,Python 客户端逐行 json.loads 时偶尔抛 JSONDecodeError,原文 Expecting value: line 1 column 1 (char 0),把出错的那一行打出来只有一个冒号开头的注释。

第一反应是「一个事件被拆成多行 data 需要先拼接」,验证下来不成立。

排查方向其实有限,先把可能性排一排。冒号开头的注释行不是 JSON。少数情况下是data: 前缀没剥掉就直接解析。

少数情况下是空行被当成一条数据送进解析。

第一件事是把原始字节流落盘看真实行

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

再往下按 SSE 规范过滤注释并拼接多行

python sse_parse.py --in stream.txt --skip-comment --join-multi

遇到 DONE 标记立即结束解析

python -c "print('break on [DONE]')"

补一条覆盖心跳行的单测

python -m pytest tests/test_sse.py -q

中途换过一次思路,把范围缩到最小的那一层,反而快了。

恢复的判定其实很直接。同一份流解析零异常,chunk 数与服务端日志一致,末尾能正常收到结束标记。

提醒一点。SSE 不是每行都是 JSON,注释、多行 data、空行都要处理,很多解析错误其实来自心跳。同一份配置在测试环境跑通,不代表线上没事,两边的默认值经常不一样。

作者 9823189