AI-модель в production: архитектура инференс-сервисов
Когда вы отправляете запрос в ChatGPT, задаете вопрос корпоративному ассистенту или загружаете документ для анализа через AI-платформу, за кулисами работает инференс-сервис. Он обрабатывает ваш текстовый запрос через языковую модель и возвращает сгенерированный ответ. Этот процесс обычно кажется мгновенным, но требует решения нескольких критических инженерных задач.
Совсем недавно запуск использования AI-модели в production был задачей для энтузиастов. Сейчас это уже становится стандартной частью корпоративной архитектуры. Но инструменты и подходы не всегда успевают за скоростью внедрения - есть немало команд, которые все еще пытаются строить mission-critical AI-сервисы по принципу “а вдруг заработает”.
За простой схемой “запрос → ответ” скрывается сложная инфраструктура: управление памятью GPU, оптимизация вычислений, batching запросов и load balancing между репликами. Инференс-сервис изолирует эту сложность от клиентских приложений, предоставляя стабильный интерфейс для взаимодействия с моделями.
Диаграмма ниже показывает общую схему взаимодействия с инференс-сервисом на высоком уровне:
flowchart LR
Client[💻 Client] --> API[📡 Inference Service API]
API --> Engine[⚙️ Inference Engine]
Engine --> Model[🧠 LLM Model]
Model --> Engine
Engine --> API
API --> Client
subgraph "Inference Service"
API
Engine
Model
endflowchart LR
Client[💻 Client] --> API[📡 Inference Service API]
API --> Engine[⚙️ Inference Engine]
Engine --> Model[🧠 LLM Model]
Model --> Engine
Engine --> API
API --> Client
subgraph "Inference Service"
API
Engine
Model
endАрхитектура инференс-сервисов
Концептуально инференс-сервис может быть построен по слоистой архитектуре, где каждый слой отвечает за конкретные функции. Это разделение позволяет независимо масштабировать компоненты и упрощает сопровождение системы.
API Layer принимает запросы от клиентов, проверяет их корректность, выполняет security операции и преобразует входные данные во внутренний формат сервиса.
Service Layer управляет бизнес-логикой обработки запросов: планирование выполнения, управление очередями, интеграция с RAG-сервисами, мониторинг состояния системы.
Inference Engine выполняет фактические вычисления инференса на доступных ресурсах: CPU, GPU или специализированных ускорителях.
flowchart TB
subgraph "API Layer"
REST[REST API]
GRPC[gRPC API]
Auth[Authentication]
Valid[Validation]
end
subgraph "Service Layer"
Queue[Request Queue]
Scheduler[Scheduler]
Monitor[Health Monitor]
end
subgraph "Inference Engine"
Engine[Inference Engine]
GPU[GPU Resources]
Memory[Memory Manager]
end
REST --> Queue
GRPC --> Queue
Auth --> Queue
Valid --> Queue
Queue --> Scheduler
Scheduler --> Engine
Monitor --> Engine
Engine --> GPU
Engine --> Memoryflowchart TB
subgraph "API Layer"
REST[REST API]
GRPC[gRPC API]
Auth[Authentication]
Valid[Validation]
end
subgraph "Service Layer"
Queue[Request Queue]
Scheduler[Scheduler]
Monitor[Health Monitor]
end
subgraph "Inference Engine"
Engine[Inference Engine]
GPU[GPU Resources]
Memory[Memory Manager]
end
REST --> Queue
GRPC --> Queue
Auth --> Queue
Valid --> Queue
Queue --> Scheduler
Scheduler --> Engine
Monitor --> Engine
Engine --> GPU
Engine --> MemoryТакая архитектура изолирует клиентские приложения от сложности вычислений и обеспечивает гибкость замены компонентов. Клиент взаимодействует только с API Layer через стандартные протоколы, не заботясь о том, где и как выполняется инференс модели.
В микросервисной архитектуре API Layer и Service Layer обычно реализуются в едином Spring Boot приложении. Это приложение взаимодействует с Inference Engine через программные интерфейсы (если engine встроен как библиотека) или через wrapper-сервисы, которые предоставляют HTTP/gRPC API для доступа к engine. При завершении обработки Service Layer может публиковать события в Kafka, что позволяет другим сервисам асинхронно реагировать на результаты инференса. Аналогичную архитектуру можно построить на других backend-технологиях, сохранив принцип разделения слоев.
Inference Engine: механика работы
Inference Engine - это ядро инференс-сервиса, которое управляет всем процессом выполнения модели. Он получает подготовленные запросы от Service Layer и координирует их обработку на доступных вычислительных ресурсах. Понимание его внутренней механики критично для оценки производительности и планирования ресурсов. Примеры: llama.cpp (CPU/GPU оптимизация), ONNX Runtime (кросс-платформенность), TensorRT (NVIDIA оптимизация), PyTorch/transformers (гибкость разработки).
Функции Inference Engine
Базовые функции:
Request Processing - принятие запросов от Service Layer, валидация параметров генерации и подготовка данных к обработке.
Model Management - загрузка весов модели в память, инициализация архитектуры и управление состоянием модели.
Pipeline Coordination - управление последовательностью этапов обработки от токенизации до декодирования результата.
Оптимизационные функции:
Batching - группировка нескольких запросов для параллельной обработки, что значительно повышает throughput при работе с GPU.
Memory Management - управление загрузкой модели в память, KV-cache для ускорения генерации, освобождение ресурсов.
Quantization - использование моделей с пониженной точностью (FP16, INT8) для экономии памяти и ускорения вычислений.
Hardware Optimization - адаптация вычислений под конкретные ускорители: CUDA для NVIDIA GPU, ROCm для AMD, специализированные библиотеки для TPU.
Pipeline обработки запроса
Input Preprocessing:
Tokenization разбивает входной текст на токены согласно словарю модели. Например, фраза “Hello world” может стать токенами [15496, 1917]. Этот процесс учитывает специальные символы, подслова (subword tokenization) и маркеры начала/конца последовательности.
Embedding Lookup преобразует каждый token ID в соответствующий вектор из embedding-матрицы модели. Размерность этих векторов обычно составляет 768-4096 элементов в зависимости от архитектуры модели.
Model Inference:
Forward Pass последовательно пропускает векторы через все слои transformer-архитектуры. На каждом слое выполняется self-attention (токены анализируют друг друга) и feed-forward обработка. Результатом становятся hidden states - представления токенов с учетом контекста.
KV-Cache сохраняет key и value тензоры из attention-механизма для уже обработанных токенов. При генерации следующего токена эти данные переиспользуются, избегая повторного пересчета всей последовательности.
Output Generation:
Logits Generation преобразует последний hidden state через выходной слой модели в логиты - необработанные вероятности для каждого токена из словаря.
Token Sampling выбирает следующий токен из распределения вероятностей. Стратегии включают greedy (самый вероятный), top-k (из k наиболее вероятных), nucleus sampling (суммарная вероятность p).
Stop Condition Check проверяет, достигнуто ли условие завершения генерации: специальный EOS токен (end of sequence) или максимальная длина последовательности. Если условие не выполнено, сгенерированный токен добавляется к входной последовательности, и процесс возвращается к Model Inference для генерации следующего токена.
Decoding конвертирует всю последовательность сгенерированных token ID обратно в текст и возвращает финальный результат.
Этот pipeline работает итеративно: каждый новый токен становится частью входной последовательности для следующей итерации. KV-cache критичен для производительности, так как избегает пересчета attention для уже обработанных токенов на каждой итерации.
flowchart TD
Request[Request from Service Layer] --> Pipeline
subgraph Pipeline["Inference Pipeline"]
subgraph "Input Preprocessing"
Tokenizer[Tokenization
Text → Token IDs]
Embedding[Embedding Lookup
IDs → Vectors]
end
subgraph "Model Inference"
Forward[Forward Pass
Transformers Layers]
KVCache[KV-Cache
Attention States]
end
subgraph "Output Generation"
Logits[Logits Generation
Hidden States → Logits]
Sampling[Token Sampling
Strategy Selection]
StopCheck{Stop Condition?
EOS token / Max length}
Decode[Decoding
Tokens → Text]
end
end
subgraph "Resources"
ModelWeights[Model Weights
GPU Memory]
GPU[GPU Cores
Parallel Execution]
end
Tokenizer --> Embedding
Embedding --> Forward
Forward --> KVCache
Forward --> Logits
Logits --> Sampling
Sampling --> StopCheck
StopCheck -->|Yes| Decode
StopCheck -->|No| Forward
Decode --> Response[Response to Service Layer]
Forward -.-> ModelWeights
Forward -.-> GPU
KVCache -.-> GPUflowchart TD
Request[Request from Service Layer] --> Pipeline
subgraph Pipeline["Inference Pipeline"]
subgraph "Input Preprocessing"
Tokenizer[TokenizationText → Token IDs] Embedding[Embedding Lookup
IDs → Vectors] end subgraph "Model Inference" Forward[Forward Pass
Transformers Layers] KVCache[KV-Cache
Attention States] end subgraph "Output Generation" Logits[Logits Generation
Hidden States → Logits] Sampling[Token Sampling
Strategy Selection] StopCheck{Stop Condition?
EOS token / Max length} Decode[Decoding
Tokens → Text] end end subgraph "Resources" ModelWeights[Model Weights
GPU Memory] GPU[GPU Cores
Parallel Execution] end Tokenizer --> Embedding Embedding --> Forward Forward --> KVCache Forward --> Logits Logits --> Sampling Sampling --> StopCheck StopCheck -->|Yes| Decode StopCheck -->|No| Forward Decode --> Response[Response to Service Layer] Forward -.-> ModelWeights Forward -.-> GPU KVCache -.-> GPU
Компоненты инференс-стека
На практике концептуальные слои реализуются через стек специализированных компонентов. LLM становятся частью прикладных систем: чат-боты, аналитика, генерация контента. Для их интеграции важно понимать стек инференса - архитектурные слои от низкоуровневых вычислений до API для приложений. Каждый слой решает специфические задачи и может быть заменен независимо от других компонентов.
flowchart LR
A[Model] --> B[Engine]
B --> C[Runtime]
C --> D[Wrapper]
D --> E[Service]
E --> F[Applications]flowchart LR
A[Model] --> B[Engine]
B --> C[Runtime]
C --> D[Wrapper]
D --> E[Service]
E --> F[Applications]Архитектурные слои
Runtime выполняет низкоуровневые вычисления на конкретном железе. CUDA обеспечивает параллельные вычисления на NVIDIA GPU, cuBLAS оптимизирует операции линейной алгебры, Metal используется для ускорения на Apple Silicon. Этот слой скрыт от разработчика и управляется автоматически.
Inference Engine исполняет модель, координируя вычисления через runtime. llama.cpp оптимизирован для CPU и локальных развертываний, ONNX Runtime поддерживает кросс-платформенные сценарии, TensorRT максимизирует производительность на NVIDIA GPU через специализированные оптимизации.
Inference Wrapper (оболочка) управляет жизненным циклом моделей, сессиями и контекстами. Этот слой выполняет критически важную функцию: предоставляет сетевое API для доступа к inference engine. Большинство современных движков (llama.cpp, transformers, TensorRT) предоставляют только программные API на C++/Python и не имеют встроенных HTTP серверов. Примеры: Ollama для локальных экспериментов, vLLM server для high-performance сценариев.
Inference Service предоставляет production-ready API для клиентов, обеспечивая безопасность, мониторинг и масштабирование. В большинстве случаев интегрируется с inference engine через wrapper слой, который обеспечивает сетевое взаимодействие. Прямая интеграция с движком также возможна, но потребует дополнительной разработки для работы с программными API и создания собственной HTTP обертки.
flowchart TB
subgraph R1 [Runtime Layer]
A1[GPU/CPU Computations]
end
subgraph R2 [Inference Engine]
B1[llama.cpp, ONNX Runtime, TensorRT]
end
subgraph R3 [Inference Wrapper]
C1[Model & Session Management
HTTP/gRPC Server
Critical for Integration]
end
subgraph R4 [Inference Service]
D1[API, Security, Monitoring]
end
A1 --> B1
B1 --> C1
C1 --> D1
B1 -.-> D1
style C1 stroke-dasharray: noneflowchart TB
subgraph R1 [Runtime Layer]
A1[GPU/CPU Computations]
end
subgraph R2 [Inference Engine]
B1[llama.cpp, ONNX Runtime, TensorRT]
end
subgraph R3 [Inference Wrapper]
C1[Model & Session ManagementHTTP/gRPC Server
Critical for Integration] end subgraph R4 [Inference Service] D1[API, Security, Monitoring] end A1 --> B1 B1 --> C1 C1 --> D1 B1 -.-> D1 style C1 stroke-dasharray: none
Wrapper vs Service
Инференс-оболочка и инференс-сервис решают разные задачи в архитектуре системы.
Оболочка (Ollama, vLLM) выполняет две ключевые функции: упрощает работу с движком через управление моделями, сессиями и контекстами, а также предоставляет сетевое API для доступа к inference engine. Большинство движков не имеют встроенных HTTP серверов, поэтому оболочка становится необходимым компонентом для интеграции с backend-приложениями.
Сервис предоставляет production-ready API для клиентов, включая метрики, безопасность, масштабирование и интеграцию с корпоративной инфраструктурой. Обязательный компонент для прикладного использования, обеспечивающий надежность и управляемость.
В микросервисной архитектуре inference service становится одним из компонентов, взаимодействующим с другими сервисами через стандартные протоколы и паттерны.
Архитектурные рекомендации
Общий подход
Для прикладного использования LLM оптимально использовать готовые движки для инференса, готовые оболочки для управления моделями и строить специализированный сервис для интеграции с приложениями.
Такой подход минимизирует поддержку нативного кода, ускоряет интеграцию и позволяет эффективно масштабировать LLM в реальных системах. Разделение ответственности между слоями упрощает замену компонентов и адаптацию под изменяющиеся требования.
Выбор архитектуры под задачи
Прототипирование и эксперименты:
- Архитектура: монолитная, Ollama + простой REST wrapper
- Стек: Python FastAPI + Ollama
- Обоснование: скорость разработки важнее производительности, минимальные операционные требования
Корпоративные приложения:
- Архитектура: микросервисная, выделенный inference service
- Стек: Spring Boot + vLLM + Redis для кэширования
- Требования: аутентификация, аудит, интеграция с корпоративной инфраструктурой, надежность
High-load продукты:
- Архитектура: распределенная с автомасштабированием
- Стек: Kubernetes + TensorRT + асинхронные очереди
- Критично: cost per request, SLA, горизонтальное масштабирование, мониторинг производительности
Быстрый MVP или ограниченные ресурсы:
- Архитектура: прокси к внешним API (OpenAI, Anthropic, Google)
- Стек: Spring Boot + HTTP клиенты + кэширование ответов
- Обоснование: нет затрат на GPU инфраструктуру, быстрый старт
- Ограничения: зависимость от внешнего провайдера, стоимость per-request, данные покидают инфраструктуру
Выбор архитектурного подхода должен соответствовать текущим требованиям проекта с возможностью эволюции к более сложным решениям по мере роста нагрузки и функциональных потребностей.
Правильно спроектированная слоистая архитектура позволяет относительно безболезненно мигрировать между подходами: начать с внешних API для быстрого MVP, затем перейти на собственную инфраструктуру при росте объемов, или наоборот - переключиться на внешние сервисы при необходимости снизить операционную нагрузку. Ключ в том, чтобы изолировать логику взаимодействия с inference-слоем за стабильными интерфейсами.