Skip to main content

Краткий ответ

В трех предложениях:
  1. Выбор между потоковой передачей и обычным режимом полностью определяется вашим кодом — полем stream в теле запроса. Тот же ключ, та же модель, тот же эндпоинт: если режим меняется, значит, переключение происходит в вашем клиентском коде (или в используемом SDK / фреймворке). Шлюз никогда не переключает его произвольно.
  2. Оба режима возвращают одинаковый итоговый контент и тарифицируются одинаково. Единственные различия — когда вы получаете текст и как вы его разбираете. Исключением является фильтрация безопасности контента: запросы без потоковой передачи автоматически переключаются на другой маршрут, в то время как потоковые запросы обрываются; см. Чем отличаются потоковые запросы и запросы без потоковой передачи при фильтрации контента?.
  3. Как выбрать: за экраном наблюдает человек → потоковая передача; результат обрабатывается программой (парсинг JSON, пакетные задачи, вызовы инструментов) → без потоковой передачи.

Различия в сравнении

Почему мои запросы переключаются между потоковой передачей и непотоковым режимом?

Это самый частый вопрос, и ответ такой: что-то на вашей стороне это меняет. Пройдитесь по этому списку — почти всегда совпадает один из пунктов:
Классический случай: stream=config.get("stream", False) или stream=is_web_request. Разные точки входа вызывают одну и ту же функцию с разными значениями, и по логам кажется, будто режим переключается случайно.Как проверить: выведите фактическое тело запроса, которое вы отправляете, и посмотрите на поле stream.
Одна и та же бизнес-логика ведёт себя по-разному в зависимости от клиента:
  • OpenAI SDK chat.completions.create(): без потоковой передачи по умолчанию
  • client.chat.completions.stream() или with_streaming_response: потоковая передача
  • Обёртки вроде LangChain / LlamaIndex: зависит от того, вызываете ли вы invoke или stream, и передавали ли вы streaming=True при создании объекта модели
  • Настольные клиенты, инструменты агентов, платформы рабочих процессов: обычно в настройках есть переключатель «потоковый вывод», а значения по умолчанию отличаются
Как проверить: убедитесь, какая точка входа фактически выполнила вызов.
Один ключ, используемый и в веб-интерфейсе чата (потоковая передача), и в ночной пакетной задаче (без потоковой передачи), создаёт логи, которые при совместном просмотре выглядят случайными.Как проверить: создайте отдельные tokens для каждого сценария использования — тогда логи сами разделятся. См. Управление token.
Вы действительно отправили stream: true, но Nginx, корпоративный gateway или какой-то proxy буферизовал ответ — сервер отправлял его порциями, proxy удержал его и выпустил весь сразу, и это ощущается как отсутствие потоковой передачи.Как проверить: один раз протестируйте, обойдя proxy; отключите буферизацию в Nginx (proxy_buffering off;). Обратите внимание, что в этом случае лог консоли по-прежнему показывает is_stream = true, потому что gateway действительно выполнил потоковую передачу.
Чтобы подтвердить, что именно сделало конкретное обращение: проверьте поле is_stream в логе консоли или получите его массово через Log Query API. Это источник истины — куда надёжнее, чем субъективное впечатление.

Выбор по сценарию

Используйте потоковую передачу

  • Чат-интерфейсы и боты поддержки — пользователям нужна немедленная обратная связь
  • Плагины для IDE и ассистенты программирования (Claude Code, Cursor и т. д.)
  • Генерация длинных материалов (длинные статьи, длинные переводы, большие блоки кода)
  • Длительные задачи моделей рассуждения — по крайней мере, вы можете видеть прогресс
  • Везде, где пользователь может нажать «остановить» во время генерации

Используйте потоковую передачу

  • Структурированный вывод: вам нужен весь JSON для json.loads()
  • Разбор аргументов вызова функций и инструментов
  • Пакетная обработка, автономные задания, запланированные задачи
  • Серверные процессы, где важен только итоговый результат и никто не ждёт
  • Быстрая проверка, отладка, написание тестовых случаев
Несколько особых случаев:

Затраты на интеграцию: одна и та же задача в обе стороны

Собственный формат Claude (/v1/messages) использует другой протокол потоковой передачи: SSE с именованными событиями Anthropic (message_start / content_block_delta / message_delta и т. д.), а не единообразные чанки OpenAI data:, и usage разбивается между событиями message_start и message_delta. Полное руководство по парсингу: Нативный формат Claude: ответы с потоковой передачей и без нее.

Тарификация и использование: одинаково в любом случае

streaming не дешевле и не дороже. Тарификация идет по token и не зависит от того, как передаются байты.Отключение посередине все равно тарифицируется — после того как вы достигнете Ctrl+C или у вашего клиента истечет таймаут, генерация на upstream все равно будет завершена, и запрос будет оплачен обычным образом. Поэтому «обрубить stream раньше, чтобы сэкономить» не работает.
Два подводных камня, связанных с usage:
  1. streaming по умолчанию не возвращает usage. На endpoint, совместимых с OpenAI, вы должны передать stream_options: {"include_usage": true}; после этого usage приходит в финальном чанке (чей массив choices пуст — проверьте перед индексированием). На APIYI это подтверждено на нескольких моделях.
  2. Не сверяйте ваш счет с usage, которые возвращает API, особенно с полями, связанными с кэшем. Возвращаемые значения не всегда совпадают с тем, что было фактически тарифицировано; факт попадания в кэш определяется по «деталям тарификации кэша» в логах консоли. См. Как объясняется тарификация кэша.
В любом случае лог консоли записывает количество token, задержку и тарификацию для каждого вызова — режим передачи не имеет значения. Значения полей: Понимание деталей тарификации в логах.

Шесть распространенных заблуждений

Разделим эти две вещи. Потоковая передача не сокращает общее время генерации — общее время от первого до последнего token остается тем же; эта часть неизменна.Однако потоковая передача действительно решает проблему «возврата пустого ответа»: пока клиентский таймаут чтения настроен так, чтобы покрывать интервал между событиями (измеренная максимальная пауза без данных на этапе размышлений модели рассуждения составляет ~42 с с keepalive-пингами между ними, поэтому подходит 90–120 с), он не сработает ошибочно. Именно режим без потоковой передачи в чистом виде — попытка одним значением таймаута покрыть генерацию более чем на десять минут от начала до конца — гарантированно приведет к сбою.Поэтому правильный подход заключается в следующем: передавайте длинный вывод в потоковом режиме с таймаутом чтения, рассчитанным на интервал между событиями. Значения для конкретных сценариев приведены в руководстве Как избежать таймаутов API; полное руководство содержится в разделе Практические рекомендации по работе с длинным выводом.
Первый байт приходит быстрее, общее время — нет. Для одной и той же модели и prompt потоковая передача и обычный запрос завершаются примерно за одно и то же время.Потоковая передача дает вам воспринимаемую скорость: пользователь видит отклик уже через секунду, а не смотрит на индикатор загрузки в течение 30 секунд. Если за экраном никто не наблюдает, эта польза равна нулю.
Нет. См. раздел «Тарификация и использование» выше: тарификация идентична, а отключение на полпути всё равно оплачивается.
Нет. Модели текстового чата в основном поддерживают её; эндпоинты генерации изображений, embedding и rerank не имеют концепции потоковой передачи и либо проигнорируют stream, либо отклонят запрос.Некоторые модели имеют дополнительные ограничения на определенные комбинации параметров при потоковой передаче. Если вы не уверены, сначала добейтесь корректной работы вызова без потоковой передачи, а затем добавьте stream: true.
У каждого режима есть свои сценарии сбоев.
  • Риски без потоковой передачи: соединение простаивает без передачи данных на протяжении всей генерации, поэтому прокси, CDN и корпоративные шлюзы могут разорвать его по таймауту неактивности. При очень больших телах ответов (вывод изображений в base64 легко достигает десятков МБ) вы также можете столкнуться с зависанием завершающего символа — см. Запросы, завершившие передачу данных, но так и не вернувшие ответ и В логах отображается успешное завершение, но клиент ничего не получает.
  • Риски потоковой передачи: не подходит для промежуточных сетевых узлов (middlebox), которые не поддерживают SSE или принудительно включают буферизацию; парсинг на стороне клиента сложнее, и в нем легко допустить незаметные ошибки.
Также обратите внимание: api-cf.apiyi.com (эндпоинт CDN) имеет ограничение длительности запроса около 100 секунд, которое влияет на оба режима. Для длительных запросов используйте api.apiyi.com или b.apiyi.com — см. Руководство по настройке базового URL.
Можно — нужно лишь собрать его самостоятельно. Последовательное объединение delta.content каждого чанка дает в точности message.content из режима без потоковой передачи.Если собранный текст выглядит неполным, проверьте три вещи: не проигнорировали ли вы finish_reason, не вышли ли из цикла до получения data: [DONE], и не урезал ли ответ промежуточный сетевой узел (middlebox).

Потоковая передача не работает? Четыре шага

1

Убедитесь, что тело запроса действительно содержит stream: true

Выведите JSON, который вы реально отправляете. При использовании библиотек-обёрток «Я думал, что передал это» и «это было передано» часто оказываются разными вещами.
2

Проверьте напрямую с помощью curl -N

Обойдите свой код и любой прокси, используя команду на вкладке «cURL бок о бок» выше. Если curl показывает, что фрагменты приходят постепенно, на стороне сервера всё в порядке, а проблема в вашем клиенте или промежуточном устройстве.
3

Проверьте буферизацию промежуточного устройства

Добавьте proxy_buffering off; в Nginx. Корпоративные шлюзы и средства безопасности могут сканировать text/event-stream как единый полезный груз — попросите сетевого администратора разрешить его прохождение.
4

Проверьте логику разбора

Читайте SSE построчно, пропускайте пустые строки и строки комментариев, начинающиеся с :, и останавливайтесь на data: [DONE]. Последний фрагмент, содержащий usage, имеет пустой массив choices — не обращайтесь к нему по индексу.
Если вы дошли до этого места без ответа, свяжитесь со службой поддержки с request_id — журнал консоли прямо показывает, был ли этот вызов обработан как потоковая передача, а также его общую задержку и время до первого байта.

Связанная документация

Как избежать тайм-аутов API

Значения тайм-аутов для разных сценариев и причины использовать потоковую передачу для длинного вывода

Руководство по настройке базового URL

Различия между эндпоинтами и ограничение CDN-узла в 100 секунд

В журнале отображается завершение, но ответ отсутствует

Классическая проблема большого ответа без потоковой передачи с указанием времени для каждого сегмента

Потоковая передача и передача без потоковой передачи в Claude

Разбор нативного протокола SSE с именованными событиями Anthropic

API генерации текста

Полный список параметров и примеры вызовов

Понимание сведений о тарификации в журнале

Значение каждого поля журнала в консоли, включая is_stream