Как передавать ответы LLM потоком с SSE и чанками статистики использования
Автоматический перевод
Эта статья была автоматически переведена с оригинальной английской версии.
Чтобы передавать ответ LLM потоком, разбирайте протокол событий сервера, собирайте дельты содержимого и обновляйте экран по мере поступления текста, который можно показать. Многие API используют Server-Sent Events, или SSE. Одно чтение HTTP может содержать часть события или несколько событий. Одно событие может содержать несколько токенов модели.
Клиентским реализациям нужны буферизация и обработка завершения, а также быстрое первое обновление.
Разбирайте события до данных модели
Формат SSE использует строки вроде data: и завершает событие пустой строкой. Чтения из сети могут разделять эти строки или объединять несколько событий. Буферизуйте неполный текст, определяйте полные события и затем разбирайте данные в формате конкретного API. Несколько строк data: относятся к одному событию.
В OpenAI Chat Completions содержимое приходит в виде дельт, которые клиент собирает в сообщение. Обрабатывайте дельты tool calls или структурированные дельты по их полям, а не считайте каждое событие обычным текстом. Маркер [DONE] — соглашение API, а не общее требование SSE.
Практичный порядок обработки на клиенте:
- Декодируйте входящие байты, не теряя символ UTF-8, разделённый между чтениями.
- Буферизуйте данные, пока не получите полное событие SSE.
- Интерпретируйте событие по схеме выбранного API.
- Добавляйте содержимое или структурированные поля в собираемый ответ.
- Обновляйте экран на подходящей границе буферизации.
Разделяйте отображение, завершение и статистику использования
По возможности сразу отображайте обычный текст. Буферизуйте незавершённые конструкции Markdown или строки кода, если немедленное форматирование вызывает повторные изменения расположения элементов. Отдельно фиксируйте начало запроса и первое сгенерированное содержимое, не смешивая их со временем открытия соединения или событием, которое содержит только метаданные.
В Chat API OpenAI параметр stream_options: {"include_usage": true} запрашивает финальный чанк статистики использования перед [DONE]. Этот чанк содержит пустой массив вариантов ответа. Прерванные или отменённые потоки могут вообще не передать его, поэтому отсутствие статистики нельзя интерпретировать как ноль токенов.
Совместимые с OpenAI серверы могут использовать другие форматы данных или иначе обрабатывать завершение. Проверяйте разделённые события, несколько событий за одно чтение, пустые дельты, отмену, ошибки сервера и отсутствие финальной статистики на реализации с зафиксированной версией. Сохраняйте уже полученный текст и отличайте неполный ответ от успешного завершения.
Инженерное руководство: стриминг на практике связывает поведение клиента с TTFT, TPOT и планированием префилла.