NormaHub knowledge base

Telegram-бот на AI API

Backend держит ключ, NormaHub отвечает на сообщения: архитектура, история диалога, лимиты бюджета и обработка ошибок.

1. Архитектура: ключ только на backend

Правило, из которого следует всё остальное: секретный ключ живёт на вашем сервере и нигде больше. Telegram-клиент присылает текст вашему backend (webhook или polling), backend добавляет ключ и обращается к NormaHub, ответ уходит пользователю. Клиент, мини-приложение и логи ключа не видят никогда.

import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["NORMAHUB_API_KEY"],  # только backend!
    base_url="https://api.normahub.cc/v1",
)

def answer(text: str) -> str:
    result = client.chat.completions.create(
        model="MODEL_ID",
        messages=[
            {"role": "system", "content": "Отвечай коротко и по-русски."},
            {"role": "user", "content": text[:2000]},
        ],
        max_tokens=256,
    )
    return result.choices[0].message.content or ""

Обрезайте вход (text[:2000]) и ограничивайте выход (max_tokens=256): без этих двух строк один «пошути длинно» от пользователя стоит как сто обычных ответов. Ключ создайте в личном кабинете отдельно под бота, со своим spend limit.

2. История диалога

Модель не помнит прошлые сообщения: память — это вы. Храните на пользователя скользящее окно последних 5–6 реплик и передавайте его в messages вместе с системным промптом. Весь лог слать нельзя: каждое сообщение будет стоить как сумма всей переписки, детали математики — в гайде по стоимости.

# История на пользователя: последние 6 сообщений, не весь лог
# Хранилище: dict в памяти для MVP, Redis/Postgres для продакшена
history: dict[int, list] = {}

def push(user_id: int, role: str, text: str) -> None:
    history.setdefault(user_id, []).append({"role": role, "content": text})
    history[user_id] = history[user_id][-6:]  # скользящее окно

Для MVP хватит dict в памяти, для продакшена — Redis или Postgres с TTL. Системный промпт задаёт язык, длину и характер ответов: чем точнее формат, тем меньше токенов на уточнения.

3. Защита бюджета

Публичный бот — это открытый кошелёк, прикройте его тремя слоями. Первый: rate limit в коде (N сообщений в минуту на пользователя, капча или allowlist для дорогих команд). Второй: spend limit на API-ключе в кабинете — аварийный тормоз при атаке. Третий: max_tokens и обрезка входа на каждый вызов. Мониторьте списания ежедневно первую неделю: аномалии видны сразу.

Разделите модели по командам: дешёвая отвечает в личке, сильная — только по явной команде или для админов. Цены входа и выхода каждой модели — в каталоге.

4. Ошибки и UX

Пользователю нельзя показывать traceback: маппите ошибки в человеческие ответы. 402 — «баланс на обслуживании, вернитесь позже» + алерт вам; 429/503 — «модель перегружена, попробуйте через минуту» с одной кнопкой повтора; 401/403 — только вам в лог, пользователь их чинить не может. Request ID каждого вызова пишите в лог рядом с user_id — поддержка найдёт операцию без вашего ключа.

Медленные ответы обрабатывайте стадиями: сразу «Думаю…», потом editMessageText с результатом. Полная таблица кодов и retry-политики — в гайде по ошибкам. Обзор архитектуры целиком — на странице решения для Telegram-бота.

Частые вопросы

Где хранить API-ключ Telegram-бота?

Только на backend-сервере, в переменных окружения. Ключ нельзя вшивать в Telegram-клиент, мини-приложение, frontend или публичный репозиторий: его извлекут и потратят ваш баланс.

Какую модель выбрать для бота?

Быструю и дешёвую для диалогов (короткие ответы, max_tokens 256–512), сильную — для отдельных тяжёлых команд. Точные ID и цены — в каталоге моделей.

Пользователь заспамил бота. Что защитит бюджет?

Три слоя: rate limit на пользователя в коде, spend limit на API-ключе в личном кабинете и max_tokens на каждый вызов. Один слой без остальных — полумера.

Бот отвечает медленно. Что делать?

Сначала отвечайте пользователю промежуточным сообщением («Думаю…»), затем редактируйте его ответом. Долгие запросы упираются в таймауты Telegram — держите max_tokens разумным и задавайте timeout клиенту.

Нужен ли VPN серверу в России?

Нет. Backend обращается к https://api.normahub.cc/v1 напрямую. Оплата — с рублёвого баланса.