Содержание
  1. Задача BentoML
  2. Service и API
  3. Упаковка Bento
  4. Зависимости и ресурсы
  5. Учебный контракт
  6. Local и managed deployment
  7. Ограничения
  8. Частые вопросы
Обзоры

Обзор BentoML: упаковка модели в API

14 ноября 2026 · 10 минут чтения

Обзор BentoML: упаковка модели в API показывает, как Python-класс с декораторами превращается в HTTP-сервис, как собирается Bento с зависимостями и как проверить контракт входных и выходных данных до развёртывания. Ниже — граница между Service, Bento и деплоем, учебный контракт sentiment и разбор частых ошибок.

Задача BentoML

Документация проекта на docs.bentoml.com описывает BentoML как открытую Python-библиотеку для построения онлайн-систем вывода, оптимизированных под AI-приложения и инференс моделей. Библиотека ставится из PyPI командой pip install bentoml; в разделе про начало работы указана рекомендация Python 3.9+, а в учебном hello-world — Python 3.11. Эти значения относятся к разным страницам и разным сценариям, поэтому при выборе версии интерпретатора ориентируйтесь на требования вашей модели.

Задача библиотеки — снять с разработчика рутину вокруг серверной обвязки. Документация перечисляет четыре направления: построение API для любой AI/ML-модели, упаковка и контейнеризация, повышение утилизации CPU и GPU, а также кастомизация бизнес-логики. Под утилизацией понимаются встроенные механизмы вроде адаптивного батчинга, параллелизма моделей, многостадийных пайплайнов и композиции нескольких моделей. Так документация описывает возможности фреймворка; показатели конкретного сервиса измеряют отдельно.

Практическая ценность проявляется на стыке двух миров. Скрипт инференса обычно живёт в ноутбуке или CLI-утилите: он читает данные, вызывает модель, печатает результат. Продукту нужен сетевой endpoint с предсказуемой схемой запроса и ответа, с версионированием модели и с воспроизводимой средой. BentoML закрывает именно этот переход: вы описываете класс, помечаете методы декораторами, а фреймворк создаёт REST-сервер, маршруты и клиентские обёртки.

Границы применимости тоже стоит держать в голове. BentoML упаковывает сервис и управляет его жизненным циклом. Качество самой модели остаётся вашей ответственностью: правильность sentiment-классификатора проверяют на отдельной размеченной выборке. Успешный ответ сервера подтверждает доступность сервиса. Фреймворк отвечает за транспорт, схему и упаковку; за метрики качества отвечает процесс оценки модели.

Service и API

Согласно странице про онлайн-сервисы, BentoML Service — это класс Python, помеченный декоратором @bentoml.service. Класс описывает логику вывода модели: загрузку весов, предобработку, вызов инференса. Методы, доступные по HTTP, помечаются декоратором @bentoml.api. По соглашению сервис определяют в файле service.py, хотя модуль и имя атрибута можно задать в формате <module_name>:<attribute_name>.

Документация приводит пример сервиса суммаризации: класс Summarization загружает пайплайн Hugging Face, а метод summarize принимает строку и возвращает строку. Контекстный менеджер bentoml.importing() используется для импортов, нужных во время обслуживания. Такой же каркас подходит для собственной модели: в __init__ загружаются веса, в методе с @bentoml.api выполняется предсказание.

Маршрут по умолчанию выводится из имени функции. Метод summarize становится доступен по пути /summarize на порту 3000 при локальном запуске. Параметр route в декораторе @bentoml.api задаёт собственный путь для одного endpoint, а параметр path_prefix в @bentoml.service добавляет общий префикс ко всем маршрутам сервиса, включая health-check /livez и /readyz. Разница существенная: route настраивает один метод, path_prefix — весь сервис.

Внутри метода доступен объект bentoml.Context. Через него читают заголовки входящего запроса, меняют статус-код, заголовки и cookie ответа, а также работают со словарём ctx.state. Документация называет этот словарь per-worker: значения видны в пределах одного воркера и разделяются между API-методами этого воркера. Хранить в нём глобальное состояние всего сервиса при нескольких воркерах не стоит.

Жизненный цикл закрывают хуки. Декоратор @bentoml.on_deployment выполняет глобальную подготовку один раз до запуска воркеров, а @bentoml.on_shutdown — очистку при остановке: закрытие соединений и освобождение ресурсов. Для длительных операций документация предлагает задачи через @bentoml.task с очередью; для параллельных вызовов — свойство .to_async и asyncio.gather.

Упаковка Bento

Bento — это артефакт сборки: сервис, модель, зависимости и метаданные, из которых получается воспроизводимый образ. Документация относит упаковку к отдельному шагу «Packaging for deployment» и указывает, что BentoML генерирует воспроизводимые Docker-образы для развёртывания в любом окружении. Модель подключается через bentoml.models.HuggingFaceModel или bentoml.models.BentoModel; в примере с iris-классификатором модель берётся как BentoModel("iris_sklearn:latest"), а файл загружается через path_of("model.pkl").

Порядок работы выглядит так. Сначала описывается сервис и проверяется локально. Затем фиксируются зависимости и версия модели. После этого собирается Bento и контейнеризуется образ. Документация упоминает, что сервис можно запустить в Docker-контейнерах или Kubernetes, а также развернуть на собственном железе. Для GPU-сценариев есть отдельный раздел про работу с видеокартами.

Отдельного внимания заслуживает история с Runner. Документация прямо говорит: Runner — устаревшая концепция BentoML 1.1, где сервис собирался из компонентов Service и Runner. Начиная с BentoML 1.2 фреймворк перешёл на класс Python как единицу описания сервиса. Для миграции со старых версий есть функция bentoml.runner_service(), превращающая Runner во внутренний сервис. Руководство по интеграции на huggingface.co содержит код с Runner и старыми версиями CUDA — этот пример относится к прежней архитектуре. Для нового проекта берите текущие примеры с @bentoml.service и @bentoml.api со страниц docs.bentoml.com.

Зависимости и ресурсы

Ресурсы объявляются в декораторе @bentoml.service. Документация показывает словарь resources с ключами cpu, memory и gpu: например, {"cpu": "2"}, {"gpu": 1}, {"cpu": "200m", "memory": "512Mi"}. Таймаут задаётся в словаре traffic, например {"timeout": 10}. Все поля конфигурации опциональны и имеют значения по умолчанию, поэтому сервис запустится и без явных ресурсов.

Параметр Где задаётся Пример из документации
cpu resources в @bentoml.service "2", "200m"
memory resources "512Mi", "4Gi"
gpu resources 1, "1"
timeout traffic 10, 600
workers @bentoml.service 1, 4
envs @bentoml.service [{"name": "HF_TOKEN"}]

Переменные окружения перечисляются в списке envs; в примере с vLLM там указан HF_TOKEN. Секреты передавайте через окружение процесса или секреты платформы. В коде сервиса оставляйте обращение к ним. Значения ресурсов применяются и при локальном запуске, и при работе образа в Kubernetes, что помогает держать одинаковые лимиты на всех этапах.

Синхронные и асинхронные API ведут себя по-разному. Для синхронной логики BentoML создаёт пул воркеров подходящего размера. Асинхронные методы освобождают event loop, пока ждут результат, и документация предупреждает: блокирующие вызовы внутри асинхронного API останавливают event loop и мешают работе health-check /readyz. Если синхронный метод нужно вызвать в асинхронном контексте, документация предлагает свойство .to_async, превращающее синхронный метод сервиса в асинхронный.

Учебный контракт

Разберём учебный контракт sentiment, заданный автором примера. Вход — объект {"text": str} с непустой строкой до 200 символов. Выход — {"label": positive|negative|neutral, "score": float от 0 до 1}. Эти ограничения требуют явных validator и model rules: в любом BentoML Service они не возникают автоматически. Ниже — учебный пример; результат работы модели не измерялся.

PYTHON45 строк
from __future__ import annotations
import os
import bentoml
from pydantic import BaseModel, Field, field_validator

class SentimentInput(BaseModel):
    text: str = Field(min_length=1, max_length=200)

    @field_validator("text")
    @classmethod
    def not_blank(cls, v: str) -> str:
        if not v.strip():
            raise ValueError("text must not be blank")
        return v

class SentimentOutput(BaseModel):
    label: str
    score: float = Field(ge=0.0, le=1.0)

    @field_validator("label")
    @classmethod
    def known_label(cls, v: str) -> str:
        allowed = {"positive", "negative", "neutral"}
        if v not in allowed:
            raise ValueError(f"label must be one of {sorted(allowed)}")
        return v

@bentoml.service(
    name="sentiment_service",
    resources={"cpu": "1", "memory": "1Gi"},
    traffic={"timeout": 10},
)
class SentimentService:
    def __init__(self) -> None:
        self.model_revision = os.environ.get("MODEL_REVISION", "local-dev")
        self.model = self._load_model()

    def _load_model(self):
        # Загрузка весов вашей модели. Версия фиксируется MODEL_REVISION.
        raise NotImplementedError("подключите свою модель")

    @bentoml.api
    def classify(self, payload: SentimentInput) -> SentimentOutput:
        raw = self.model.predict(payload.text)
        return SentimentOutput(label=raw["label"], score=raw["score"])

Полностью заполненный положительный fixture: вход {"text": "отлично"}, вымышленный ответ {"label": "positive", "score": 0.8} — форма проходит контракт. Это вымышленное учебное значение; модель его не выдавала, уверенность не измерялась. Отрицательные fixtures: {"text": ""} не проходит входной validator; {"label": "positive", "score": 1.2} не проходит выходной validator. Проверки упаковки: revision модели и зависимости зафиксированы, CPU или GPU объявлены, health-check отделён от оценки качества.

Local и managed deployment

Локальный запуск выполняется командой bentoml serve. Документация показывает, что сервер поднимается на http://localhost:3000, а метод summarize доступен по пути /summarize. Вызвать endpoint можно через curl, через Python-клиент bentoml.SyncHTTPClient("http://localhost:3000") или через Swagger UI: на странице сервера в разделе Service APIs есть кнопка «Try it out» и поле Request body.

Локальная проверка даёт быстрый цикл обратной связи. Вы видите, как схема превращается в маршрут, как отвечает валидатор на некорректный ввод и как выглядит тело ответа. Документация советует создавать виртуальное окружение для изоляции зависимостей и приводит команды для macOS, Linux и Windows. После успешной локальной проверки переходите к сборке Bento и контейнера.

Этап Команда или действие Что проверяем
Локальный запуск bentoml serve Маршруты, схемы, валидаторы
Вызов API curl, Python-клиент, Swagger UI Формат запроса и ответа
Сборка Bento Упаковка сервиса и модели Фиксация revision и зависимостей
Контейнер Генерация Docker-образа Воспроизводимость среды
Развёртывание Docker, Kubernetes, собственное железо Ресурсы и таймауты

Управляемый вариант размещения — BentoCloud, которую документация упоминает как один из путей развёртывания. Документация также описывает агентские навыки: кодирующий агент может развернуть BentoML Service в Kubernetes или EC2. Тарифы, регионы и условия доступа из России проверяйте на сайте провайдера перед выбором площадки.

Ограничения

BentoML упаковывает сервис и не делает sentiment-модель правильной. Успешный ответ сервера говорит о том, что транспорт и схема работают; качество предсказаний проверяют на отдельной размеченной выборке. Смешивать эти две проверки в одном шаге не стоит: health-check отвечает за доступность процесса, а оценка качества — за метрики модели.

Латентность, пропускную способность и стоимость измеряют для выбранных модели, железа и нагрузки. Документация описывает механизмы адаптивного батчинга и параллелизма. Если вам нужны конкретные показатели, их получают на вашем стенде с вашей моделью.

Старый код с Runner относится к BentoML 1.1. Примеры из сторонних руководств могут содержать устаревшие версии CUDA и конструкции, которых нет в текущем API. Сверяйтесь со страницами docs.bentoml.com и переносите оттуда актуальные @bentoml.service и @bentoml.api. Отдельно проверяйте совместимость версии Python: разные страницы документации рекомендуют 3.9+ и 3.11.

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

Что такое BentoML простыми словами?
Это открытая Python-библиотека для построения онлайн-систем вывода моделей. Вы описываете класс с декоратором @bentoml.service, помечаете методы декоратором @bentoml.api, а фреймворк создаёт REST-сервер и маршруты. Документация называет её Unified Model Serving Framework для API инференса и мультимодельных систем.

Как запустить BentoML локально?
Установите библиотеку через pip install bentoml, опишите сервис в service.py и выполните bentoml serve. Сервер поднимется на http://localhost:3000, а метод станет доступен по маршруту из его имени. Проверить вызов можно через curl, Python-клиент или Swagger UI.

Чем BentoML отличается от FastAPI?
FastAPI даёт веб-фреймворк общего назначения, а BentoML добавляет к нему слой работы с моделями: загрузку весов, версионирование, упаковку в Bento и контейнеризацию. Внутри BentoML можно монтировать ASGI-приложения FastAPI через @bentoml.asgi_app. Выбор зависит от того, нужна ли вам готовая обвязка вокруг инференса.

Как задать зависимости и ресурсы сервиса?
Ресурсы перечисляются в словаре resources декоратора @bentoml.service: cpu, memory, gpu. Таймаут задаётся в traffic, переменные окружения — в списке envs. Все поля опциональны и имеют значения по умолчанию, а конфигурация применяется и локально, и в контейнере.

Можно ли развернуть BentoML в Docker и Kubernetes?
Документация указывает, что BentoML генерирует воспроизводимые Docker-образы для развёртывания в любом окружении. Сервис можно запускать в Docker-контейнерах или Kubernetes, а также на собственном железе. Управляемый вариант размещения — BentoCloud; условия доступа проверяйте на сайте провайдера.

Читайте также

3 материала