hubris
Чат-бот на Python за 15 минут: пошаговый гайд по LLM API

Чат-бот на Python за 15 минут: пошаговый гайд по LLM API

1 июля 2026 г. · Команда Hubris · 7 мин чтения

Чтобы написать чат-бота на Python, достаточно трёх вещей: библиотеки openai, API-ключа и доступа к Chat Completions API. В этом гайде вы за 15 минут пройдёте путь от пустой папки до консольного бота, который помнит историю диалога и печатает ответ по мере генерации. Работаем через Hubris — OpenAI-совместимый API с оплатой в рублях.

Что понадобится: окружение и API-ключ

Нужны Python 3.10 или новее, официальная библиотека openai и ключ Hubris. Ключ выпускается за пару минут:

  1. Зарегистрируйтесь на hubris.pw — вход по коду из письма, пароль придумывать не нужно.
  2. В разделе «Ключи» создайте API-ключ. Полностью он показывается один раз — сразу сохраните его в надёжном месте.
  3. В разделе «Биллинг» пополните баланс: по СБП, банковской картой или по счёту, если вы юридическое лицо.

Теперь подготовьте окружение и положите ключ в переменную окружения — хранить его в коде нельзя:

python -m venv .venv && source .venv/bin/activate
pip install openai
export HUBRIS_API_KEY="sk-gw-ваш-ключ"

Если что-то пошло не так, сверьтесь с быстрым стартом — там тот же путь расписан со скриншотами.

Первый запрос к модели

Библиотека openai умеет работать с любым совместимым сервисом — достаточно указать base_url. Создайте файл bot.py:

import os
from openai import OpenAI

client = OpenAI(
    base_url="https://api.hubris.pw/v1",
    api_key=os.environ["HUBRIS_API_KEY"],
)

response = client.chat.completions.create(
    model="openai/gpt-4o-mini",
    messages=[
        {"role": "user", "content": "Объясни в двух предложениях, что такое LLM."}
    ],
)
print(response.choices[0].message.content)

Запустите python bot.py — в консоли появится ответ модели. Имя модели задаётся строкой вида провайдер/название, а messages — это список сообщений диалога. Полный перечень параметров запроса и формат ответа описаны в справочнике Chat Completions.

Цикл диалога: учим бота помнить контекст

Светящееся окно терминала с петлями цикла диалога

Модель не хранит состояние между запросами — каждый вызов для неё первый. «Память» делается просто: вы накапливаете список сообщений и каждый раз отправляете его целиком.

history = []

while True:
    user_input = input("Вы: ")
    if user_input.lower() in ("выход", "exit"):
        break
    history.append({"role": "user", "content": user_input})
    response = client.chat.completions.create(
        model="openai/gpt-4o-mini",
        messages=history,
    )
    answer = response.choices[0].message.content
    history.append({"role": "assistant", "content": answer})
    print(f"Бот: {answer}\n")

Обратите внимание: в историю добавляются и реплики пользователя, и ответы модели. Уберите вторую строку с append — и на втором вопросе бот «забудет», что сам говорил секунду назад.

У такой памяти есть цена: чем длиннее история, тем больше входных токенов уходит на каждый запрос. Предел тоже существует — контекстное окно; у openai/gpt-4o-mini это 128 тысяч токенов, на десятки экранов переписки хватит с запасом.

Потоковый ответ: текст появляется по мере генерации

Поток светящихся токенов течёт между двумя узлами

Пока модель пишет длинный ответ, пользователь смотрит на пустой экран — для чат-бота это плохо. Решение — параметр stream=True: сервер отдаёт ответ маленькими частями по мере генерации, и бот «печатает» как живой собеседник.

def ask(messages: list) -> str:
    stream = client.chat.completions.create(
        model="openai/gpt-4o-mini",
        messages=messages,
        stream=True,
    )
    parts = []
    for chunk in stream:
        if chunk.choices and chunk.choices[0].delta.content:
            text = chunk.choices[0].delta.content
            parts.append(text)
            print(text, end="", flush=True)
    print()
    return "".join(parts)

Две детали, на которых спотыкаются новички. Во-первых, текст приходит кусками в delta.content, и у служебных частей потока он пустой — поэтому нужна проверка перед печатью. Во-вторых, ответ всё равно надо собрать целиком (список parts), чтобы положить его в историю диалога.

Системный промпт и выбор модели

Характер бота задаёт системное сообщение — первая запись в истории с ролью system. Модель будет следовать ей во всём диалоге:

history = [{
    "role": "system",
    "content": "Ты — ассистент службы поддержки интернет-магазина. "
               "Отвечай кратко, дружелюбно и только по-русски.",
}]

Смена модели — одна строка кода: подставьте другое имя в параметр model. Несколько ходовых вариантов для чат-ботов (цены за 1 млн токенов, актуальны на июнь 2026):

МодельВход, ₽Выход, ₽
openai/gpt-4o-mini15,9263,66
deepseek/deepseek-chat21,2484,90
openai/gpt-5-mini26,53212,21
anthropic/claude-haiku-4.5106,11530,53

Для первых экспериментов в каталоге есть модели с суффиксом :free — например, meta-llama/llama-3.3-70b-instruct:free: токены по нулевой цене, но со строгими ограничениями по нагрузке. Для рабочего бота надёжнее недорогая платная модель.

О том, какие задачи бизнес решает чат-ботами на LLM — от поддержки клиентов до обработки заявок, — читайте на странице сценария «Чат-бот». А если у вас уже есть код под API OpenAI и вы ищете способ оплачивать его в рублях, поможет статья «ChatGPT API в рублях».

Полный код чат-бота

Всё вместе — около 40 строк. Сохраните как bot.py и запустите python bot.py:

import os
from openai import OpenAI

client = OpenAI(
    base_url="https://api.hubris.pw/v1",
    api_key=os.environ["HUBRIS_API_KEY"],
)

MODEL = "openai/gpt-4o-mini"

history = [{
    "role": "system",
    "content": "Ты — вежливый ассистент. Отвечай кратко и по-русски.",
}]


def ask(messages: list) -> str:
    """Отправляет историю диалога, печатает и возвращает ответ."""
    stream = client.chat.completions.create(
        model=MODEL,
        messages=messages,
        stream=True,
    )
    parts = []
    for chunk in stream:
        if chunk.choices and chunk.choices[0].delta.content:
            text = chunk.choices[0].delta.content
            parts.append(text)
            print(text, end="", flush=True)
    print()
    return "".join(parts)


print("Чат-бот запущен. Напишите «выход», чтобы завершить.")
while True:
    user_input = input("\nВы: ").strip()
    if not user_input:
        continue
    if user_input.lower() in ("выход", "exit", "quit"):
        print("До встречи!")
        break
    history.append({"role": "user", "content": user_input})
    print("Бот: ", end="", flush=True)
    answer = ask(history)
    history.append({"role": "assistant", "content": answer})

Этого каркаса достаточно, чтобы перенести бота куда угодно: тот же код работает в Telegram-обработчике, в веб-сервисе на FastAPI или в консольной утилите для коллег.

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

Подойдёт ли библиотека openai для других моделей?

Да. API Hubris совместим с форматом OpenAI Chat Completions, поэтому один и тот же код работает со всеми моделями каталога — меняется только строка model. Можно начать на gpt-4o-mini, а завтра переключиться на DeepSeek или Claude без переписывания бота.

Сколько стоит работа такого бота?

Оплата — по фактическому расходу токенов, отдельно за вход и выход. Один обмен репликами на openai/gpt-4o-mini (вопрос плюс ответ, примерно 500 токенов) обходится около двух копеек по ценам на июнь 2026. С ростом истории диалога запросы дорожают, потому что вся переписка отправляется заново.

Как контролировать расходы?

Баланс в Hubris предоплатный: вы пополняете счёт в разделе «Биллинг» и тратите только то, что на нём есть, — без автосписаний с карты. Расход по каждому запросу виден в журнале личного кабинета: модель, токены, стоимость в рублях.

Что делать, когда история диалога станет слишком длинной?

Простейший приём — оставлять системный промпт и последние 20–30 сообщений, а старые удалять. Приём поинтереснее — попросить ту же модель сжать давнюю часть переписки в короткое резюме и подставить его в начало истории. Для бота из этого гайда хватит первого варианта.

Все модели из статьи доступны в Hubris — единый API, оплата в рублях.