AI中转遇到上游返回chunk乱码

AI中转服务在转发大模型流式响应时,最让人头疼的就是上游返回的chunk出现乱码。
它通常表现为中文变成问号或火星文、接口输出的换行位置错乱、以及多个data块粘在一起导致解析失败。
这些问题大多出在编码、换行和分隔符三个环节。
下面按排查顺序,给出可以直接套用的调试方法。

第一步:先复现并抓取原始响应

在动手改配置前,先用curl直接打上游接口,把chunk原样保存下来,避免中转服务二次加工干扰判断。
以下命令只打印响应头:

curl -i -N -H "Authorization: Bearer $YOUR_KEY" https://upstream.example.com/v1/chat/completions \
  -d '{"model":"gpt-3.5-turbo","stream":true}' -o /tmp/raw_chunk.txt

保存后重点看两处:响应头里的Content-Type是否包含charset=utf-8,以及chunk内容中是否出现\xef\xbb\xbf(UTF-8的BOM标志)。
如果Content-Type没有明确charset,很多HTTP客户端会默认按ISO-8859-1解码,中文自然就乱了。

第二步:从编码层面把字符集统一成UTF-8

确认原始响应确实正常后,再检查中转服务转发时是否做了错误的编码转换。
常见坑有两个:

  • 上游返回UTF-8,中转服务用gzip压缩后没有正确设置Content-Encoding,客户端解压失败产生乱码。
  • 代码里用decode('utf-8', errors='ignore')吞掉异常,导致字符被截断成半个。

建议在中转服务中强制做一次标准化输出。
以Python为例,在返回响应前统一转码:

# 强制将上游字节流转为UTF-8文本再转发
text = raw_bytes.decode('utf-8', errors='replace')
clean_text = text.replace('\ufeff', '')  # 去掉BOM

如果是Java或Go服务,检查响应头是否显式指定Content-Type: application/json; charset=utf-8

第三步:处理换行符不一致引发的错乱

上游流式响应通常使用\n分隔不同事件,但有些模型服务端会返回\r\n,或者在中转过程中被Nginx等代理吞掉换行。
典型现象是:用调试工具能看到{"choices":[...]}一段一段出现,但用tail看时全挤在一行。

解决办法是通过正则将换行标准化:

import re
normalized = re.sub(r'\r\n|\r', '\n', chunk_text)

另外,
如果Nginx开启了chunked_transfer_encoding
注意保持proxy_buffering off;
否则缓冲区可能等到数据积攒后才整体转发,
破坏流式时机的感知。

第四步:分隔符不匹配导致的数据粘包

大模型接口的流式格式多为SSE(Server-Sent Events),每个事件以data:开头,以空行\n\n结束,最后再用data: [DONE]标示完成。
乱码问题如果表现为“一段数据里混杂多个data前导”,通常是分隔符处理失误。
可以写段脚本先拆分再解析:

sed 's/^data: //; /^\s*$/d' /tmp/raw_chunk.txt | head -50

如果希望可靠地重组JSON,用Python读流并逐行判断:

for line in sys.stdin:
    line = line.strip()
    if not line:
        continue
    if line.startswith("data:"):
        payload = line[5:].strip()
        if payload == "[DONE]":
            break
        # 对payload做json.loads处理

避坑清单:这三个细节最容易忽略

  • 不要随意改变上游的Content-Type,尤其是把text/event-stream改成application/json,会导致客户端错误解析二进制流。
  • 中转服务不要开额外的字符编码转换插件,例如某些网关自动按GBK转换,必须关闭。
  • 测试时避免用浏览器直接访问流式接口,浏览器解码方式不同,容易误报乱码,建议用curl或写脚本验证。

验证是否修好

执行完上述调整,重新用curl拉取并检查三点:第一,响应头包含charset=utf-8
第二,chunk中的中文能正确显示,无BOM;
第三,用Python脚本逐行解析能完整拿到所有data字段并以[DONE]结尾。
命令如下:

curl -N -H "Authorization: Bearer $YOUR_KEY" YOUR_GATEWAY_URL | python3 inspect_sse.py

如果输出正常,说明AI中转的chunk乱码问题已经在编码、换行和分隔符三个层面解决。
以后再遇到类似报错,优先按这个顺序排查,能省下大量翻日志的时间。

分享到:
上一篇
SGLang开启KV缓存复用,降低重复prompt显存开销教
下一篇
中转系统对接企业微信告警,接口异常自动推送报警消息
1
系统公告

机房迁移升级通知

尊敬的用户: IP 段 103.23.148.x、156.224.29.x 原香港一区线路波动、攻击频繁,平台定于 7 月 5 日凌晨分批迁移至香港 GIA 机房,硬件升级 AMD 铂金机型。 迁移均在凌晨操作,最大程度降低业务影响,迁移期间服务器临时关机; 升级后配置不降低、费用不涨价,数据默认同步迁移; 迁移后 IP 全部更换,请及时修改域名解析、防火墙白名单; 建议提前备份重要数据,有问题可联系在线客服。 感谢理解与支持! 泽御云科技 2026.06.30
服务中心
客服
在线客服
24小时为您服务
咨询
联系我们
联系我们,为您的业务提供专属服务。
24/7 技术支持
如果您遇到寻求进一步的帮助,请过工单与我们进行联系。
24/7 即时支持
泽御云
售前客服
泽御云
泽御云
售后客服
泽御云
技术支持
评价
您对当前页面的整体感受是否满意?
😞
非常不满意
😕
不满意
😐
一般
🙂
满意
😊
非常满意