Skip to main content

AI Telegram Bot on a VDS with LangChain and Ollama

AI Agents on VPS · 19.04.2026 · 4 min read
Illustration for “AI Telegram Bot on a VDS with LangChain and Ollama”

Overview

Let's build a Telegram bot with AI capabilities: it will remember conversation context, use a local LLM through Ollama, and answer questions about your documents.

Installing dependencies

pip install python-telegram-bot langchain langchain-ollama
pip install python-dotenv

Project structure

tg-ai-bot/
├── bot.py
├── .env
└── requirements.txt

Bot code

>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", "You are a helpful assistant.")]
    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()

The .env file

BOT_TOKEN=your_telegram_bot_token_here

Running as a systemd service

>[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
Get your BOT_TOKEN from @BotFather on Telegram. Create a new bot with the /newbot command and copy the token.

Common Errors

Most failures in python-telegram-bot bots have nothing to do with the LLM — they come from the mechanism used to receive updates from Telegram.

telegram.error.Conflict: terminated by other getUpdates request

This error means two bot instances are polling Telegram at the same time with the same token — for example, an old systemd process did not stop before the new one started. Check systemctl status and the process list (ps aux | grep bot.py) before restarting.

telegram.error.InvalidToken

The token from .env is invalid: either the file was not loaded (make sure python-dotenv is actually called before the variable is read), or the token was copied with an extra space or got truncated. Check the value right before the bot starts by logging its length, not the token itself.

Long Polling vs Webhook

Parameter Long polling Webhook
Needs a public domain with HTTPS No Yes
Response latency Usually a fraction of a second Minimal, Telegram pushes to you directly
Setup complexity on a VDS Low, just run the process Higher, needs a reverse proxy and a certificate
Good for Small and medium bots High-load bots with many updates

When This Approach Is Not a Good Fit

  • You expect high load with thousands of messages per minute — the long polling setup in this example does not scale horizontally without reworking history storage.
  • Conversation history must survive a process restart — the current implementation keeps it only in the in-memory history dictionary.
  • You need multi-user isolation with different system prompts — that requires a separate settings store per chat_id, not one shared system prompt.
  • You need guaranteed message delivery even if the process crashes — that requires a task queue, not a direct call inside the handler.

Verifying the Bot Responds

systemctl status ai-telegram-bot --no-pager
journalctl -u ai-telegram-bot -n 50 --no-pager

Confirm the service shows active (running) and the log has no repeating Ollama connection errors. Send the bot a test message and check that the log records the update being received — if no update arrives at all, the problem is on the Telegram API side or the server's network access, not in the bot's code.

It is also worth capping history length and the request rate from a single user: without rate limiting, one active user can send messages faster than the local model can answer them, and the queue of unprocessed updates will keep growing. The simplest safeguard is to limit the number of concurrent LLM requests per chat_id and reply with "please wait for the previous response" if the limit is exceeded.

Was this article helpful?
← Back to Knowledge Base Ask Support