OpenAI Compatible SSE 流式输出接入与排错

先分清 Responses 与 Chat Completions 的事件结构,再检查认证、缓冲和超时。本文明确区分已验证路由与尚未验证的模型能力。

SSE 流式响应Responses APIChat Completions已验证认证层路由

流式响应改变了什么

非流式请求会等完整响应生成后再返回。流式请求则在模型生成内容时持续发送事件。OpenAI 的 HTTP 流式接口使用服务器发送事件(SSE);Responses API 与 Chat Completions 的事件结构不同。

接口增量文本位置结束信号
Responsesresponse.output_text.delta 等类型化事件response.completed 或错误事件
Chat Completionschunk.choices[0].delta.contentSSE 终止行 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;
}
这是一段排障示例,不是可以直接复制到生产环境的策略,也不是 OpenAI 规定的超时值。修改前应检查现有 Nginx 配置、上游限制和滥用防护。

按现象定位故障层

现象优先检查
收到事件前返回 401Key、Authorization 请求头和网关认证
收到事件前返回 404Base 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 所有模型都支持流式输出?

没有。公开探测只验证两个接口路径可以到达认证层。已认证流式能力必须按计划使用的模型和接口分别测试。