Огляд
Створимо 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 і повернути повідомлення "зачекайте на попередню відповідь", якщо ліміт перевищено.