Сижу, пытаюсь в третий раз объяснить ChatGPT контекст задачи — и понимаю, что трачу больше времени на вводные, чем на саму работу. Каждый новый чат начинается с нуля. Никакой памяти, никакого «ты же знаешь, как я обычно пишу». Это и стало последней каплей — решил сделать своего бота в Telegram, который знает меня, работает по моим правилам и всегда под рукой.
Расскажу, что получилось, что сломалось и почему я в итоге доволен — хотя путь был кривым.
Что вообще нужно, чтобы это заработало
Минимальный набор: аккаунт в Telegram, API-ключ от языковой модели и место, где бот будет жить. Со вторым пунктом я сначала пошёл не туда — взял самый дорогой тариф GPT-4, потому что «ну раз для себя, то лучшее». Через неделю посмотрел на счёт и тихо переключился на GPT-4o-mini. Для личного ассистента разница в качестве почти незаметна, а цена — в десять раз ниже.
Для хостинга есть три реальных варианта.
Локально на своём компьютере. Просто, бесплатно, но работает только пока компьютер включён. Подходит, чтобы понять механику и не больше.
Railway или Render. Бесплатные тарифы, деплой через GitHub, бот живёт в облаке постоянно. Я остановился здесь.
VPS. Полный контроль, но надо уметь работать с сервером. Если не умеешь — не начинай с этого.
Создаём бота через BotFather
Самая простая часть, хотя я умудрился и тут потерять минут двадцать.
Открываешь Telegram, находишь @BotFather, пишешь /newbot. Он спрашивает имя бота (это то, что видят люди) и username (должен заканчиваться на bot). Дальше BotFather выдаёт токен — длинную строку вроде 7284920183:AAF.... Это ключ от бота, храни его как пароль.
Где я застрял: назвал username уже занятым именем и потом долго придумывал свободное. Совет — добавляй к имени цифры или год, так быстрее.
После создания сразу иди в настройки: /mybots → выбираешь бота → Bot Settings → Allow Groups: Off (если хочешь только личное использование). Иначе бот может оказаться в чужих группах, если кто-то угадает его имя.
Код: минимально рабочая версия
Я писал на Python с библиотекой python-telegram-bot. Вот скелет, который реально работает:
import os
from telegram import Update
from telegram.ext import ApplicationBuilder, MessageHandler, filters, ContextTypes
from openai import OpenAI
client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
SYSTEM_PROMPT = """Ты — мой персональный ассистент.
Знаешь, что я работаю с текстами и технологиями.
Отвечай по-русски, коротко и по делу."""
async def handle_message(update: Update, context: ContextTypes.DEFAULT_TYPE):
user_message = update.message.text
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": user_message}
]
)
await update.message.reply_text(response.choices[0].message.content)
app = ApplicationBuilder().token(os.environ["TELEGRAM_TOKEN"]).build()
app.add_handler(MessageHandler(filters.TEXT, handle_message))
app.run_polling()
Это работает. Но у этой версии нет памяти — каждое сообщение бот обрабатывает как первое. Для настоящего ассистента это проблема.
Добавляем память разговора
Час потратил на то, чтобы сделать «умную» память через векторную базу данных — и в итоге выбросил всё это. Для личного использования хватает хранить последние N сообщений в обычном словаре.
conversation_history = {}
async def handle_message(update: Update, context: ContextTypes.DEFAULT_TYPE):
user_id = update.effective_user.id
user_message = update.message.text
if user_id not in conversation_history:
conversation_history[user_id] = []
conversation_history[user_id].append(
{"role": "user", "content": user_message}
)
# Берём только последние 10 сообщений, чтобы не раздувать контекст
recent_history = conversation_history[user_id][-10:]
messages = [{"role": "system", "content": SYSTEM_PROMPT}] + recent_history
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=messages
)
assistant_reply = response.choices[0].message.content
conversation_history[user_id].append(
{"role": "assistant", "content": assistant_reply}
)
await update.message.reply_text(assistant_reply)
Важный момент: эта история живёт в памяти процесса. Если бот перезапустится — забудет всё. Для большинства задач это нормально. Если нужна постоянная память — смотри в сторону SQLite, это несложно прикрутить потом.
System prompt: где настоящая магия
Вот чего я не понимал в начале: бот становится персональным не от кода, а от system prompt. Это инструкция, которую модель получает перед каждым разговором. Здесь ты объясняешь, кто ты, как работаешь и что тебе нужно.
Мой prompt эволюционировал раз пять. Сейчас там есть контекст обо мне — чем занимаюсь, в каком часовом поясе, на каком языке отвечать по умолчанию. Стиль ответов — без воды, без «конечно!», без лишних предисловий, сразу к делу. Частые сценарии — я добавил несколько штук: «если просят отредактировать текст — сохраняй мой стиль», «если вопрос про код — давай рабочий пример, а не объяснения».
Первые версии были слишком длинными и торжественными. Сейчас — три абзаца, конкретно. Работает лучше.
Деплой на Railway
Railway подключается к GitHub-репозиторию и сам собирает проект при каждом пуше. Создаёшь аккаунт, жмёшь New Project → Deploy from GitHub, выбираешь репозиторий.
Переменные окружения (TELEGRAM_TOKEN, OPENAI_API_KEY) добавляешь в Variables. Никогда не клади их в код напрямую — это базовая гигиена.
Бесплатный тариф Railway даёт 500 часов в месяц. Если бот только для тебя — хватит с запасом.
После деплоя бот работает постоянно. Пишешь в Telegram — получаешь ответ за секунду-две. Именно так и должно быть.
Прошло несколько недель с момента запуска. Бот стал частью рабочего процесса: черновики, быстрые переводы, «объясни мне вот эту ошибку». Главное — он знает мой контекст с первого сообщения, а не с пятого.
Единственное, что я бы сделал иначе с самого начала — сразу написал нормальный system prompt, а не занимался кодом. Потому что код здесь несложный. А вот объяснить машине, кто ты и что тебе нужно, — это отдельное искусство.
