Как передавать ответы LLM потоком с SSE и чанками статистики использования

Автоматический перевод

Эта статья была автоматически переведена с оригинальной английской версии.

Чтобы передавать ответ LLM потоком, разбирайте протокол событий сервера, собирайте дельты содержимого и обновляйте экран по мере поступления текста, который можно показать. Многие API используют Server-Sent Events, или SSE. Одно чтение HTTP может содержать часть события или несколько событий. Одно событие может содержать несколько токенов модели.

Клиентским реализациям нужны буферизация и обработка завершения, а также быстрое первое обновление.

Разбирайте события до данных модели

Формат SSE использует строки вроде data: и завершает событие пустой строкой. Чтения из сети могут разделять эти строки или объединять несколько событий. Буферизуйте неполный текст, определяйте полные события и затем разбирайте данные в формате конкретного API. Несколько строк data: относятся к одному событию.

В OpenAI Chat Completions содержимое приходит в виде дельт, которые клиент собирает в сообщение. Обрабатывайте дельты tool calls или структурированные дельты по их полям, а не считайте каждое событие обычным текстом. Маркер [DONE] — соглашение API, а не общее требование SSE.

Практичный порядок обработки на клиенте:

  1. Декодируйте входящие байты, не теряя символ UTF-8, разделённый между чтениями.
  2. Буферизуйте данные, пока не получите полное событие SSE.
  3. Интерпретируйте событие по схеме выбранного API.
  4. Добавляйте содержимое или структурированные поля в собираемый ответ.
  5. Обновляйте экран на подходящей границе буферизации.

Разделяйте отображение, завершение и статистику использования

По возможности сразу отображайте обычный текст. Буферизуйте незавершённые конструкции Markdown или строки кода, если немедленное форматирование вызывает повторные изменения расположения элементов. Отдельно фиксируйте начало запроса и первое сгенерированное содержимое, не смешивая их со временем открытия соединения или событием, которое содержит только метаданные.

В Chat API OpenAI параметр stream_options: {"include_usage": true} запрашивает финальный чанк статистики использования перед [DONE]. Этот чанк содержит пустой массив вариантов ответа. Прерванные или отменённые потоки могут вообще не передать его, поэтому отсутствие статистики нельзя интерпретировать как ноль токенов.

Совместимые с OpenAI серверы могут использовать другие форматы данных или иначе обрабатывать завершение. Проверяйте разделённые события, несколько событий за одно чтение, пустые дельты, отмену, ошибки сервера и отсутствие финальной статистики на реализации с зафиксированной версией. Сохраняйте уже полученный текст и отличайте неполный ответ от успешного завершения.

Инженерное руководство: стриминг на практике связывает поведение клиента с TTFT, TPOT и планированием префилла.