Разработка 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
    1003

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 дня

Свяжитесь с нами для бесплатной консультации и точного расчёта стоимости. Закажите разработку под ключ с гарантией качества.