AI в Next.js через AI Gateway: route handler, стриминг, AI SDK
Как встроить AI в Next.js: route handler на OpenAI SDK с base_url AI Gateway, потоковый ответ через ReadableStream и совместимость с Vercel AI SDK. Ключ только на сервере.
В Next.js модель вызывают на сервере — в route handler'е (App Router) или API route. Клиентские компоненты обращаются к этому эндпоинту, а ключ остаётся в окружении. Ниже — базовый handler, потоковый вариант и подключение через Vercel AI SDK. Модели берём из каталога AI Gateway.
Подготовка
Положите ключ в .env.local как AIGATE_API_KEY (без префикса NEXT_PUBLIC_ — иначе он попадёт в браузер). Базовый URL шлюза — https://ai-gatewey.ru/v1.
npm install openaiРеализация
- Route handler с обычным ответом
Файл
app/api/chat/route.ts— серверный эндпоинт, который зовёт модель и возвращает JSON:// app/api/chat/route.ts import OpenAI from "openai"; const client = new OpenAI({ baseURL: "https://ai-gatewey.ru/v1", apiKey: process.env.AIGATE_API_KEY, }); export async function POST(req: Request) { const { message } = await req.json(); const resp = await client.chat.completions.create({ model: "deepseek/deepseek-chat", messages: [{ role: "user", content: message }], }); return Response.json({ reply: resp.choices[0].message.content }); } - Потоковый ответ
Включаем
stream: trueи отдаём чанки черезReadableStream— фронтенд читает тело потоком:export async function POST(req: Request) { const { message } = await req.json(); const stream = await client.chat.completions.create({ model: "deepseek/deepseek-chat", messages: [{ role: "user", content: message }], stream: true, }); const encoder = new TextEncoder(); return new Response( new ReadableStream({ async start(controller) { for await (const chunk of stream) { const delta = chunk.choices[0]?.delta?.content; if (delta) controller.enqueue(encoder.encode(delta)); } controller.close(); }, }), { headers: { "Content-Type": "text/plain; charset=utf-8" } }, ); } - Вариант на Vercel AI SDK
AI Gateway совместим с провайдером
@ai-sdk/openai: указываемbaseURL, иuseChat/streamTextработают как обычно:// app/api/chat/route.ts import { createOpenAI } from "@ai-sdk/openai"; import { streamText } from "ai"; const aigate = createOpenAI({ baseURL: "https://ai-gatewey.ru/v1", apiKey: process.env.AIGATE_API_KEY, }); export async function POST(req: Request) { const { messages } = await req.json(); const result = streamText({ model: aigate("deepseek/deepseek-chat"), messages, }); return result.toDataStreamResponse(); }
process.env.AIGATE_API_KEY. Не давайте переменной префикс NEXT_PUBLIC_ и не обращайтесь к шлюзу из клиентских компонентов — иначе ключ окажется в бандле браузера.Какие модели подойдут
Для интерактивного UI важна скорость; массовые запросы дешевле гонять через быструю модель, а флагман подключать точечно:
| Модель | Ввод, ₽/1М | Вывод, ₽/1М | Контекст |
|---|---|---|---|
| DeepSeek: DeepSeek V3 | 31 | 125 | 128K |
| OpenAI: GPT-5.4 Mini | 118 | 705 | 400K |
| Anthropic: Claude Sonnet 5 | 314 | 1 568 | 1M |
Частые вопросы
Работает ли хук useChat из Vercel AI SDK?
Да. Клиентский useChat обращается к вашему route handler'у, а тот через провайдер @ai-sdk/openai с baseURL AI Gateway — к модели. Смена провайдера меняет только baseURL и model.
App Router или Pages Router?
Оба подходят. В App Router это route handler app/api/chat/route.ts, в Pages Router — pages/api/chat.ts. Логика вызова SDK одинакова; для стриминга удобнее App Router и Web Streams.
Можно ли звать модель прямо в Server Component?
Можно, если ответ нужен на этапе рендера страницы. Для интерактивного чата используйте route handler или server action, чтобы отвечать на действия пользователя без полной перезагрузки.
AI в Next.js — за пять минут после регистрации
Получить ключ