Streaming
Server-Sent Events формат для chat completions stream.
Streaming
При stream: true ответ от /v1/chat/completions приходит как Server-Sent Events: каждый chunk — отдельная строка data: <json> с разделителем \n\n. Поток завершается строкой data: [DONE].
Заголовки ответа
HTTP/1.1 200 OK
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
X-Accel-Buffering: no
Формат chunk-а
Каждый chunk — JSON-объект chat.completion.chunk:
{
"id": "chatcmpl-abc123",
"object": "chat.completion.chunk",
"created": 1714000000,
"model": "anthropic/claude-haiku-4.5",
"choices": [
{
"index": 0,
"delta": { "role": "assistant", "content": "О" },
"finish_reason": null
}
]
}
В первом chunk-е delta обычно содержит role: "assistant". Следующие — только инкремент content. Последний chunk перед [DONE] имеет finish_reason: "stop" (или length, tool_calls, и т.д.) и поле usage с итоговыми токенами:
{
"id": "chatcmpl-abc123",
"object": "chat.completion.chunk",
"created": 1714000000,
"model": "anthropic/claude-haiku-4.5",
"choices": [
{
"index": 0,
"delta": {},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 12,
"completion_tokens": 1,
"total_tokens": 13
}
}
После usage-chunk-а поток завершается:
data: [DONE]
Hubris автоматически добавляет stream_options: { include_usage: true } ко всем stream-запросам, поэтому usage приходит всегда.
Парсинг
Парсите построчно с буфером: один chunk может прийти разорванным на несколько TCP-сегментов. Псевдокод:
buffer = ""
for raw_bytes in response.iter_content():
buffer += raw_bytes.decode("utf-8")
while "\n\n" in buffer:
line, buffer = buffer.split("\n\n", 1)
if not line.startswith("data: "):
continue
payload = line[len("data: "):]
if payload == "[DONE]":
return
chunk = json.loads(payload)
# обработка delta
Не парсьте [DONE] как JSON — это литерал-маркер, не JSON.
Дисконнект
Если клиент закрыл соединение до окончания стрима, Hubris всё равно дочитывает ответ от провайдера и списывает деньги — это защищает от «бесплатных токенов» через abort. Если вы намеренно прерываете запрос (например, по timeout-у), ожидайте полное списание стоимости.
Что дальше
- POST /v1/chat/completions — параметры запроса.
- Ошибки — что бывает при сбое стрима.