Розробка AI-бота для Telegram на базі LLM

Telegram-бот без контексту — марний. LLM не пам'ятають діалог, кожен запит ізольований. Ми вирішуємо це через FSM на Redis та автоматичну компресію історії. Результат: бот, який пам'ятає вас, обробляє голос та картинки, а ви контролюєте бюджет. Наш досвід — 5+ років в AI/ML та більше 30 успішних про

Напрямки AI-розробки

Часті запитання

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1441
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1301
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    998
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1267
  • image_logo-advance_0.webp
    Розробка логотипу компанії B2B Advance
    713
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    1005

Telegram-бот без контексту — марний. LLM не пам'ятають діалог, кожен запит ізольований. Ми вирішуємо це через FSM на Redis та автоматичну компресію історії. Результат: бот, який пам'ятає вас, обробляє голос та картинки, а ви контролюєте бюджет. Наш досвід — 5+ років в AI/ML та більше 30 успішних проєктів.

Які проблеми вирішує Telegram AI-бот

Контекст діалогу. LLM не пам'ятають історію — кожне повідомлення обробляється ізольовано. Ми зберігаємо діалог в Redis через aiogram FSM. Обмежуємо історію останніми 20 повідомленнями (налаштовується). Для довгих сесій автоматично компресуємо контекст за допомогою summarization — стискаємо старі повідомлення в одне резюме.

Мультимодальний ввод. Telegram підтримує текст, голос та фото. Голос транскрибуємо через Whisper (через Groq — затримка <1 сек). Зображення обробляємо через vision API Claude або GPT-4o. Користувачеві не потрібно перемикатися між інструментами — все в одному чаті.

Rate limiting та бюджет. Кожен запит до LLM коштує грошей (токени). Зловмисник може спамити та обнулити рахунок. Ми ставимо обмеження: не більше 10 запитів за хвилину на користувача. При перевищенні бот пише: «⏳ Занадто багато запитів. Зачекайте хвилину.» Додатково — daily cap на токени з повідомленням адміністратора.

Як ми це робимо: стек та код

Стек: aiogram 3.x (асинхронний фреймворк), Redis (FSM та кеш), Anthropic SDK (Claude), Groq SDK (Whisper), Anthropic Vision API. Конфігурація через змінні середовища, деплой в Docker.

Базовий AI-бот з aiogram 3.x

import asyncio from aiogram import Bot, Dispatcher, Router, types, F from aiogram.filters import CommandStart, Command from aiogram.fsm.context import FSMContext from aiogram.fsm.storage.redis import RedisStorage from anthropic import AsyncAnthropic BOT_TOKEN = "BOT_TOKEN" ANTHROPIC_API_KEY = "ANTHROPIC_API_KEY" bot = Bot(token=BOT_TOKEN) storage = RedisStorage.from_url("redis://localhost:6379") dp = Dispatcher(storage=storage) router = Router() dp.include_router(router) thropic_client = AsyncAnthropic(api_key=ANTHROPIC_API_KEY) # Історія діалогу — зберігається в FSM context @router.message(CommandStart()) async def start(message: types.Message, state: FSMContext): await state.update_data(history=[]) await message.answer( "Привет! Я AI-ассистент на базе Claude. Задай любой вопрос.", reply_markup=get_main_keyboard() ) def get_main_keyboard(): from aiogram.utils.keyboard import ReplyKeyboardBuilder builder = ReplyKeyboardBuilder() builder.button(text="🗑 Очистить историю") builder.button(text="ℹ️ О боте") builder.adjust(2) return builder.as_markup(resize_keyboard=True) @router.message(F.text == "🗑 Очистить историю") async def clear_history(message: types.Message, state: FSMContext): await state.update_data(history=[]) await message.answer("История диалога очищена.") @router.message(F.text & ~F.text.startswith("/")) async def handle_text(message: types.Message, state: FSMContext): data = await state.get_data() history = data.get("history", []) # Додаємо повідомлення користувача в історію history.append({"role": "user", "content": message.text}) # Показуємо "друкує..." await bot.send_chat_action(message.chat.id, "typing") # Streaming відповідь full_response = "" sent_message = await message.answer("...") async with anthropic_client.messages.stream( model="claude-haiku-4-5", max_tokens=2048, system="Ти — полезный ассистент. Отвечай кратко и по существу.", messages=history, ) as stream: async for text in stream.text_stream: full_response += text # Оновлюємо повідомлення кожні 50 символів if len(full_response) % 50 == 0: await sent_message.edit_text(full_response) await sent_message.edit_text(full_response) # Зберігаємо відповідь в історію history.append({"role": "assistant", "content": full_response}) # Обмежуємо історію — 20 повідомлень await state.update_data(history=history[-20:]) 

Обробка голосових повідомлень

import io from groq import AsyncGroq groq_client = AsyncGroq(api_key="GROQ_API_KEY") @router.message(F.voice) async def handle_voice(message: types.Message, state: FSMContext): await bot.send_chat_action(message.chat.id, "typing") # Завантажуємо голосове повідомлення voice = message.voice file = await bot.get_file(voice.file_id) file_bytes = await bot.download_file(file.file_path) # Транскрибуємо через Whisper на Groq (швидко) transcription = await groq_client.audio.transcriptions.create( file=("voice.ogg", file_bytes.read()), model="whisper-large-v3", language="ru", ) text = transcription.text await message.answer(f"📝 Розпізнано: {text}") # Обробляємо як текстове повідомлення await handle_text_with_content(message, state, text) 

Обробка зображень

import base64 @router.message(F.photo) async def handle_photo(message: types.Message, state: FSMContext): await bot.send_chat_action(message.chat.id, "typing") # Беремо фото найкращої якості photo = message.photo[-1] file = await bot.get_file(photo.file_id) file_bytes = await bot.download_file(file.file_path) image_data = base64.standard_b64encode(file_bytes.read()).decode() caption = message.caption or "Что на этом изображении?" response = await anthropic_client.messages.create( model="claude-haiku-4-5", max_tokens=1024, messages=[{ "role": "user", "content": [ {"type": "image", "source": {"type": "base64", "media_type": "image/jpeg", "data": image_data}}, {"type": "text", "text": caption}, ] }] ) await message.answer(response.content[0].text) 

Rate limiting та billing захист

from aiogram.filters import BaseFilter from collections import defaultdict import time class RateLimitFilter(BaseFilter): def __init__(self, rate_limit: int = 10, period: int = 60): self.rate_limit = rate_limit self.period = period self.user_requests = defaultdict(list) async def __call__(self, message: types.Message) -> bool: user_id = message.from_user.id now = time.time() # Видаляємо старі запити self.user_requests[user_id] = [ t for t in self.user_requests[user_id] if now - t < self.period ] if len(self.user_requests[user_id]) >= self.rate_limit: await message.answer("⏳ Занадто багато запитів. Зачекайте хвилину.") return False self.user_requests[user_id].append(now) return True # Застосовуємо фільтр @router.message(RateLimitFilter(rate_limit=10), F.text) async def handle_with_limit(message: types.Message, state: FSMContext): await handle_text(message, state) 

Як забезпечити контекст діалогу в Telegram-боті?

Для постійного контексту ми використовуємо Redis Storage. Стан FSM зберігається між запитами. Історія діалогу — масив повідомлень з ролями user та assistant. Обмежуємо його останніми 20 повідомленнями, щоб не перевищити контекстне вікно моделі (у Claude Haiku — 200k токенів). Якщо діалог довший — автоматично компресуємо старі повідомлення в одне резюме через LLM.

Чому Redis, а не PostgreSQL?

Redis дає latency p99 < 10 мс, PostgreSQL — ~50 мс. Для FSM, де кожен запит перезаписує стан, швидкість критична. Крім того, Redis автоматично видаляє застарілі дані (TTL), що спрощує підтримку.

Процес роботи

Етап Тривалість Результат
Аналіз вимог 1 день Технічне завдання, вибір LLM, архітектура
Прототип бота 2-3 дні MVP з текстовим діалогом
Інтеграція голосу/зображень 2-3 дні Мультимодальний ввод
Rate limiting, адмін-панель 3-5 днів Захист від зловживань, моніторинг
Деплой та тестування 2-3 дні Публікація, навантажувальне тестування

Порівняння моделей LLM для Telegram-бота

Модель Швидкість (latency p50) Якість відповідей Вартість за 1M токенів
Claude Haiku 300 мс Хороша $0.25
GPT-4o 800 мс Відмінна $5.00
LLaMA 3 (local) 150 мс Середня $0.02 (електроенергія)

Claude Haiku в 2.5 рази швидше GPT-4o при порівнянній якості для типових завдань, що робить його оптимальним для чат-ботів.

Практичний кейс: клієнтська підтримка

З нашої практики: для SaaS-продукту розробили Telegram-бота на Claude Haiku. Результат: 73% звернень оброблялися без участі підтримки. Час відповіді: 24 години → миттєво. Клієнт заощадив ~40% бюджету підтримки в перший місяць. Ми налаштували rate limiting та денний ліміт токенів — щоденна витрата не перевищувала $1.5, що підтверджує ефективність підходу.

Типові помилки при розробці AI-бота

  • Зберігання історії в пам'яті процесу. При перезапуску бота втрачається контекст. Використовуйте Redis.
  • Ігнорування rate limiting. Один користувач може спамити та обнулити бюджет. Обов'язково ставте ліміти.
  • Відсутність обробки помилок LLM. Модель може впасти або повернути некоректну відповідь. Обгортайте виклики в try-except.
  • Жорстка прив'язка до однієї моделі. Якщо модель стане недоступною, бот перестане працювати. Передбачте fallback на іншу LLM.

Що входить в роботу

  • Технічне завдання та вибір стеку.
  • Розробка бота (діалог, голос, зображення).
  • Налаштування rate limiting та адміністрування.
  • Інтеграція Redis та деплой в Docker.
  • Документація, доступи та навчання команди.
  • Підтримка протягом місяця після запуску.

Строки орієнтовно

  • Базовий бот з діалогом: 2–3 дні
  • Голос + зображення: 2–3 дні
  • Rate limiting + admin panel: 1 тиждень
  • Публікація + моніторинг: +2–3 дні

Зв'яжіться з нами для безкоштовної консультації та точного розрахунку вартості. Замовте розробку під ключ з гарантією якості.