# 流式输出

https://modelportal.ai/docs/streaming?lang=zh

流式输出让模型边生成边返回，适合长回答和需要尽快显示首字的界面。

| 协议 | 怎么开启 | 结束标志 |
| --- | --- | --- |
| OpenAI 兼容 | 请求体加 `"stream": true` | `data: [DONE]` |
| Anthropic 兼容 | 请求体加 `"stream": true` | `message_stop` 事件 |
| Gemini 兼容 | 调用 `:streamGenerateContent?alt=sse` | 流结束；不带 `alt=sse` 时返回 JSON 数组 |

```bash
curl -N https://modelportal.ai/v1/chat/completions \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "MODEL_ID", "stream": true, "stream_options": {"include_usage": true}, "messages": [{"role": "user", "content": "写一首短诗"}]}'
```

```python
from openai import OpenAI

client = OpenAI(base_url="https://modelportal.ai/v1", api_key="YOUR_API_KEY")
stream = client.chat.completions.create(
    model="MODEL_ID",
    messages=[{"role": "user", "content": "写一首短诗"}],
    stream=True,
)
for chunk in stream:
    if chunk.choices and chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="")
```

## 用量

- OpenAI 格式要在请求里加 `"stream_options": {"include_usage": true}`，最后一个分块才会带 `usage`；平台不会替没要用量的请求补上。
- 流里的用量就是计费用量，与账单一致。带用量的最后一个事件里还有 `provider`、`attempts` 和用量对象里的 `cost`（扣费金额，USD）；OpenAI Chat 的每个分块都带 `provider`。见[接口概览](/docs/api-overview)。

## 超时与中断

- 等待第一个内容事件最长 600 秒（所有尝试共用）；开始输出后，两个事件之间超过 120 秒没有数据会断开；一次输出最长 60 分钟。
- 等待第一个内容事件期间，平台每 15 秒发一条 SSE 注释 `: keepalive`，免得客户端或中间代理因为空闲断开。SSE 客户端会自动忽略注释；Gemini 不带 `alt=sse` 的 JSON 数组里，保活是一个换行。
- 响应头在第一个内容事件到达或开始发保活时发出，`X-ModelPortal-Request-Id` 一定在里面。
- 响应头发出之前失败，返回普通的 HTTP 错误；发出之后失败（包括只发过保活就全部失败），以 SSE 错误事件结束。开始输出之后中断，按已经产生的用量计费，拿不到准确用量时按估算计费，账单里标记「预估」。
