Пошаговый туториал по реализации потоковых ответов от LLM в приложении на Next.js: от Server-Sent Events до интеграции Vercel AI SDK и отмены запросов. Примерное время выполнения — 60–120 минут.
Статья была полезной?
К концу руководства вы получите рабочую реализацию потоковых ответов от LLM в Next.js с серверной частью, клиентской интеграцией и обработкой отмен. Ожидаемое время выполнения — примерно 1–2 часа при наличии настроенной среды.
node:20-slim ~190 MB.ai@0.20.0 (релиз 2026) для серверного стриминга.Стриминг ответа от LLM сокращает время первого отображаемого символа и увеличивает восприятие скорости системы у пользователя. В 2025–2026 годах продукты с прогрессивным отображением контента показывают рост конверсии до 15% по сравнению с полным ожиданием ответа.
Технически стриминг снижает оконную латентность: вместо ожидания полного ответа приложение получает токены по мере генерации, что позволяет отобразить начало ответа за 100–300 мс при оптимальной сети и модели. Для чат-интерфейсов это улучшает UX и снижает вероятность отмены запроса со стороны пользователя.

Скриншот: прогрессивная отрисовка ответа по токенам
Цель шага — реализовать простой 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
Задача — подключить 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)
Войдите или зарегистрируйтесь, чтобы оставить комментарий
Загрузка комментариев…