Архитектура обслуживания моделей: почему API — это только парадная дверь
Разбираем платформу за эндпоинтом инференса: маршрутизацию, масштабирование, версионирование, наблюдаемость, безопасность и вызов моделей из Spring AI или LangChain4j.
Подумайте, что видит посетитель ресторана: кто-то принимает заказ, исчезает в сторону кухни и возвращается с тарелкой. Невидимая часть важнее. Заказы надо согласовать, запасы проверить, повара готовят блюда, одновременно обслуживается много столов, и каждая тарелка должна попасть к нужному человеку.
Обслуживание модели машинного обучения устроено так же. Снаружи приложение видит 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.