# Chat Completions 流式输出

为 Chat Completions 请求设置 `stream: true` 后，服务通过 Server-Sent Events（SSE）逐段返回模型生成内容。完成本页操作后，客户端可以合并文本增量、识别结束事件，并在连接中断时避免重复输出。

## 前提条件

- 已从[获取可用模型](../../getting-started/available-models.md)取得模型 ID。纯文本消息使用支持文本对话的模型；消息中包含图像时，使用支持多模态输入的模型。
- 已准备访问令牌，并在 Chat Completions 请求 Header 中设置 `Authorization: Bearer <ACCESS_TOKEN>`。`<ACCESS_TOKEN>` 可以是个人访问令牌，也可以是已授予 Genesis 权限的服务账号 API Key；创建和管理凭据请参阅[身份认证](../../getting-started/authentication.md)。
- 客户端具备读取 HTTP 响应流的能力。

## 发送流式请求

流式响应不使用新的接口。向 Chat Completions 请求中加入 `"stream": true`：

```text
POST <GENESIS_BASE_URL>/chat/completions
```

```bash
curl -X POST "$GENESIS_BASE_URL/chat/completions" \
  -H "Authorization: Bearer $GENESIS_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "<MODEL_ID>",
    "messages": [
      {
        "role": "user",
        "content": "用一句话解释数据血缘。"
      }
    ],
    "stream": true
  }'
```

成功后，响应使用 `text/event-stream` 返回多条 SSE 事件，而不是一个完整的 JSON 对象。纯文本请求的消息结构和通用参数见[文本对话](text-chat.md)；图文消息是否可用取决于所选模型的多模态输入能力。

## 读取 SSE 事件

Chat Completions 流中的每条事件以 `data:` 开头。下面的内容仅说明事件形态，`id`、时间和 Token 数会随请求变化：

```text
data: {"id":"<request-id>","object":"chat.completion.chunk","created":0,"model":"<MODEL_ID>","choices":[{"index":0,"delta":{"content":"数据"},"finish_reason":null}]}

data: {"id":"<request-id>","object":"chat.completion.chunk","created":0,"model":"<MODEL_ID>","choices":[{"index":0,"delta":{"content":"血缘描述数据之间的关系。"},"finish_reason":null}]}

data: {"id":"<request-id>","object":"chat.completion.chunk","created":0,"model":"<MODEL_ID>","choices":[{"index":0,"delta":{},"finish_reason":"stop"}],"usage":{"prompt_tokens":0,"completion_tokens":0,"total_tokens":0}}

data: [DONE]
```

按以下顺序处理事件：

1. 使用空行划分完整 SSE 事件；网络分片不足以组成完整事件时，保留未完成内容并与下一段数据拼接。
2. 对每个 JSON 事件读取 `choices[].delta.content`。字段有文本时追加到当前回复；字段缺失或为空时不追加文本。
3. `finish_reason` 出现非空值时，记录生成结束原因。`length` 表示输出达到当前长度限制，不能视为完整回答。
4. 收到 `data: [DONE]` 后停止读取并关闭流。`usage` 只在实际事件包含时读取。

不要把每个网络读取块直接当作一个 JSON 对象解析，也不要使用非流式响应中的 `choices[].message.content` 读取增量文本。

## 处理连接中断

在收到结束事件前连接关闭时，当前回复可能不完整。应用应保留已经展示的文本，并向调用方明确显示本次输出未完成。

请求开始返回文本后直接重试，可能得到重复内容并产生新的用量。只有业务能够识别重复请求或对输出去重时，才自动重试；否则应由调用方确认后重新发起请求。排查时保留已收到事件中的请求 ID、模型 ID 和 HTTP 状态信息。

## 区分不同接口的流式格式

本页的 `choices[].delta.content` 和 `data: [DONE]` 只适用于 Chat Completions。Responses 和 Messages 使用各自的响应对象与事件格式；调用这些接口时，请按对应接口页面的事件定义解析，不要复用本页的字段路径。

## 常见问题

| 现象 | 先检查 | 下一步 |
| --- | --- | --- |
| 一直等到结束才显示文本 | 请求体中的 `stream` 是否为 `true`，以及客户端是否逐段读取响应体 | 按本页的 SSE 事件顺序读取和追加 `delta.content`。 |
| JSON 解析失败 | 是否在收到完整 SSE 事件前就解析数据 | 保留跨网络分片的未完成内容，收到事件分隔后再解析。 |
| 输出在中途停止 | 是否收到 `data: [DONE]`、`finish_reason` 或连接错误 | 将回复标记为未完成；确认业务可以去重后再决定是否重试。 |
| 认证或模型错误 | `Authorization: Bearer <ACCESS_TOKEN>`、令牌状态、`model` 和当前可用模型列表 | 按[身份认证](../../getting-started/authentication.md)检查凭据，并从[获取可用模型](../../getting-started/available-models.md)重新选择模型。 |

## 下一步

- [发送非流式文本对话](text-chat.md)
- [选择支持多模态输入的模型](../../getting-started/choose-model-capabilities.md)
- [查看当前凭证可用的模型](../../getting-started/available-models.md)
