К концу руководства вы получите рабочую реализацию потоковых ответов от LLM в Next.js с серверной частью, клиентской интеграцией и обработкой отмен. Ожидаемое время выполнения — примерно 1–2 часа при наличии настроенной среды.
Что вы изучите
- Как реализовать Server-Sent Events (SSE) в маршруте Next.js для стриминга токенов.
- Как подключить Vercel AI SDK (версия 0.20.0, 2026) для потоковой генерации ответов.
- Как корректно отменять запросы и освобождать ресурсы с AbortController.
- Клиентские паттерны отображения прогрессивного ответа и UX-паттерны для LLM-стриминга.
- Практические рекомендации по деплою на Vercel и мониторингу.
Требования
- Node.js 20.15 (релиз 2026) — рекомендованная версия. Образ
node:20-slim~190 MB. - Next.js 14 (релиз 2025) с App Router (app/), runtime: edge/experimental поддержка.
- Vercel AI SDK
ai@0.20.0(релиз 2026) для серверного стриминга. - Номинальные ресурсы: минимум 2 GB RAM и 2 vCPU для локальной разработки с моделью средней нагрузки.
- Операционные системы: Ubuntu 22.04/24.04, macOS Ventura (13+)/Windows 11 (WSL2).
- Порты: локально Next.js dev — 3000, SSE эндпоинт использует тот же порт.
Зачем streaming?
Стриминг ответа от LLM сокращает время первого отображаемого символа и увеличивает восприятие скорости системы у пользователя. В 2025–2026 годах продукты с прогрессивным отображением контента показывают рост конверсии до 15% по сравнению с полным ожиданием ответа.
Технически стриминг снижает оконную латентность: вместо ожидания полного ответа приложение получает токены по мере генерации, что позволяет отобразить начало ответа за 100–300 мс при оптимальной сети и модели. Для чат-интерфейсов это улучшает UX и снижает вероятность отмены запроса со стороны пользователя.

Скриншот: прогрессивная отрисовка ответа по токенам
Шаг 1: server-sent events
Цель шага — реализовать простой SSE-эндпоинт в Next.js (app/api/stream/route.ts), который будет передавать события текстом по мере генерации. SSE совместим с большинством браузеров и прост в реализации через Response с типом text/event-stream.
Команда — создайте файл маршрута и установите зависимости (если их нет):
npm init -y
npm install next@14 react react-dom
Пример реализации (app/api/stream/route.ts):
import { NextResponse } from 'next/server'
export async function GET(req: Request) {
const encoder = new TextEncoder()
const stream = new ReadableStream({
start(controller) {
controller.enqueue(encoder.encode('data: starting
'))
let i = 0
const interval = setInterval(() => {
i++
controller.enqueue(encoder.encode(`data: token-${i}
`))
if (i >= 5) {
controller.enqueue(encoder.encode('data: [DONE]
'))
clearInterval(interval)
controller.close()
}
}, 200) // каждые 200ms — пример
}
})
return new NextResponse(stream, {
headers: {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-store',
}
})
}
Объяснение: маршрут открывает поток и посылает несколько сообщений с интервалом 200 ms. Формат SSE требует префикса data: и двойного перевода строки.
Ожидаемый вывод (curl):
$ curl -N http://localhost:3000/api/stream
data: starting
data: token-1
data: token-2
...
data: [DONE]
Типичная ошибка: браузер/сервер отвечает 500 или вы видите ERR_HEADERS_SENT.
Фикс: убедитесь, что вы не вызываете другие методы ответа после создания ReadableStream; используйте return new NextResponse(stream, { headers: {...} }). Для Node.js runtime проверьте, что ваша версия Next.js поддерживает ReadableStream в серверном окружении (Next.js 14+).

Скриншот сетевого трафика: Server-Sent Events в DevTools
Шаг 2: AI SDK от Vercel
Задача — подключить Vercel AI SDK 0.20.0 (2026) для стриминга ответов модели и передавать токены через SSE-эндпоинт. SDK упрощает работу с провайдерами и поддерживает потоковую выдачу токенов.
Команда — установка SDK:
npm install ai@0.20.0
Пример серверного кода (app/api/ai-stream/route.ts):
import { NextResponse } from 'next/server'
import { createClient } from 'ai'
const client = createClient({ apiKey: process.env.VERCEL_AI_API_KEY })
export async function POST(req: Request) {
const { prompt } = await req.json()
const encoder = new TextEncoder()
const stream = new ReadableStream({
async start(controller) {
try {
// SDK предоставляет метод stream, который вызывает onToken
await client.stream({
model: 'gpt-4o-mini',
prompt,
onToken(token) {
controller.enqueue(encoder.encode(`data: ${token}
`))
}
})
controller.enqueue(encoder.encode('data: [DONE]
'))
controller.close()
} catch (err) {
controller.enqueue(encoder.encode(`data: [ERROR] ${String(err)}
`))
controller.close()
}
}
})
return new NextResponse(stream, {
headers: {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-store',
}
})
}
Объяснение: SDK вызывает колбэк onToken при поступлении каждого токена. Мы просто пробрасываем эти токены клиенту через SSE. Такое решение минимизирует задержки между получением токена и его показом в UI.
Ожидаемый вывод (curl):
$ curl -N -X POST http://localhost:3000/api/ai-stream -d '{"prompt":"Hello\
Комментарии (0)
Войдите или зарегистрируйтесь, чтобы оставить комментарий
Загрузка комментариев…