|Docs

Deploy an AI-Powered Bot for Discord or Telegram

botdiscordtelegrampython

This guide covers deploying a chat bot for Discord or Telegram on Railway that uses an LLM API (OpenAI, Anthropic, etc.) to generate responses. The bot runs as an always-on service, listens for messages, and replies with AI-generated text.

Railway is a CPU-based platform. The bot calls external LLM APIs over HTTP. No models run locally.

Architecture

The bot consists of two components:

  • Bot service runs continuously, connects to the Discord or Telegram API, listens for messages, and calls the LLM API to generate responses.
  • Postgres (optional) stores conversation history per user or channel so the bot can maintain context across messages.

Bot services do not need a public domain. They connect outbound to the messaging platform's API and to the LLM API.

Prerequisites

1. Set up the project

Create a project directory with a requirements.txt:

For a Discord bot:

discord.py
openai

For a Telegram bot:

python-telegram-bot
openai

Install dependencies locally with pip install -r requirements.txt.

2. Write the bot code

Here is a minimal Discord bot using discord.py and OpenAI. Save this as bot.py:

import os
import discord
from openai import AsyncOpenAI

intents = discord.Intents.default()
intents.message_content = True
bot = discord.Client(intents=intents)
llm = AsyncOpenAI(api_key=os.environ["OPENAI_API_KEY"])

@bot.event
async def on_message(message):
    if message.author == bot.user:
        return

    response = await llm.chat.completions.create(
        model="gpt-4o-mini",
        messages=[
            {"role": "system", "content": "You are a helpful assistant."},
            {"role": "user", "content": message.content},
        ],
    )
    await message.channel.send(response.choices[0].message.content)

bot.run(os.environ["DISCORD_TOKEN"])

For Telegram, use python-telegram-bot instead. Save this as bot.py:

import os
from telegram.ext import ApplicationBuilder, MessageHandler, filters
from openai import AsyncOpenAI

llm = AsyncOpenAI(api_key=os.environ["OPENAI_API_KEY"])

async def handle_message(update, context):
    response = await llm.chat.completions.create(
        model="gpt-4o-mini",
        messages=[
            {"role": "system", "content": "You are a helpful assistant."},
            {"role": "user", "content": update.message.text},
        ],
    )
    await update.message.reply_text(response.choices[0].message.content)

app = ApplicationBuilder().token(os.environ["TELEGRAM_TOKEN"]).build()
app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, handle_message))
app.run_polling()

3. Deploy to Railway

  1. Push your bot code to a GitHub repository.
  2. Create a new project on Railway.
  3. Click + New > GitHub Repo and select your repository.
  4. Set the start command to: python bot.py
  5. Set environment variables under the Variables tab:
    • DISCORD_TOKEN or TELEGRAM_TOKEN: your bot token.
    • OPENAI_API_KEY or ANTHROPIC_API_KEY: your LLM API key.
  6. The bot does not need a public domain. It connects outbound to Discord/Telegram servers.

Deploy the bot as an always-on service, not a cron job. Bots must stay connected to receive messages in real time.

4. Add conversation memory with Postgres

Without a database, the bot treats every message independently. To maintain conversation context:

  1. Add PostgreSQL to your project.
  2. Reference DATABASE_URL in the bot service.
  3. Store recent messages per user or channel:
CREATE TABLE conversations (
  id SERIAL PRIMARY KEY,
  channel_id TEXT NOT NULL,
  role TEXT NOT NULL,
  content TEXT NOT NULL,
  created_at TIMESTAMPTZ DEFAULT now()
);

CREATE INDEX idx_conversations_channel ON conversations(channel_id);

Before calling the LLM, load the last N messages for the channel and include them in the messages array. This gives the bot conversational context.

5. Handle rate limits

LLM APIs enforce rate limits on requests per minute and tokens per minute. When your bot is active in multiple channels simultaneously, you can hit these limits. Mitigations:

  • Use a smaller, faster model (GPT-4o mini, Claude Haiku) for most responses. Reserve larger models for complex queries.
  • Add a per-channel cooldown to avoid rapid-fire LLM calls.
  • Implement retry logic with exponential backoff for 429 responses.
  • Truncate conversation history to limit token usage per request.

Next steps