Когда потоковый вызов ведёт себя странно, у вас на руках стена из строк event и data, а три вещи, которые вы хотите знать, разбросаны по ней: что модель на самом деле сказала, почему остановилась и сколько израсходовала. Текст приходит фрагментами, аргументы инструментов — частичным JSON, который разбирается только с последним куском, а расход поделён между первым событием и последним. Здесь всё это собирается обратно. Обе распространённые формы потока обрабатываются, потому что на практике вставляют обе, а события, которые не разобрались, сообщаются, а не пропускаются молча.
Возможности
Текст собран из дельт по порядку
Аргументы инструментов восстановлены из частичного JSON и отформатированы
Извлекаются причина остановки, модель и расход
Обрабатывается и блочная форма, и форма choices/delta
Повторяющиеся строки data соединяются по спецификации
Комментарии поддержания соединения игнорируются, а не считаются событиями
События ошибок показываются, а не пропускаются
Каждое событие разворачивается, есть подсчёт по именам
Как использовать Просмотр SSE-потока
Вставьте сырой поток
Прочтите собранный текст
Проверьте причину остановки и расход
Разверните отдельные события, если что-то осталось непонятным
Пример
Ввод
delta: {"type":"text_delta","text":"Order 4471 "}
Результат
Order 4471 shipped on 30 August.
Фрагменты по шести событиям, собранные по порядку.
Частые ошибки и устранение неполадок
Текста нет вовсе. — Возможно, поток закончился до появления содержимого — посмотрите список событий и причину остановки. Отказ или событие ошибки дают корректный и пустой поток.
Аргументы инструментов обрезаны. — Они приходят частичным JSON в нескольких событиях. Если поток оборвался, JSON так и не закроется, и показывается сырой фрагмент.
Некоторые события не разбираются. — Обычно это поток, обрезанный посреди события при копировании. Такие сообщаются с их номером, а не отбрасываются.
Числа расхода выглядят неполными. — Они разнесены по потоку: входные токены в начале, выходные в конце. У потока без последних событий не хватает половины.
Часто задаваемые вопросы
Что такое server-sent events?
Простой потоковый формат: строки «поле — значение», события разделены пустыми строками. Именно его используют потоковые ответы API, поэтому сорвавшийся вызов оставляет вас с этой стеной.
Какие формы потока поддерживаются?
Блочная, где текст приходит типизированными дельтами внутри блоков содержимого, и форма choices/delta. Обе распознаются автоматически, поскольку вставляют ту, что записал их клиент.
Почему аргументы приходят кусками?
Они передаются частичным JSON, чтобы клиент мог начать отрисовку до завершения вызова. Значит, фрагменты разбираются только с приходом последнего, и оборванный поток оставляет некорректный JSON.
Можно ли увидеть, во что это обошлось?
Блок расхода извлекается, когда он есть, включая чтения из кэша. Он говорит, что израсходовал вызов; дальше в дело вступают инструменты стоимости.
Отправляется ли поток куда-нибудь?
Нет. В потоке лежит весь ответ и часто породивший его промпт, и весь разбор происходит в браузере.