Skip to main content

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

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

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

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

Это самый частый вопрос, и ответ такой: что-то на вашей стороне это меняет. Пройдитесь по этому списку — почти всегда совпадает один из пунктов:
Классический случай: 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()
  • Разбор аргументов function-calling / tool-call
  • Пакетная обработка, автономные задачи, запланированные задачи
  • Серверные сценарии, где важен только итоговый результат и никто не ждет
  • Быстрая проверка, отладка, написание тест-кейсов
Несколько особых случаев:

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

Собственный формат 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 прийти раньше. Она не сокращает общее время генерации и не гарантирует непрерывный поток данных.Модели с рассуждением (gemini-3.1-pro-preview, gpt-5.6-sol, gpt-5.5-pro и т. д.) могут вообще не выдавать ничего на этапе размышления, что точно так же приводит к срабатыванию тайм-аута чтения у клиента.Правильное решение — задавать значения timeout для каждого сценария — см. Как избежать тайм-аутов API.
Первый байт приходит быстрее; в целом — нет. Для одной и той же модели и одного и того же prompt потоковая передача и без потоковой передачи завершаются примерно за одно и то же время.Потоковая передача даёт вам ощущение скорости: пользователь видит движение уже через секунду, а не смотрит на индикатор загрузки 30 секунд. Если никто не смотрит на экран, это значение равно нулю.
Нет. См. «Тарификация и использование» выше: тарификация идентична, и при отключении на середине запрос всё равно тарифицируется.
Нет. Модели текстового чата обычно поддерживают; endpoints для генерации изображений, embedding и rerank не имеют понятия потоковой передачи и либо проигнорируют stream, либо отклонят его.У некоторых моделей есть дополнительные ограничения для определённых сочетаний параметров в режиме потоковой передачи. Если не уверены, сначала добейтесь, чтобы вызов работал без потоковой передачи, а затем добавьте stream: true.
У обоих есть свои режимы отказа.
  • Риски без потоковой передачи: соединение молчит на протяжении всей генерации, поэтому прокси, CDN и корпоративные шлюзы могут разорвать его по тайм-ауту простоя. При очень больших телах ответа (base64-вывод изображений легко достигает десятков МБ) вы также можете столкнуться с зависшим завершающим обработчиком — см. Запросы, которые полностью передали данные, но так и не вернулись и В журнале указано завершение, но клиент ничего не получает.
  • Риски потоковой передачи: она плохо совместима с промежуточными устройствами, которые не поддерживают SSE или принудительно буферизуют данные; разбор на стороне клиента сложнее, и в нём легко допустить малозаметную ошибку.
Также учтите: api-cf.apiyi.com (эндпоинт CDN) имеет примерно 100-секундный предел для запроса, который затрагивает оба режима. Для длительных запросов используйте api.apiyi.com или vip.apiyi.com — см. Руководство по настройке Base URL.
Можно — вы просто собираете его сами. Если последовательно объединить delta.content каждого chunk, вы получите в точности тот же message.content, что и без потоковой передачи.Если собранный текст выглядит неполным, проверьте три вещи: не проигнорировали ли вы finish_reason, не вышли ли вы из цикла до получения data: [DONE] и не обрезал ли ответ промежуточный узел.

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

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

Значения таймаута по сценариям и почему потоковая передача не спасает вас

Руководство по настройке Base URL

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

Лог показывает завершение, но ответа нет

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

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

Разбор собственного SSE-протокола named-event от Anthropic

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

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

Понимание деталей тарификации в логах

Что означает каждое поле лога в консоли, включая is_stream