Telegram-бот с GPT на Node.js через AI Gateway (grammY)
Как сделать Telegram-бота с AI на Node.js: grammY или node-telegram-bot-api плюс openai SDK с base_url AI Gateway, память диалога по чату и ключи в переменных окружения.
Соберём AI-бота для Telegram на Node.js: grammY принимает сообщения, а официальный openai SDK обращается к модели. Достаточно направить SDK на AI Gateway через baseURL — и бот отвечает моделями из каталога. В конце — короткий вариант на node-telegram-bot-api.
Подготовка
Понадобятся токен бота от @BotFather и ключ AI Gateway sk-aigate-…. Оба секрета кладём в переменные окружения (TELEGRAM_TOKEN, AIGATE_API_KEY). Базовый URL шлюза — https://ai-gatewey.ru/v1.
npm install grammy openaiРеализация
- Клиент и хранилище контекста
Настраиваем
openaiна AI Gateway и заводим по чату короткую историю сообщений в обычномMap:tstsimport { Bot } from "grammy";import OpenAI from "openai";const bot = new Bot(process.env.TELEGRAM_TOKEN!);const ai = new OpenAI({baseURL: "https://ai-gatewey.ru/v1",apiKey: process.env.AIGATE_API_KEY,});type Msg = { role: "system" | "user" | "assistant"; content: string };const history = new Map<number, Msg[]>();const SYSTEM: Msg = { role: "system", content: "Ты дружелюбный ассистент. Отвечай кратко." }; - Обработчик с памятью диалога
На каждое текстовое сообщение дополняем историю чата, отправляем её модели и возвращаем ответ, попутно обрезая старые реплики:
tstsbot.on("message:text", async (ctx) => {const chatId = ctx.chat.id;const hist = history.get(chatId) ?? [SYSTEM];hist.push({ role: "user", content: ctx.message.text });const resp = await ai.chat.completions.create({model: "deepseek/deepseek-v4-flash",messages: hist,});const answer = resp.choices[0].message.content ?? "…";hist.push({ role: "assistant", content: answer });// держим системный промпт плюс 10 последних реплик; фильтр обязателен —// hist уже начинается с SYSTEM, и без него он копился бы в каждом обменеhistory.set(chatId, [SYSTEM, ...hist.filter((m) => m.role !== "system").slice(-10)]);await ctx.reply(answer);});bot.start(); - Альтернатива: node-telegram-bot-api
Если используете
node-telegram-bot-api, меняется только слой Telegram — вызов SDK тот же:jsjsconst TelegramBot = require("node-telegram-bot-api");const OpenAI = require("openai");const bot = new TelegramBot(process.env.TELEGRAM_TOKEN, { polling: true });const ai = new OpenAI({baseURL: "https://ai-gatewey.ru/v1",apiKey: process.env.AIGATE_API_KEY,});bot.on("message", async (msg) => {// "message" ловит все типы (фото, стикеры, голос), а не только текст —// без фильтра msg.text будет undefined и запрос к модели упадётif (!msg.text) return;const resp = await ai.chat.completions.create({model: "deepseek/deepseek-v4-flash",messages: [{ role: "user", content: msg.text }],});bot.sendMessage(msg.chat.id, resp.choices[0].message.content);});
Какие модели подойдут
Поток сообщений в ботах большой, ответы короткие — берут быструю дешёвую модель, качества которой хватает для большинства диалогов:
Частые вопросы
grammY или node-telegram-bot-api?
grammY современнее, типизирован под TypeScript и удобнее для middleware и сессий. node-telegram-bot-api проще и привычнее в старых проектах. Слой обращения к модели в обоих одинаковый.
Где хранить историю диалога в продакшене?
Map в памяти сбрасывается при перезапуске и не переживает горизонтальное масштабирование. Для боевого бота храните контекст в Redis или БД по идентификатору чата.
Стоит ли использовать webhooks вместо polling?
Для продакшена — да: webhooks экономят ресурсы и лучше масштабируются. Для разработки и небольших ботов polling (bot.start()) проще, ведь не нужен публичный HTTPS-адрес.