Обзор
Создадим Telegram-бота с AI-возможностями: он будет помнить контекст разговора, использовать локальную LLM через Ollama и отвечать на вопросы по вашим документам.
Установка зависимостей
pip install python-telegram-bot langchain langchain-ollama
pip install python-dotenv Структура проекта
tg-ai-bot/
├── bot.py
├── .env
└── requirements.txt Код бота
>import os
from telegram import Update
from telegram.ext import Application, MessageHandler, filters, ContextTypes
from langchain_ollama import OllamaLLM
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.messages import HumanMessage, AIMessage
llm = OllamaLLM(model="llama3.2")
history = {}
async def handle_message(update: Update, context: ContextTypes.DEFAULT_TYPE):
chat_id = update.effective_chat.id
user_text = update.message.text
if chat_id not in history:
history[chat_id] = []
history[chat_id].append(HumanMessage(content=user_text))
if len(history[chat_id]) > 20:
history[chat_id] = history[chat_id][-20:]
messages = [("system", "Ты полезный ассистент.")]
for msg in history[chat_id]:
role = "user" if isinstance(msg, HumanMessage) else "assistant"
messages.append((role, msg.content))
prompt = ChatPromptTemplate.from_messages(messages)
chain = prompt | llm
response = chain.invoke({})
history[chat_id].append(AIMessage(content=response))
await update.message.reply_text(response)
app = Application.builder().token(os.getenv("BOT_TOKEN")).build()
app.add_handler(MessageHandler(filters.TEXT, handle_message))
app.run_polling() Файл .env
BOT_TOKEN=your_telegram_bot_token_here Запуск как системная служба
>[Unit]
Description=AI Telegram Bot
After=network.target
[Service]
WorkingDirectory=/home/user/tg-ai-bot
EnvironmentFile=/home/user/tg-ai-bot/.env
ExecStart=/home/user/tg-ai-bot/venv/bin/python bot.py
Restart=always
[Install]
WantedBy=multi-user.target Частые ошибки
Большинство сбоев Telegram-ботов на python-telegram-bot связано не с LLM, а с самим механизмом получения обновлений от Telegram.
telegram.error.Conflict: terminated by other getUpdates request
Эта ошибка означает, что два экземпляра бота одновременно опрашивают Telegram с одним и тем же токеном — например, старый systemd-процесс не остановился перед запуском нового. Проверьте systemctl status и список процессов (ps aux | grep bot.py) перед повторным запуском.
telegram.error.InvalidToken
Токен из .env не подходит: либо файл не загрузился (проверьте, что python-dotenv действительно вызывается до чтения переменной), либо токен скопирован с лишним пробелом или обрезан. Проверьте значение прямо перед стартом бота, выведя его длину, а не сам токен, в лог.
Long polling против webhook
| Параметр | Long polling | Webhook |
|---|---|---|
| Нужен публичный домен с HTTPS | Нет | Да |
| Задержка ответа | Обычно доли секунды | Минимальная, Telegram сам стучится к вам |
| Сложность настройки на VDS | Низкая, достаточно запустить процесс | Выше, нужен reverse proxy и сертификат |
| Подходит для | Небольших и средних ботов | Высоконагруженных ботов, много обновлений |
Когда такой подход не подходит
- Ожидается высокая нагрузка с тысячами сообщений в минуту — long polling из примера не масштабируется горизонтально без доработки хранения истории.
- История диалога должна переживать перезапуск процесса — текущая реализация хранит её только в памяти словаря
history. - Нужна многопользовательская изоляция с разными системными промптами — потребуется отдельное хранилище настроек на chat_id, а не общий системный промпт.
- Требуется гарантированная доставка сообщений даже при падении процесса — для этого нужна очередь заданий, а не прямой вызов внутри обработчика.
Проверка, что бот отвечает
systemctl status ai-telegram-bot --no-pager
journalctl -u ai-telegram-bot -n 50 --no-pager Убедитесь, что служба в статусе active (running), а в логе нет повторяющихся ошибок подключения к Ollama. Отправьте боту тестовое сообщение и проверьте, что в логе появляется факт получения апдейта — если апдейт не приходит вовсе, проблема на стороне Telegram API или сетевого доступа с сервера, а не в коде бота.
Стоит также предусмотреть ограничение на длину истории и частоту запросов от одного пользователя: без rate limiting один активный пользователь может отправлять сообщения быстрее, чем локальная модель успевает на них отвечать, и очередь необработанных обновлений будет расти. Простейшая защита — ограничить число одновременных запросов к LLM на один chat_id и вернуть сообщение "подождите предыдущий ответ", если лимит превышен.