AI API 聚合平台:190+ 大模型、图像与视频模型

APIMart 流式输出怎么配置?从 stream:true 到 SSE 处理

更新于 2026-10-31 · apimart.cyou

简答:APIMart 流式输出的核心是在兼容 OpenAI 的聊天请求体中加入 <code>"stream": true</code>,然后按 SSE 事件逐段读取增量内容。先确认当前文档给出的 Base URL、API Key 和模型 ID,再用最小请求测试;如果服务端返回完整 JSON、浏览器一直等待或连接中断,应依次检查请求参数、响应类型、代理缓冲和超时设置。

定义:流式输出是指模型生成内容后立即通过 Server-Sent Events(SSE)分段返回,而不是等待完整答案生成后一次性返回。

先试这一步:确认配置与最小请求

本文是第三方 AI API 接入指南,不代表 APIMart 官方。APIMart 的公开页面将其描述为提供 OpenAI 兼容接口的 AI API 聚合层;公开文章示例使用 https://api.apimart.ai/v1 作为 Base URL,但具体可用地址、模型 ID、权限和状态仍应以当前文档或实际响应为准。可先查看 APIMart 页面和当前接口文档,避免把旧地址直接用于生产环境。

  1. 准备一个 API Key,并只放在服务端环境变量中,不要写入浏览器代码或提交到 Git。
  2. 复制当前文档显示的 Base URL,确认不要重复拼接 /v1。
  3. 从模型页面复制精确的模型 ID,不要根据展示名称自行猜测。
  4. 在请求体加入 stream: true,并确认请求地址是聊天接口而不是图像、视频或异步任务接口。
  5. 成功判定不是“收到了 HTTP 200”这么简单,还要确认响应类型接近 text/event-stream,并能读取至少一段增量文本。
检查项正确方向常见错误
Base URL使用当前文档提供的地址把完整接口地址再次拼接
认证Authorization: Bearer YOUR_API_KEYKey 为空、过期或带多余引号
请求参数stream: true写成字符串或放在错误层级
模型使用目录中显示的精确 ID使用营销名称或已下架 ID
响应处理按 SSE 事件逐段读取直接调用一次性 JSON 解析

curl、Python 和 Node.js 配置示例

下面示例采用 OpenAI 兼容的 Chat Completions 结构。YOUR_BASE_URL、YOUR_API_KEY 和 YOUR_MODEL_ID 都是占位符,实际值必须从当前文档或模型页面核对。公开资料说明,兼容接口可以通过 stream: true 返回流式内容;OpenAI API 参考也将流式事件列为接口能力之一,具体字段仍应以实际网关响应为准。参考:APIMart 统一 LLM API 示例、Chat API 参考。

curl:先验证是否真的返回流

curl -N "YOUR_BASE_URL/chat/completions" -H "Authorization: Bearer YOUR_API_KEY" -H "Content-Type: application/json" -d '{"model":"YOUR_MODEL_ID","messages":[{"role":"user","content":"用一句话解释 SSE"}],"stream":true}'

-N用于减少 curl 对输出的缓冲。若终端仍然只在最后显示完整结果,先不要判断接口不支持流式,继续检查网关、反向代理或客户端缓冲。

Python:逐行读取 SSE 数据

import os
import json
import requests

url = os.environ["APIMART_BASE_URL"].rstrip("/") + "/chat/completions"
headers = {"Authorization": f"Bearer {os.environ['APIMART_API_KEY']}", "Content-Type": "application/json"}
body = {"model": os.environ["APIMART_MODEL"], "messages": [{"role": "user", "content": "用一句话解释 SSE"}], "stream": True}

with requests.post(url, headers=headers, json=body, stream=True, timeout=(10, 180)) as response:
response.raise_for_status()
for line in response.iter_lines(decode_unicode=True):
if not line or not line.startswith("data:"):
continue
data = line[5:].strip()
if data == "[DONE]":
break
try:
event = json.loads(data)
text = event.get("choices", [{}])[0].get("delta", {}).get("content") or ""
print(text, end="", flush=True)
except json.JSONDecodeError:
print("收到非 JSON SSE 数据,需记录原始行并核对网关格式", flush=True)

Node.js:使用 fetch 读取增量字节

const response = await fetch(`${process.env.APIMART_BASE_URL}/chat/completions`, {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.APIMART_API_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
model: process.env.APIMART_MODEL,
messages: [{ role: "user", content: "用一句话解释 SSE" }],
stream: true
})
});

if (!response.ok || !response.body) throw new Error(`HTTP ${response.status}`);
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = "";
while (true) {
const { value, done } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split("\n");
buffer = lines.pop() || "";
for (const line of lines) {
if (!line.startsWith("data:")) continue;
const data = line.slice(5).trim();
if (data === "[DONE]") continue;
try {
const chunk = JSON.parse(data);
process.stdout.write(chunk.choices?.[0]?.delta?.content || "");
} catch {
console.error("非 JSON SSE 数据:", data);
}
}
}

SSE 怎么解析:增量拼接、结束标记与前端转发

SSE 本质上是服务器持续发送的事件流,客户端不能把整个响应当作一个普通 JSON 一次性解析。浏览器端常见的 SSE 响应类型是 text/event-stream,事件通常按空行分隔,数据行以 data: 开头。可参考 MDN 的 Server-sent events 说明。

如果浏览器通过自己的后端代理接收流,后端应转发流式响应,而不是先等待上游完整结束。通常需要保持 Content-Type: text/event-stream,并根据部署环境设置 Cache-Control: no-cache;使用 Nginx 时可考虑关闭响应缓冲,例如 X-Accel-Buffering: no。这些设置解决的是代理层交付问题,不代表模型本身一定支持流式输出。

前端的“停止生成”按钮应取消浏览器到后端的请求;后端还要把取消信号继续传递给上游请求。否则页面虽然停止显示,服务端可能仍在继续生成并产生用量。取消后的计费和 usage 返回方式没有在本次公开资料中得到统一确认,应以当前接口响应和计费说明为准。

哪些接口适合流式输出?哪些不适合?

场景通常的处理方式核验重点
聊天文本使用聊天接口并设置 stream: true模型 ID、SSE 字段、结束标记
工具调用或 Agent流式传输文本和事件,工具参数先缓存事件顺序、JSON 是否完整、重复执行风险
图像生成通常先提交生成请求,再等待结果或任务状态是否返回任务 ID,是否另有轮询接口
视频生成通常采用异步任务流程任务状态、结果地址和有效期
需要完整 JSON 的后台任务优先使用同步响应或异步任务结构化输出和失败重试策略

不要因为平台提供统一 API,就默认所有模型和所有接口都支持相同的流式字段。APIMart 页面同时列出聊天、图像、视频和音频等不同能力,支持范围与返回格式应按具体模型文档确认。对模型支持、限速、区域可用性等问题,公开支持页面也建议按具体模型和请求情况核对,参考 APIMart Support。

流式输出失败时,按这个顺序排查

  1. 401 或 403:确认 Key 是否为空、是否包含多余空格、是否使用了正确的 Bearer 格式;再检查请求是否发到了对应 Base URL。
  2. 404:打印最终请求地址,检查是否重复拼接 /v1、是否误用了模型页面地址,或当前网关实际使用的是其他路径。
  3. 400:先删除可选参数,只保留 model、messages 和 stream,确认请求体是合法 JSON。
  4. 返回完整 JSON:检查 stream 是否为布尔值 true,并确认当前模型和接口真的支持流式;同时检查客户端是否自动聚合响应。
  5. 浏览器一直等待:检查后端是否设置流式响应头,Nginx、CDN 或框架是否启用了缓冲;用 curl 直接请求区分上游问题和前端代理问题。
  6. 429:降低并发,记录响应头和请求 ID,采用带上限的指数退避;不要瞬间重复发送大量相同请求。
  7. 5xx 或超时:区分首字节前超时与输出中途断开,设置合理的连接超时和读取超时,保留已收到的文本,并只对可重试错误重试。
  8. 流中断:保存部分内容和请求日志,避免把半截 JSON 当成完整结果;重新发起请求时应考虑续写提示,而不是盲目重复执行工具调用。

排查时建议记录 HTTP 状态码、最终 URL、模型 ID、响应头、首字节时间、已接收字符数和请求 ID,但必须脱敏 API Key、用户隐私和完整提示词。

常见问题

APIMart 流式输出只需要加 stream:true 吗?

对兼容 OpenAI 的聊天接口来说,stream:true 是核心开关,但还必须确认 Base URL、模型 ID、鉴权方式和客户端读取逻辑。若代理层缓冲响应,服务端可能已经在发送流,浏览器却仍然看不到增量内容。

为什么 curl 能看到流,网页却要等全部生成完?

通常是后端代理、Nginx、CDN 或框架默认缓冲导致。先确认后端返回 text/event-stream,再检查是否设置了 no-cache 和关闭代理缓冲,最后确认前端没有把响应整体读取后才渲染。

流式响应里的内容应该读取哪个字段?

兼容 Chat Completions 的响应通常会把增量文本放在 choices 中的 delta.content,但不同网关或模型可能返回不同事件结构。应先打印一条脱敏原始事件,再根据实际结构编写解析器,不要把单一字段泛化到所有接口。

图片和视频接口也能使用 stream:true 吗?

不能默认这样处理。聊天文本适合逐段输出,图像和视频通常采用异步任务或结果查询流程。是否支持流式、是否返回 task_id,需要查看具体模型接口说明和实际响应。

流式输出会不会改变计费或 usage 返回方式?

流式主要改变交付方式,不应直接推断为改变计费规则。但 usage 可能在最后一个事件、响应头或其他字段中返回,取消请求后的计费处理也可能取决于网关实现,应以当前计费说明和实际响应为准。

相关阅读

参考资料

  1. APIMart 中文页面:OpenAI 兼容 API 与模型能力介绍
  2. APIMart:一个 API 调用所有 LLM(apimart.ai)
  3. APIMart Support(apimart.ai)