Как поднять AI-бота в Telegram через OpenAI API
Эхо-бот в Telegram собирается за полчаса, а бот с OpenAI внутри — за полчаса плюс неделя граблей. Ключ отдаёт 403 из России, длинный ответ не влезает в сообщение, стриминг упирается в «message is not modified», а к утру на балансе минус двадцать долларов, потому что бота нашли посторонние. Разберём схему целиком: где держать процесс, код на aiogram, память диалога, стриминг и защиту кошелька.
Содержание
- Почему AI-бот в телеграме не запускается из России
- Готовим сервер и ключи
- Минимальный AI-бот: сорок строк, которые уже работают
- Память диалога и сколько это стоит в деньгах
- Стриминг ответа и лимиты Telegram, о которые все спотыкаются
- Чтобы бот не разорил вас за одну ночь
- Какой сервер брать в MAATRIX под AI-бота в телеграме
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Почему AI-бот в телеграме не запускается из России
Схема простая: Telegram Bot API — ваш процесс — api.openai.com. Первое звено из России доступно, третье — нет. Ключ, купленный любым способом, с российского IP отвечает так:
$ curl -s https://api.openai.com/v1/models -H "Authorization: Bearer sk-proj-..."
{"error":{"message":"Country, region, or territory not supported",
"type":"request_forbidden","param":null,
"code":"unsupported_country_region_territory"}}
HTTP-код — 403, в SDK это openai.PermissionDeniedError. Ошибка гео-политическая, а не сетевая: TCP-соединение с Cloudflare перед api.openai.com встаёт нормально, и ping до него из Москвы даёт вменяемые 25–40 мс. Поэтому причину часами ищут в сети, хотя её там нет.
VPN на ноутбуке не спасает: бот должен отвечать круглосуточно. VPN на сервере спасает, но добавляет звено, которое падает само и роняет бота. Честнее вынести процесс туда, где ключ работает без прослоек.
Из локаций MAATRIX годятся UK (Лондон) и US (Нью-Йорк) — обе страны в списке поддерживаемых OpenAI. Лондон удобнее по второму звену: серверы Telegram Bot API стоят в Амстердаме, и ping -c 5 149.154.167.220 из Лондона даёт 7–9 мс против 75–85 мс из Нью-Йорка. На фоне 600–900 мс до первого токена это не решает судьбу, но при стриминге бот шлёт на ответ десятки editMessageText, и разница копится.
Готовим сервер и ключи
Берём Ubuntu 24.04 LTS: там из коробки Python 3.12, которого хватает и aiogram, и SDK OpenAI. Сначала пользователь и фаервол.
adduser --disabled-password --gecos "" aibot
ufw default deny incoming
ufw allow 22/tcp
ufw enable
Открывать больше нечего: на long polling бот только ходит наружу, 443 понадобится лишь при вебхуках. Это и есть аргумент начать с polling — домен и сертификат не нужны.
Дальше окружение и зависимости:
apt update && apt install -y python3-venv python3-pip redis-server
sudo -u aibot python3 -m venv /home/aibot/venv
sudo -u aibot /home/aibot/venv/bin/pip install "aiogram>=3.15" "openai>=1.60" redis tiktoken
Токен бота получаем у BotFather командой /newbot: он выглядит как 8123456789:AAH..., числа до двоеточия — user id бота. Сразу загляните в /mybots → Bot Settings → Group Privacy: по умолчанию приватность включена, и в группах бот видит только команды и реплаи — AI-ассистенту, читающему обсуждение, её надо отключить.
Ключ OpenAI создаётся в проекте на платформе и начинается с sk-proj-. Оба секрета кладём в /etc/aibot.env:
TG_TOKEN=8123456789:AAH...
OPENAI_API_KEY=sk-proj-...
MODEL=gpt-4o-mini
chmod 600 /etc/aibot.env — читает только root, а systemd отдаст переменные процессу. Проверяем ключ до всякого кода:
curl -s -o /dev/null -w "%{http_code}\n" https://api.openai.com/v1/models \
-H "Authorization: Bearer $OPENAI_API_KEY"
200 — порядок; 401 — ключ битый или отозван; 403 — запрос всё ещё из неподдерживаемой страны; 429 с телом "code": "insufficient_quota" — ключ живой, но баланс нулевой. Последнее ловит почти каждого: API оплачивается отдельно от подписки ChatGPT Plus, Plus не даёт доступа к API ни на доллар. И честно про оплату: российские карты OpenAI не принимает — либо зарубежная карта, либо посредник, а во втором случае вы делите аккаунт с чужой инфраструктурой. Сам сервер у MAATRIX оплачивается картой РФ, СБП или криптой.
Развернуть за пару минут
Готовый образ на VPS MAATRIX: NVMe, AMD EPYC, root-доступ. Локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Развернуть бот-стекМинимальный AI-бот: сорок строк, которые уже работают
Кладём в /home/aibot/bot.py:
import asyncio, logging, os
from aiogram import Bot, Dispatcher, F
from aiogram.client.default import DefaultBotProperties
from aiogram.enums import ChatAction
from aiogram.types import Message
from aiogram.utils.chat_action import ChatActionSender
from openai import AsyncOpenAI
SYSTEM = "Ты помощник в Telegram. Отвечай коротко, по-русски, без вступлений."
bot = Bot(os.environ["TG_TOKEN"], default=DefaultBotProperties(parse_mode=None))
dp = Dispatcher()
ai = AsyncOpenAI(api_key=os.environ["OPENAI_API_KEY"], timeout=60.0, max_retries=2)
@dp.message(F.text)
async def on_text(m: Message):
async with ChatActionSender(bot=bot, chat_id=m.chat.id, action=ChatAction.TYPING):
r = await ai.chat.completions.create(
model=os.environ["MODEL"],
messages=[{"role": "system", "content": SYSTEM},
{"role": "user", "content": m.text}],
max_tokens=800,
)
await m.answer(r.choices[0].message.content)
async def main():
await dp.start_polling(bot)
if __name__ == "__main__":
logging.basicConfig(level=logging.INFO)
asyncio.run(main())
Три детали, на которых спотыкаются. В aiogram 3.7+ parse_mode задаётся через DefaultBotProperties, старый Bot(parse_mode=...) бросает TypeError. ChatActionSender нужен потому, что индикатор «печатает…» живёт ровно 5 секунд, а модель думает дольше — без него он гаснет, и пользователь решает, что бот умер. timeout=60.0 ставим явно, иначе зависший запрос держит хендлер очень долго.
Запускаем вручную, чтобы увидеть трейсбек: set -a; . /etc/aibot.env; set +a, затем sudo -u aibot -E /home/aibot/venv/bin/python /home/aibot/bot.py.
Грабля при смене модели: у reasoning-моделей серии o параметр зовётся max_completion_tokens, а temperature они не принимают вовсе — ошибка 400 Unsupported parameter: 'max_tokens' означает ровно это. Список доступных ключу моделей честнее документации: curl -s https://api.openai.com/v1/models -H "Authorization: Bearer $OPENAI_API_KEY" | grep -o '"id": "[^"]*"'.
Память диалога и сколько это стоит в деньгах
Бот выше отвечает с чистого листа — «а подробнее?» он не поймёт. Историю держим в уже установленном Redis, в /etc/redis/redis.conf хватит трёх строк:
bind 127.0.0.1
maxmemory 128mb
maxmemory-policy allkeys-lru
После systemctl restart redis-server держим диалог списком: LPUSH chat:{user_id}, затем LTRIM chat:{user_id} 0 19 (последние 20 реплик) и EXPIRE chat:{user_id} 86400.
Теперь про деньги — главный сюрприз AI-ботов. Каждый запрос отправляет всю историю заново, поэтому входные токены растут лавиной. Считаем по ставкам gpt-4o-mini (0,15 $ за миллион входных и 0,60 $ за миллион выходных):
| Что отправляем | Входных токенов | Цена ответа | 10 000 ответов | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Только вопрос, без истории | ~250 | $0,00028 | Нужны сами нейросети для контента?Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП. | ||||||||||||||||||||||||||||
| 10 последних реплик | ~1600 | $0,00048 | $4,8 | ||||||||||||||||||||||||||||
| 50 реплик, без обрезки | ~7000 | $0,00129 | Развернуть за пару минутГотовый образ на VPS MAATRIX: NVMe, AMD EPYC, root-доступ. Локации UK, США, Франция и РФ. Оплата картой РФ и по СБП. Развернуть бот-стекМинимальный AI-бот: сорок строк, которые уже работаютКладём в
Три детали, на которых спотыкаются. В aiogram 3.7+ Запускаем вручную, чтобы увидеть трейсбек: Грабля при смене модели: у reasoning-моделей серии Память диалога и сколько это стоит в деньгахБот выше отвечает с чистого листа — «а подробнее?» он не поймёт. Историю держим в уже установленном Redis, в
После Теперь про деньги — главный сюрприз AI-ботов. Каждый запрос отправляет всю историю заново, поэтому входные токены растут лавиной. Считаем по ставкам
Выход везде — 400 токенов. Разница между первой и третьей строкой почти пятикратная, а качество впятеро не растёт. Обрезайте историю не по числу сообщений, а по токенам: Стриминг ответа и лимиты Telegram, о которые все спотыкаютсяЖдать 15 секунд молча никто не будет, поэтому ответ печатают по мере генерации: Частота правок. Telegram даёт примерно одно сообщение в секунду на чат. Правка на каждом чанке приносит Пустая правка. Если текст между двумя правками не изменился, прилетит
Длина. Предел сообщения — 4096, но считается он не в питоновских символах, а в кодовых единицах UTF-16: эмодзи весят по две. Ответ с Отдельно разметка. Модель охотно возвращает markdown, и при
Универсального лечения нет: либо конвертируйте вывод в MarkdownV2 с экранированием всех Чтобы бот не разорил вас за одну ночьTelegram-бот публичен: имя вида
Два риска настройками не закрываются. Диалоги проходят через OpenAI — для чувствительных данных это неприемлемо, там нужна локальная модель. И тарифные лимиты аккаунта на первом уровне невысоки: при всплеске прилетит Какой сервер брать в MAATRIX под AI-бота в телеграмеВся тяжёлая работа идёт на стороне OpenAI, ваш сервер только пересылает текст. По замерам живого бота на polling с Redis: Python с aiogram занимает 95–120 МБ RSS, Redis в простое — около 12 МБ, CPU между запросами не нагружен.
На минимуме реально жить, но своп на 1 ГБ подключите сразу — он спасает от OOM при обновлении зависимостей. Сомневаетесь — берите второй вариант: разница в цене меньше, чем вечер разбора По локации берите UK (Лондон): ключ OpenAI работает без прослоек, до Telegram в Амстердаме 7–9 мс, до пользователей в ЕС низкий пинг, площадка в GDPR-периметре. FR (Франция) по параметрам совпадает с Лондоном, US (Нью-Йорк) предпочтительнее, если бот вдобавок ходит в американские сервисы с требованием чистого US-IP. RU напрямую не годится — оттуда прилетит тот самый 403 и понадобится прокси-звено, о нём отдельно в статье про API-прокси к OpenAI из России. Сравнение площадок — в материале про VPS в Великобритании для Telegram-бота. Оплата сервера — картой российского банка, по СБП, криптой или токеном MAAT; зарубежная карта не нужна. Машина разворачивается за минуты, так что от заказа до первого ответа бота — около часа вместе с кодом. Развернуть за пару минутГотовый образ на VPS MAATRIX: NVMe, AMD EPYC, root-доступ. Локации UK, США, Франция и РФ. Оплата картой РФ и по СБП. Развернуть бот-стек |
Выход везде — 400 токенов. Разница между первой и третьей строкой почти пятикратная, а качество впятеро не растёт. Обрезайте историю не по числу сообщений, а по токенам: enc = tiktoken.get_encoding("o200k_base") и len(enc.encode(text)). Именно get_encoding, а не encoding_for_model — последний не знает новых имён моделей и падает с KeyError. Бюджет контекста держите в 2000–3000 токенов.
Стриминг ответа и лимиты Telegram, о которые все спотыкаются
Ждать 15 секунд молча никто не будет, поэтому ответ печатают по мере генерации: stream=True и правка одного сообщения. Здесь три подводных камня.
Частота правок. Telegram даёт примерно одно сообщение в секунду на чат. Правка на каждом чанке приносит TelegramRetryAfter с полем retry_after, а при упорстве — временную блокировку бота. Рабочий интервал между editMessageText — 1,2 секунды.
Пустая правка. Если текст между двумя правками не изменился, прилетит Bad Request: message is not modified. Это нормальный исход гонки, гасить его надо точечно, а не глушить весь except:
try:
await bot.edit_message_text(buf[:4000], chat_id=m.chat.id, message_id=sent.message_id)
except TelegramBadRequest as e:
if "message is not modified" not in str(e):
raise
Длина. Предел сообщения — 4096, но считается он не в питоновских символах, а в кодовых единицах UTF-16: эмодзи весят по две. Ответ с len(text) == 4050 спокойно улетает в Bad Request: message is too long. Отсюда порог 4000 и нарезка по строкам, чтобы не рвать блоки кода.
Отдельно разметка. Модель охотно возвращает markdown, и при parse_mode="Markdown" одна незакрытая звёздочка даёт:
Bad Request: can't parse entities: Can't find end of the entity starting at byte offset 217
Универсального лечения нет: либо конвертируйте вывод в MarkdownV2 с экранированием всех _*[]()~>#+-=|{}.!, либо — проще — держите parse_mode=None. Поэтому он и стоит в примере выше.
Чтобы бот не разорил вас за одну ночь
Telegram-бот публичен: имя вида @something_ai_bot находится поиском, и через сутки в нём окажутся незнакомые люди — то есть прямой расход баланса. Минимум защиты выглядит так.
- Белый список или квота. Личному боту хватает проверки
if m.from_user.id not in ALLOWED: return. Публичному нужен счётчик в Redis:INCRBY quota:{uid}:{YYYY-MM-DD} {tokens}сEXPIRE 172800и отказ при превышении лимита. - Жёсткий потолок в OpenAI. В настройках проекта задаётся месячный budget limit — единственная защита, которая работает, даже когда код упал или ключ утёк.
- Гигиена ключа. Секреты только в
/etc/aibot.envс правами 600,.envв.gitignore, никаких токенов в логах. Утёкшиеsk-proj-выгребают ботами с публичных репозиториев за минуты, так что при подозрении отзывайте ключ сразу. - Автозапуск. В юните
/etc/systemd/system/aibot.service—User=aibot,EnvironmentFile=/etc/aibot.env,Restart=always,RestartSec=5и обязательноTimeoutStopSec=30, чтобы запросы к OpenAI доигрывали при рестарте. - Логи. Болтливый бот пишет сотни мегабайт в journald: поставьте
SystemMaxUse=200Mв/etc/systemd/journald.conf.
Два риска настройками не закрываются. Диалоги проходят через OpenAI — для чувствительных данных это неприемлемо, там нужна локальная модель. И тарифные лимиты аккаунта на первом уровне невысоки: при всплеске прилетит 429 с телом Rate limit reached ... on requests per min (RPM): Limit 500, Used 500, обрабатывайте его отдельно от insufficient_quota и ставьте экспоненциальный бэкофф.
Какой сервер брать в MAATRIX под AI-бота в телеграме
Вся тяжёлая работа идёт на стороне OpenAI, ваш сервер только пересылает текст. По замерам живого бота на polling с Redis: Python с aiogram занимает 95–120 МБ RSS, Redis в простое — около 12 МБ, CPU между запросами не нагружен.
| Вариант | Конфигурация | Для чего хватает |
|---|---|---|
| Минимум | 1 vCPU, 1 ГБ RAM, 10 ГБ NVMe | Бот на long polling, Redis 128 МБ, до нескольких сотен пользователей |
| Комфортно | 2 vCPU, 2 ГБ RAM, 20–30 ГБ NVMe | Вебхук с nginx и Let's Encrypt, голосовые через ffmpeg, PostgreSQL под историю |
| С запасом | 4 vCPU, 8 ГБ RAM, 60 ГБ NVMe | Несколько ботов, RAG с векторной базой, очередь задач, обработка файлов |
На минимуме реально жить, но своп на 1 ГБ подключите сразу — он спасает от OOM при обновлении зависимостей. Сомневаетесь — берите второй вариант: разница в цене меньше, чем вечер разбора Killed в dmesg. Подробнее про память — в разборе сколько ресурсов нужно VPS под Telegram-ботов. GPU не берите: через API он простаивает.
По локации берите UK (Лондон): ключ OpenAI работает без прослоек, до Telegram в Амстердаме 7–9 мс, до пользователей в ЕС низкий пинг, площадка в GDPR-периметре. FR (Франция) по параметрам совпадает с Лондоном, US (Нью-Йорк) предпочтительнее, если бот вдобавок ходит в американские сервисы с требованием чистого US-IP. RU напрямую не годится — оттуда прилетит тот самый 403 и понадобится прокси-звено, о нём отдельно в статье про API-прокси к OpenAI из России. Сравнение площадок — в материале про VPS в Великобритании для Telegram-бота.
Оплата сервера — картой российского банка, по СБП, криптой или токеном MAAT; зарубежная карта не нужна. Машина разворачивается за минуты, так что от заказа до первого ответа бота — около часа вместе с кодом.
Развернуть за пару минут
Готовый образ на VPS MAATRIX: NVMe, AMD EPYC, root-доступ. Локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Развернуть бот-стекОбсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Частые вопросы
Можно ли обойтись российским VPS и прокси?
Работает, но у вас два процесса вместо одного, лишние 30–80 мс на запрос и вторая точка отказа: при падении прокси бот молча перестаёт отвечать.
Сколько стоит содержать такого бота?
Сервер начального уровня плюс токены: для бота на 20–50 ответов в день расход на API — единицы долларов в месяц. Риск не в трафике, а в отсутствии лимитов: публичный бот без квот съедает месячный бюджет за ночь.
Polling или вебхук для AI-бота?
Начинайте с polling: не нужны домен, сертификат и открытые порты, а пропускную способность всё равно ограничивает модель. На вебхук переходите, когда одновременных диалогов станет много.
Нужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.