乱码源于客户端未正确处理sse的utf-8解码或事件块分割;需确保响应头含charset=utf-8、用textdecoder("utf-8")配stream:true、按\n\n切分并过滤注释行,或使用sseclient-py等专用解析器。
☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 多模态理解力帮你轻松跨越从0到1的创作门槛☜☜☜

模型输出乱码不是模型本身出错,而是客户端没正确处理 SSE 流式响应体的字符编码或换行分隔逻辑。
为什么用 SSE 接 Fable 5.1 时容易出现乱码
Fable 5.1 的流式接口强制走 SSE(Server-Sent Events),响应头固定为 Content-Type: text/event-stream;charset=utf-8,但很多客户端库(尤其是旧版 fetch 或未配置解码器的 EventSource)会忽略 charset=utf-8,默认用 ISO-8859-1 解析字节流,导致中文、emoji、数学符号全变成 或乱码。
另一个常见原因是没按 SSE 协议规范切分事件块:每条消息必须以 data: 开头,以双换行 \n\n 结尾。如果前端直接把整个响应体当 JSON 解析,或用 response.text() 一次性读取,就会把多条 data: 拼在一起,JSON 解析失败后显示原始字符串片段——看起来像“乱码”。
- 检查响应头是否真包含
charset=utf-8(用 curl -I 或浏览器 Network 面板确认) - 不要用
response.json()直接解析流式响应;必须监听message事件或手动按\n\n切分 - Node.js 环境下,
node-fetch低于 v3.3.0 默认不支持text/event-stream自动解码,需手动decoder.decode(chunk)
Python requests + SSE 客户端典型乱码修复
用 requests 做流式请求时,r.iter_lines() 默认按 \n 分割,但 SSE 要求识别 data: 前缀和完整事件块,直接迭代会把一条消息切成多段。
将 Claude Agent SDK 与 You.com HTTP MCP 服务器集成,支持 Python 和 TypeScript。当开发者提及 Claude Agent SDK、Anthropic Agent SDK 或将 Claude 与 MCP 工具集成时使用。
正确做法是用专门的 SSE 解析器,比如 sseclient-py:
from sseclient import SSEClient
import json
<p>url = "<a href="https://www.php.cn/link/892fd67cd220133aaff1c1121b9111fc">https://www.php.cn/link/892fd67cd220133aaff1c1121b9111fc</a>"
headers = {"Authorization": "Bearer " + os.environ["FABLE_API_KEY"]}
params = {"model": "deepseek-v4", "stream": True}</p><p>client = SSEClient(url, headers=headers, params=params)
for event in client:
if event.data and event.data.strip() != "[DONE]":
try:
chunk = json.loads(event.data)
print(chunk["choices"][0]["delta"].get("content", ""))
except json.JSONDecodeError:
continue # 忽略格式异常的 data 行</p>
- 别自己写
iter_lines()+json.loads()组合,SSE 的data:可能跨行、带注释:行 -
sseclient-py会自动处理 UTF-8 解码、事件分割、重连逻辑,比手搓可靠得多 - 注意
event.data是已去除data:前缀的纯字符串,直接json.loads即可
前端 fetch + TextDecoder 处理乱码的关键点
现代浏览器中,fetch 流式响应必须配合 TextDecoder 显式指定 UTF-8,否则 reader.read() 返回的 Uint8Array 会被错误解释:
const decoder = new TextDecoder("utf-8");
const response = await fetch("/v1/chat/completions", {
headers: { "Authorization": "Bearer " + apiKey },
body: JSON.stringify({ model: "deepseek-flash", stream: true })
});
<p>const reader = response.body.getReader();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const text = decoder.decode(value, { stream: true }); // 关键:stream: true
// 再按 \n\n 切分 text,提取 data: 后的内容
}</p>
-
decoder.decode(value, { stream: true })中的stream: true不能省——它让解码器缓存末尾不完整的 UTF-8 字节序列(比如一个中文字符被切在两个 chunk 中间) - 别用
new TextDecoder().decode(value),缺少stream: true会导致中文被截断成乱码 - SSE 事件可能包含空行、注释行(以
:开头),解析前先过滤掉非data:行
乱码问题九成出在字符解码或事件解析层,而不是模型返回了错误内容。Fable 5.1 的 SSE 输出严格遵循标准,只要客户端按协议走,就不会有乱码——但这个“按协议走”的细节,恰恰是多数人调试时最先跳过的环节。










