Потоковые ответы
Получайте ответы в реальном времени по мере генерации токенов.
Включение потоковой передачи
Добавьте stream: true в запрос для включения потоковых ответов:
request.json
{
"model": "Qwen/Qwen3-235B-A22B-Instruct-2507-FP8",
"messages": [{ "role": "user", "content": "Hello!" }],
"stream": true
}Формат SSE-ответа
Потоковые ответы используют Server-Sent Events (SSE). Каждый чанк - JSON-объект с префиксом 'data: ':
sse-response.txt
data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}]}
data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":"Hello"},"finish_reason":null}]}
data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":"!"},"finish_reason":null}]}
data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","choices":[{"index":0,"delta":{},"finish_reason":"stop"}],"usage":{"prompt_tokens":10,"completion_tokens":5,"total_tokens":15,"base_cost_usd":0.000075,"platform_fee_usd":0.0000075,"total_cost_usd":0.0000825}}
data: [DONE]Использование в последнем чанке
Информация о стоимости включена в последний чанк перед [DONE].
Структура чанка
Каждый потоковый чанк имеет следующую структуру:
chunk-types.ts
interface ChatCompletionChunk {
id: string;
object: "chat.completion.chunk";
created: number;
model: string;
choices: [{
index: number;
delta: {
role?: "assistant";
content?: string;
};
finish_reason: "stop" | null;
}];
usage?: {
prompt_tokens: number;
completion_tokens: number;
total_tokens: number;
base_cost_usd: number;
platform_fee_usd: number;
total_cost_usd: number;
}; // Only in final chunk
}Примеры кода
Примеры потоковой передачи для разных окружений:
python
from openai import OpenAI
client = OpenAI(
base_url="https://api.gonkagate.com/v1",
api_key="gp-your-api-key"
)
stream = client.chat.completions.create(
model="Qwen/Qwen3-235B-A22B-Instruct-2507-FP8",
messages=[{"role": "user", "content": "Write a poem"}],
stream=True
)
for chunk in stream:
if chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)
# Final chunk contains usage info
if chunk.usage:
print(f"\n\nCost: ${chunk.usage.total_cost_usd:.6f}")Отслеживание стоимости в потоке
Последний чанк включает полную информацию об использовании и стоимости:
Проверяйте последний чанк — Использование с total_cost_usd доступно только в последнем чанке перед [DONE].
cost-tracking.ts
// Track costs from streaming response
let totalCost = 0;
for await (const chunk of stream) {
// ... handle content ...
if (chunk.usage) {
totalCost = chunk.usage.total_cost_usd;
console.log(`Request cost: $${totalCost.toFixed(6)}`);
console.log(`Breakdown: base $${chunk.usage.base_cost_usd.toFixed(6)} + fee $${chunk.usage.platform_fee_usd.toFixed(6)}`);
}
}Обработка ошибок в потоке
Корректно обрабатывайте проблемы соединения при потоковой передаче:
Разрыв соединения
Сетевые проблемы могут прервать поток. Реализуйте логику переподключения для продакшена.
error-handling.ts
async function streamWithErrorHandling(messages: Message[]) {
try {
const stream = await client.chat.completions.create({
model: "Qwen/Qwen3-235B-A22B-Instruct-2507-FP8",
messages,
stream: true,
});
for await (const chunk of stream) {
// Process chunk...
}
} catch (error) {
if (error.code === "ECONNRESET" || error.code === "ETIMEDOUT") {
// Connection was dropped
console.error("Connection lost. Consider retrying.");
} else if (error.status === 402) {
// Insufficient balance
showDepositModal();
} else {
throw error;
}
}
}