OpenAI Compatible SSE 流式输出接入与排错
先分清 Responses 与 Chat Completions 的事件结构,再检查认证、缓冲和超时。本文明确区分已验证路由与尚未验证的模型能力。
流式响应改变了什么
非流式请求会等完整响应生成后再返回。流式请求则在模型生成内容时持续发送事件。OpenAI 的 HTTP 流式接口使用服务器发送事件(SSE);Responses API 与 Chat Completions 的事件结构不同。
| 接口 | 增量文本位置 | 结束信号 |
|---|---|---|
| Responses | response.output_text.delta 等类型化事件 | response.completed 或错误事件 |
| Chat Completions | chunk.choices[0].delta.content | SSE 终止行 data: [DONE] |
流式测试前先验证 Key 和模型
先请求 GET /v1/models,复制当前 Key 可见的准确模型 ID,再发送一个简短的非流式请求。这样可以先排除认证和模型路由问题,避免把它们误判为流解析错误。
curl -sS https://monkeytheme.com/v1/models \ -H "Authorization: Bearer $OPENAI_API_KEY"
2026 年 8 月 3 日,未携带 Key、且请求体包含 stream: true 的生产探测分别请求了 /v1/responses 和 /v1/chat/completions,两者均返回结构化的 401 API_KEY_REQUIRED。这只能证明请求到达认证层,不能证明每个模型都支持已认证流式输出。
用 Python SDK 接收流式事件
官方 Python SDK 支持 stream=True。下面的 Responses 示例只输出文本增量,并单独处理错误事件。
from openai import OpenAI
client = OpenAI(
api_key="YOUR_KEY",
base_url="https://monkeytheme.com/v1",
)
stream = client.responses.create(
model="MODEL_ID_FROM_LIST",
input="Write one short sentence.",
stream=True,
)
for event in stream:
if event.type == "response.output_text.delta":
print(event.delta, end="", flush=True)
elif event.type == "error":
print("\nstream error:", event)如果使用 Chat Completions,应遍历 chunk 并读取 chunk.choices[0].delta.content。请勿用 Responses 事件解析器处理 Chat Completions。
用 Node.js SDK 接收流式事件
import OpenAI from "openai";
const client = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
baseURL: "https://monkeytheme.com/v1",
});
const stream = client.responses.stream({
model: "MODEL_ID_FROM_LIST",
input: "Write one short sentence.",
});
stream.on("response.output_text.delta", (event) => {
process.stdout.write(event.delta);
});
await stream.finalResponse();官方 Node SDK 也提供 Chat Completions stream runner,但返回结构不同。迁移时应按接口文档改解析逻辑,不能只替换字段名。
用 curl 查看原始 SSE 边界
curl -N https://monkeytheme.com/v1/responses \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: text/event-stream" \
-d '{
"model": "MODEL_ID_FROM_LIST",
"input": "Reply with OK",
"stream": true
}'-N 会关闭 curl 的输出缓冲。如果 curl 能逐条显示事件,而应用只能一次性显示全部内容,应检查应用解析器以及应用和网关之间的代理。
流式响应卡住时检查代理
Nginx 官方文档说明,proxy_buffering off 会在收到上游响应时同步传给客户端;proxy_read_timeout 计算的是两次连续读取之间的等待时间,并非整个响应的总时长。
location /v1/ {
proxy_pass http://your_upstream;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_buffering off;
proxy_read_timeout 300s;
}按现象定位故障层
| 现象 | 优先检查 |
|---|---|
| 收到事件前返回 401 | Key、Authorization 请求头和网关认证 |
| 收到事件前返回 404 | Base URL、重复的 /v1 或不支持的接口 |
| 所有事件一次性出现 | 客户端输出缓冲或反向代理缓冲 |
| 静默一段时间后断流 | 连续读取之间的超时;记录时间戳和 request ID |
| 重连后文本重复 | 应用重试或重连逻辑;不要假设流可以从任意字节续传 |
资料与相关教程
常见问题
流式输出必须使用 WebSocket 吗?
本教程讲的是基于服务器发送事件的 HTTP 流式响应。这里的 Responses 和 Chat Completions 示例都不要求 WebSocket。
为什么内容最后一次性出现?
先用 curl -N 测试。如果 curl 能逐条输出而应用不能,应检查客户端缓冲;如果两者都不能,应检查反向代理缓冲和上游响应。
Responses 和 Chat Completions 可以共用解析器吗?
不可以。Responses 使用 response.output_text.delta 等类型化事件;Chat Completions 的增量文本位于 choices[0].delta.content。
401 是否说明不支持流式输出?
不是。结构化 401 表示请求在模型输出前认证失败。修复 Key 或请求头后,再使用该 Key 可见的模型测试流式输出。
本文是否确认 MonkeyAI 所有模型都支持流式输出?
没有。公开探测只验证两个接口路径可以到达认证层。已认证流式能力必须按计划使用的模型和接口分别测试。