Головна / Статті / Архітектура обслуговування моделей: чому API — це лише парадні двері

Архітектура обслуговування моделей: чому API — це лише парадні двері

Розбираємо платформу за ендпоінтом інференсу: маршрутизацію, масштабування, версіонування, спостережуваність, безпеку та виклик моделей зі Spring AI чи LangChain4j.

2004 слів

Подумайте, що бачить відвідувач ресторану: хтось приймає замовлення, зникає в бік кухні й повертається з тарілкою. Невидима частина важливіша. Замовлення треба узгодити, запаси перевірити, кухарі готують страви, одночасно обслуговують багато столів, і кожна тарілка має потрапити до потрібної людини.

Обслуговування моделі машинного навчання влаштоване так само. Ззовні застосунок бачить HTTP-ендпоінт, який приймає запит і повертає передбачення. За ним можуть бути маршрутизація, автентифікація, отримання ознак, попередня обробка, саме середовище виконання моделі, керування ресурсами, вибір версії, моніторинг і обробка збоїв. Ендпоінт — це офіціант. Архітектура обслуговування — увесь ресторан.

Виходимо з ноутбука

Модель може ідеально працювати в ноутбуці й усе одно завдавати чимало клопоту в експлуатації, щойно від неї починають залежати інші системи. Під час розробки дата-сайєнтист завантажує модель, готує вхідні дані, запускає інференс і перевіряє результати, усе в контрольованому середовищі. Продакшн ламає кожну з цих зручностей. Кілька застосунків просять передбачення одночасно, трафік зростає й падає, версії треба міняти, не перериваючи клієнтів, а відповідь може залежати від даних, якими володіють інші сервіси.

У цей момент модель перестає бути окремим артефактом і стає одним із компонентів розподіленої системи. Питання зміщується з того, як її викликати, на те, як надавати інференс як надійний продакшн-сервіс.

API — це парадні двері, не більше

API дає застосункам контрольований спосіб запитувати передбачення, але це лише невелика частина цілого. Уявіть платіж, що проходить через застосунок інтернет-банку. Перш ніж повернеться рішення, запит, можливо, доведеться автентифікувати, збагатити ознаками клієнта, провалідувати, попередньо обробити, зіставити з версією моделі, оцінити, а потім обробити результат.

Кожен із цих кроків може змінити підсумок. Модель може відповідати за мілісекунди, а отримання ознак — гальмувати. Здорова модель може стати недоступною, бо під нею скінчилися обчислювальні ресурси. Нова версія моделі може поводитися інакше, а контракт API при цьому не зміниться взагалі.

Тож ставтеся до API як до точки входу в систему обслуговування, так само як офіціант уособлює видимий бік ресторану.

Що відбувається за один інференс

Продакшн-запит зазвичай проходить крізь кілька зон відповідальності, перш ніж відповідь дійде до бізнес-застосунку. Шлюз може займатися автентифікацією, авторизацією, маршрутизацією та лімітами запитів. Потім шар обслуговування отримує ознаки чи контекст, виконує попередню обробку, обирає версію моделі й викликає середовище виконання. Після цього вивід, можливо, треба ще обробити, перш ніж повернути.

Шлях виглядає так: клієнтський застосунок, далі API або шлюз, далі шар обслуговування, далі отримання ознак і контексту, далі середовище виконання моделі, далі постобробка, далі відповідь.

Коли бачиш увесь шлях, простіше діагностувати. Якщо виклик триває дві секунди замість двохсот мілісекунд, модель може бути ні до чого. Винними можуть бути отримання ознак, мережеві переходи, конкуренція за ресурси чи перевантажений воркер. Тому розглядайте обслуговування як одну систему від клієнта до середовища виконання і так само її вимірюйте.

Архітектура за цим

Зрілі рішення розподіляють відповідальність, а не запихають усе в один сервіс. Бізнес-застосунок відповідає за взаємодію з клієнтом чи процесом. Шар обслуговування обробляє запити на інференс. Середовище виконання запускає модель. Довкола них — платформні можливості для розгортання, масштабування, безпеки, спостережуваності та керування ресурсами.

Ключове: обслуговування моделей належить до платформи й стоїть між застосунками та середовищами виконання. Воно може підключатися до сховищ ознак, реєстрів моделей, шлюзів та інфраструктури, не роблячи нічого з цього частиною моделі. Коли моделей і споживачів більшає, такий поділ окупається: платформні команди можуть змінювати деталі розгортання й середовища виконання, не змушуючи кожну команду застосунку в них розбиратися.

Однієї моделі рідко вистачає

У першому розгортанні може бути одна модель, але корпоративні платформи рідко лишаються такими охайними. Різним бізнес-функціям потрібні різні моделі, а одна модель може існувати в кількох версіях, поки її оцінюють і розгортають.

Тому маршрутизація стає питанням проєктування. Платформа має вирішувати, яка модель і версія відповідає на запит і де вона працює, особливо коли моделі відрізняються вимогами до ресурсів або ділять залізо.

Реєстр моделей дає надійний каталог того, що є і які версії доступні. Замість розкидати деталі розгортання по коду застосунків, шар обслуговування читає інформацію про життєвий цикл із реєстру. Так створення моделей відокремлюється від їх споживання, і модель може розвиватися, не змушуючи клієнтів змінюватися з кожним релізом.

Масштабування інференсу

Масштабування інференсу не завжди схоже на масштабування звичайного вебсервісу. Stateless API часто росте додаванням екземплярів. Сервери моделей мають додаткові обмеження, бо моделі можуть зʼїдати багато памʼяті, потужностей GPU чи часу на запуск.

Великій моделі може знадобитися спеціалізоване залізо, а маленька може обробляти тисячі запитів на секунду. Деяким навантаженням корисно групувати запити в батчі, щоб залізо не простоювало. Інші не терплять навіть невеликого зростання часу відповіді.

Тож рішення про масштабування мають враховувати розмір моделі, трафік, паралельність, залізо, цілі щодо затримки й вартість разом. Додавання екземплярів може прибрати одне вузьке місце і створити інше, якщо обмеженням стане час завантаження чи наявність GPU.

Синхронно, асинхронно і пакетно

Не кожному сценарію потрібна негайна відповідь. Перевірці на шахрайство під час авторизації платежу вона потрібна зараз. Обробка документів може прийняти завдання й віддати результати пізніше.

Пакетний інференс — третій патерн. Оцінка мільйонів клієнтів за ніч — це про пропускну здатність, а не про затримку одного запиту.

Кожен патерн має свої архітектурні особливості, тож починайте з бізнес-процесу, а не зі звички до REST. Спитайте, як скоро потрібне передбачення і де воно вбудовується в навколишній процес.

Версіонування — питання продакшну

Викотити модель — не те саме, що викотити реліз застосунку. Нова модель може зсунути передбачення й продуктивність, навіть якщо інфраструктура обслуговування не змінилася, тому важливе контрольоване розгортання.

Поширений підхід: спрямовувати невелику частку трафіку на нову версію, а решту залишати старій. Платформа стежить за технічними й бізнес-сигналами, поступово збільшує частку і може відкотитися, якщо новачок поводиться погано.

Спостережуваність

Класичний моніторинг каже, чи здорова інфраструктура. Обслуговуванню потрібен ширший погляд: затримка інференсу, пропускна здатність, збої, версії моделей, використання ресурсів і стан залежностей на кшталт сервісів ознак.

Система може виглядати технічно здоровою й усе одно видавати дивні результати, якщо модель отримує вхідні дані, несхожі на ті, на яких її будували. Тому спостережуваність має поєднувати інфраструктурні метрики з доречними сигналами рівня моделі, зважаючи на чутливість даних. Мета — впевненість, що працює потрібна модель і працює надійно в очікуваних межах, а не просто те, що ендпоінт відповідає.

Безпека та ізоляція

Ендпоінти обслуговування відкривають цінні бізнес-можливості й працюють із чутливими даними, тож безпека має бути в дизайні від початку. Автентифікація, авторизація, валідація запитів, обмеження частоти, мережеві межі й контроль доступу мають оточувати інференс, а не зʼявлятися після розгортання.

Ізоляція не менш важлива, коли моделі ділять інфраструктуру. Одне навантаження з великим обсягом не повинно залишати без обчислень чи памʼяті сторонні моделі, особливо коли йдеться про GPU. Якщо вважати обслуговування функцією платформи, ці заходи можна застосовувати однаково, а не змушувати кожну команду застосунку самотужки розвʼязувати ті самі проблеми.

Використання з Java

З Java-застосунку виклик моделі може здаватися оманливо простим. Фреймворк на кшталт Spring AI дає чисту програмну абстракцію, а розгортання, масштабування, маршрутизація й запуск моделей лишаються поза застосунком. У компанії такий поділ цінний: командам застосунків не варто володіти інфраструктурними рішеннями, потрібними для експлуатації кожної моделі.

Зі Spring AI застосунок використовує ChatClient для виклику ШІ-можливості, а саму модель надає інфраструктура обслуговування:

@Service
public class RiskAssessmentService {

    private final ChatClient chatClient;

    public RiskAssessmentService(ChatClient chatClient) {
        this.chatClient = chatClient;
    }

    public String assess(String transactionContext) {
        return chatClient.prompt()
                .system("""
                        You are a transaction risk assessment assistant.
                        Analyse the supplied transaction context.
                        """)
                .user(transactionContext)
                .call()
                .content();
    }
}

Код не знає, де саме модель: у локальному контейнері, кластері Kubernetes, на виділеному сервері інференсу чи на GPU. Це клопіт платформи. Застосунок споживає можливість через той інтерфейс, який йому дали.

Ідея стає кориснішою, коли моделі потрібен структурований контекст. Замість того щоб кожен застосунок сам отримував і збирав вхідні дані, перенесіть цю роботу в сервіс застосунку чи платформи:

public String assess(String customerId, Transaction transaction) {

    String context = featureService
            .getCustomerContext(customerId);

    return chatClient.prompt()
            .system("Assess the transaction using the customer context.")
            .user("""
                    Customer context:
                    %s

                    Transaction:
                    %s
                    """.formatted(context, transaction))
            .call()
            .content();
}

Java-застосунок оркеструє бізнес-взаємодію, сервіс ознак постачає актуальний контекст, а шар обслуговування відповідає за інференс. Що більше застосунків використовують ту саму модель, то ціннішим стає такий поділ.

LangChain4j пропонує схожу абстракцію на рівні застосунку. Корпоративний застосунок визначає інтерфейс, що представляє ШІ-можливість, і це тримає інфраструктуру конкретної моделі поза бізнес-кодом:

public interface RiskAssistant {

    @SystemMessage("""
        Assess the transaction risk using the supplied
        customer and transaction context.
        """)
    String assess(String context);
}

Потім застосунок використовує цю можливість через фреймворк, а ендпоінтом за нею керують незалежно:

String context = featureService
        .getCustomerContext(customerId);

String assessment = riskAssistant.assess(context);

Важлива межа проходить не між Spring AI і LangChain4j. Будь-який із них може бути шаром інтеграції. Важить поділ бізнес-коду, ШІ-оркестрації та інфраструктури обслуговування. Він дає платформі змінюватися самостійно: модель може переїхати в інше середовище виконання, потужності можуть зрости, може вийти нова версія, і ніщо з цього не вимагатиме переробляти Java-застосунки, які її використовують. У цьому й полягає справжня користь від того, щоб вважати обслуговування можливістю платформи, а не просто моделлю, схованою за HTTP-ендпоінтом.

Вибір архітектури

Немає одного дизайну на всі навантаження. Маленька модель у внутрішньому інструменті з низьким трафіком може чудово працювати всередині застосунку. Модель, яку ділять кілька бізнес-застосунків, може виправдати окремий шар обслуговування.

Контейнери дають однакове розгортання й масштабування, а Kubernetes — сильнішу оркестрацію для великих портфелів моделей. Спеціалізовані платформи інференсу мають сенс, коли потрібні GPU, дуже висока пропускна здатність, просунутий батчинг або тонкий контроль ресурсів.

Зважуйте характеристики моделі, профіль трафіку, вимоги до затримки, критичність для бізнесу, операційну зрілість і вартість. Найнавороченіша платформа не обовʼязково підходить. Прагніть мінімальної архітектури, яка надійно закриває потреби навантаження й лишає розумний шлях для зростання.

Ендпоінт — лише початок

Повернімося до ресторану: відвідувач бачить офіціанта, але це тонкий шар великої операції. Замовлення треба правильно прийняти, надіслати на потрібну станцію, приготувати з наявних ресурсів, узгодити з іншими столами й подати, не зупинивши кухню.

Обслуговування моделей працює так само. Ендпоінт робить модель доступною, а доступність — лише початок. Надійний інференс тримається на тому, що довкола: маршрутизації, отриманні контексту, версіях, обчисленнях, масштабуванні, обробці збоїв, спостережуваності, безпеці й операційному контролі.

Модель може лишатися в центрі можливості, але саме архітектура обслуговування вирішує, чи зможе ця можливість підтримувати реальні бізнес-рішення. Обслуговування — це не про те, щоб виставити модель назовні. Це про те, щоб побудувати систему, яка дасть моделі надійно підтримувати такі рішення.

Що ще почитати

Для Java-боку дивіться документацію LangChain4j і Spring AI. З боку платформи добрі відправні точки — документація Kubernetes, KServe і Triton Inference Server від NVIDIA.