AGTCloud API Docs
文档指南API Reference集成与资源更新与帮助

Streaming

逐步接收模型输出,并正确处理事件、增量、完成与断流。

Streaming 让客户端在模型生成完整回答之前持续接收增量内容。它适合聊天界面、长文本生成和需要尽快展示首段结果的场景,但客户端必须正确处理事件边界、内容拼接、完成状态和连接中断。

Streaming 改变返回方式,不改变任务本身

同一个任务通常可以选择非流式或流式返回。先完成非流式请求,再开启 Streaming,更容易区分请求参数问题和流式解析问题。

使用前确认

  1. 在模型广场确认目标模型支持所选协议和 Streaming。
  2. 根据协议使用对应端点和事件结构,不要让同一个解析器猜测所有协议。
  3. 确认客户端、反向代理和网关不会缓冲整个响应后再一次性返回。

完整字段分别由 Chat Completions、Responses、Anthropic Messages 和 Gemini Stream Generate Content Reference 维护。

发起最小流式请求

下面通过 Chat Completions 开启流式输出:

curl --no-buffer 'https://api.agtcloud.cn/v1/chat/completions' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer your-api-key' \
  --data '{
    "model": "MODEL_ID",
    "messages": [
      {"role": "user", "content": "分三点解释指数退避。"}
    ],
    "stream": true
  }'

--no-buffer 让 cURL 及时显示已经收到的数据,不会改变服务端事件结构。

按事件读取,而不是按网络数据包读取

HTTP 连接每次交给客户端的字节数量并不等于一个完整事件。一个 JSON 对象可能被拆成多个数据块,多个事件也可能在同一个数据块中到达。

对于 SSE,客户端应先按空行识别完整事件,再读取其中的 data: 内容:

const response = await fetch('https://api.agtcloud.cn/v1/chat/completions', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer your-api-key',
  },
  body: JSON.stringify({
    model: 'MODEL_ID',
    messages: [{ role: 'user', content: '解释什么是指数退避。' }],
    stream: true,
  }),
});

if (!response.ok || !response.body) {
  throw new Error(`请求失败:${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 events = buffer.split('\n\n');
  buffer = events.pop() ?? '';

  for (const event of events) {
    const data = event
      .split('\n')
      .filter((line) => line.startsWith('data:'))
      .map((line) => line.slice(5).trimStart())
      .join('\n');

    if (!data || data === '[DONE]') continue;
    const chunk = JSON.parse(data);
    const delta = chunk.choices?.[0]?.delta?.content;
    if (delta) process.stdout.write(delta);
  }
}

生产代码还应处理取消请求、读取超时、心跳、非 JSON 事件以及流结束时尚未消费的缓冲区。

四种协议的流式结构

Chat 通常返回 Chat Completion Chunk。文本位于 choices[].delta.content,工具参数可能出现在 choices[].delta.tool_calls,结束原因位于 finish_reason;事件流可能以 [DONE] 结束。

协议入口存在不代表所有模型都会返回上述所有内容类型。只实现应用实际使用、并已由目标模型返回的分支。

拼接文本和工具参数

  • 文本增量按候选、输出项或 Content Block 的索引分别拼接。
  • 工具名称、调用 ID 和参数可能分多次到达,应为每个调用维护独立缓冲区。
  • 工具参数只有在完整结束后才能解析为 JSON,不能逐块执行。
  • 推理摘要、Thinking Block 和最终回答使用不同缓冲区,不能混成一段文本。
  • 如果协议在最后返回 Usage,应在收到完成事件前继续读取连接。

判断成功、失败和中断

现象客户端处理
收到协议规定的完成事件保存完整结果和 Usage,标记请求成功
收到错误或失败事件保存已展示内容,同时将本次请求标记为失败
连接提前关闭标记为不完整,不把已有文本冒充完整回答
用户主动停止取消读取并在界面标记“已停止生成”
长时间没有新事件按应用超时策略取消,保留必要的排障信息

流式请求已经向用户展示部分内容后,不应自动无限重放。重试可能产生另一份不同回答,也可能重复触发工具或其他有副作用的行为。

上线前检查

  • 页面能够逐步显示文本,而不是等到连接关闭才显示。
  • 中文和多字节字符不会因数据块切分而乱码。
  • 工具参数按调用 ID 正确拼接,并在执行前完成校验。
  • 用户取消、网络断开、超时和服务端错误都有明确状态。
  • 日志不会记录 API Key、完整敏感 Prompt 或未经脱敏的工具参数。

下一步可阅读 Tool Calling 和错误与排障。

本页目录