Ответ модели можно получить целиком одним запросом, а можно кусками по мере генерации. Второй вариант это стриминг через server-sent events. Разберём, когда он окупается, а когда только добавляет код без пользы.
Что происходит под капотом
При обычном запросе сервер держит соединение открытым, пока не сгенерирует весь ответ, и только потом присылает его целиком. При стриминге тот же сервер шлёт события по мере готовности токенов: клиент открывает HTTP-соединение с заголовком Accept: text/event-stream и читает поток строк вида data: {...}, разделённых пустой строкой.
Формат в API Anthropic отличается от формата OpenAI. У Anthropic события именованные: message_start, content_block_delta, message_stop и так далее, каждое со своим полем type. У OpenAI поток проще: те же data: строки с дельтой текста и завершающий data: [DONE]. Через Claudexia работают оба формата, стриминг переключается тем же параметром stream: true, что и в оригинальных SDK.
Когда стриминг даёт реальный выигрыш
В чат-интерфейсе разница между «крутится спиннер пять секунд» и «текст начал появляться через триста миллисекунд» ощущается сильно, даже если итоговое время одинаковое. Человек начинает читать раньше и воспринимает систему как отзывчивую.
То же самое с длинными ответами. Если модель пишет пару тысяч токенов, пользователь успевает прочитать начало, пока генерируется конец. Ждать статичный экран всё это время неприятно.
Стриминг также полезен, если хочется дать пользователю возможность прервать генерацию. Увидел, что ответ идёт не туда, нажал стоп, соединение закрылось, деньги за оставшиеся токены не потрачены.
Когда можно не заморачиваться
Если ответ короткий, классификация, извлечение одного поля, простое да или нет, пользователь всё равно не успеет прочитать текст по частям, а код усложнится зря.
Серверная обработка без интерфейса, где результат идёт дальше в базу или в другую систему, тоже не выигрывает от стриминга. Там нужен полный и провалидированный ответ, а частичный текст пришлось бы буферизовать целиком перед использованием, и весь смысл стриминга теряется.
Батч-обработка десятков и сотен запросов почти всегда живёт проще без стриминга: меньше состояния, проще ретраи, проще подсчёт токенов.
Как разбирать частичные чанки
Главная ловушка: сетевой чанк не равен смысловой единице текста. Один чанк может обрезать слово или JSON посередине, особенно если вы одновременно стримите tool use с частичными аргументами функции.
Рабочая практика: копить текстовые дельты в буфер и не пытаться парсить JSON, пока не пришло событие о завершении блока. Пример на Python с SDK Anthropic:
import anthropic
client = anthropic.Anthropic(
api_key="ваш-ключ-claudexia",
base_url="https://api.claudexia.tech/v1",
)
with client.messages.stream(
model="claude-sonnet-4.6",
max_tokens=1024,
messages=[{"role": "user", "content": "Напиши короткое стихотворение про осень"}],
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)
final = stream.get_final_message()
SDK сам собирает дельты в цельный текст и в конце отдаёт полное сообщение с точным числом токенов. Если работаете с сырыми SSE без SDK, повторите ту же логику руками: складывайте строки в буфер, разбирайте JSON только на границе события.
Разрыв соединения и переподключение
Долгий стрим может оборваться: клиент ушёл в фон, мобильная сеть моргнула, прокси закрыл соединение по таймауту. У LLM API нет штатного механизма продолжить с того же места, в отличие от загрузки файлов с resume.
Рабочий подход простой. Ловите обрыв как обычную сетевую ошибку, сохраняйте уже полученный текст и отдельно решайте, что с ним делать: показать частичный ответ с пометкой «прервано» или отправить запрос заново. Для повтора имеет смысл сократить max_tokens до объёма, который реально нужен, чтобы не удвоить счёт зря.
Если обрывы частые именно на длинных генерациях, дело нередко не в клиенте, а в промежуточном прокси с коротким таймаутом на соединение. Стоит поднять таймаут на стороне клиента и проверить, что между приложением и Claudexia нет посредника, который сам обрубает долгие соединения.
Коротко
SSE даёт ощутимый выигрыш там, где человек ждёт и читает: чат, длинные ответы, возможность прервать генерацию. В серверной обработке без интерфейса он только добавляет сложности. Собирайте дельты в буфер, парсите JSON на границе события, а на разрыв соединения реагируйте как на обычную сетевую ошибку с сохранением уже полученного текста.