Статический
Батчи фиксированного размера, которые ждут заполнения. Годится для офлайн-задач и плохо подходит для интерактивного трафика, потому что батча ждут все.
Приёмы системного уровня, определяющие, сколько запросов способен обслужить парк GPU и как быстро: батчинг, управление памятью KV-кэша, ускорение decode, разделение фаз, параллелизм и маршрутизация. Задержка, пропускная способность и стоимость тянут в разные стороны; какой угол победит, решает нагрузка.
Одиночный запрос оставляет большую часть GPU без дела; группировка запросов распределяет каждое чтение весов на множество токенов. Способ группировки имеет значение:
Батчи фиксированного размера, которые ждут заполнения. Годится для офлайн-задач и плохо подходит для интерактивного трафика, потому что батча ждут все.
Батч закрывается по временному окну или по пределу размера, что ограничивает ожидание. Лучше, но батч всё равно завершается в темпе самого медленного участника.
Планировщик работает с точностью до токена: завершённые последовательности уходят на ходу, ожидающие запросы подключаются сразу. Это массовый вариант по умолчанию (vLLM, SGLang, TensorRT-LLM) и самый крупный отдельный выигрыш в утилизации.
Chunked prefill развивает эту идею: длинные промпты режутся на части и чередуются с шагами decode, так что один огромный промпт больше не может застопорить поток токенов для всех остальных. Политика батчинга это политика задержек; измеряйте TTFT и задержку между токенами, а не только токены в секунду.
Наивное обслуживание резервирует непрерывную память KV на максимально возможную длину каждого запроса и теряет большую её часть на фрагментацию. PagedAttention заимствует идеи виртуальной памяти: кэш живёт в блоках фиксированного размера, выделяемых по мере надобности, а таблица блоков сопоставляет логические позиции каждой последовательности с физическими блоками. Потери сокращаются примерно до последнего неполного блока, одинаковые префиксы могут делить физические блоки, а высвобожденная память превращается в более крупные эффективные батчи. Подход появился в vLLM и теперь стандартен для движков обслуживания; это выигрыш в управлении памятью, а не более быстрое ядро.
Если два запроса начинаются с побайтово одинаковых префиксов токенов (тот же системный промпт, те же примеры, та же история диалога), работу prefill для этого префикса можно вычислить один раз и переиспользовать, сокращая TTFT и вычисления prefill при каждом попадании. Нужны точные совпадения токенов, поэтому дисциплина промпта важна: статическое содержимое в начале, изменчивые значения (метки времени, данные пользователя, идентификаторы запросов) как можно позже, сериализация детерминированная. Следите за долей попаданий; низкая обычно означает, что шаблон промпта пропускает изменчивость в своё начало.
Кэш растёт линейно с контекстом и параллельностью, и HBM на GPU заканчивается первой. Выгрузка сбрасывает более холодный кэш в оперативную память CPU, на локальный SSD или в удалённые хранилища и подтягивает его обратно по требованию, так что простаивающие сессии чата и длинные общие контексты перестают удерживать HBM (LMCache это заметный пример с открытым исходным кодом, интегрированный с vLLM). Приём оправдан для длинных контекстов и возобновляемых сессий; компромисс здесь между временем передачи и пересчётом, поэтому измерьте оба пути на своих уровнях хранения.
Decode ограничен памятью, поэтому на каждом шаге остаётся свободное вычислительное время. Дешёвая черновая модель предлагает несколько токенов; целевая модель проверяет их за один проход и принимает самую длинную верную цепочку. Принятые токены обходятся в малую долю стоимости; отклонённые черновики возвращают к обычному декодированию, а точные схемы проверки сохраняют распределение выходов целевой модели.
Prefill ограничен вычислениями и приходит всплесками; decode ограничен пропускной способностью и идёт ровно. Размещённые вместе, они мешают друг другу: длинный prefill стопорит поток токенов у всех. Разделение выносит фазы в отдельные пулы воркеров, которые масштабируются и настраиваются независимо, а воркер prefill передаёт KV-кэш воркеру decode по быстрой сети. Передача это плата за подход, поэтому он окупается на масштабе парка и вредит при малом масштабе или коротких промптах; среди фреймворков vLLM, SGLang и NVIDIA Dynamo.
Параллелизм по данным реплицирует модель и распределяет трафик. Тензорный параллелизм разрезает отдельные слои между GPU, чтобы поместились слишком крупные модели, ценой обмена данными на каждом шаге (ему нужны каналы класса NVLink). Конвейерный параллелизм назначает диапазоны слоёв стадиям и заполняет пузыри конвейера микробатчами. Экспертный параллелизм распределяет экспертов MoE по устройствам. Реальные развёртывания сочетают всё это, и верная комбинация подбирается опытным путём: тензорный параллелизм увеличивает нагрузку на каналы, а репликация сокращает запас памяти под KV на каждом GPU, поэтому измеряйте конфигурации, а не рассуждайте из общих принципов.
Когда реплик много, маршрутизатор сам становится полем для оптимизации. Round-robin игнорирует всё, что важно для LLM; лучшие сигналы это текущая нагрузка, запас памяти и прежде всего локальность кэша: маршрутизация с учётом префикса или с привязкой к сессии отправляет запрос туда, где его состояние KV уже находится (обычный приём это консистентное хеширование по префиксу промпта, его используют проекты вроде llm-d). Парки с разделением фаз маршрутизируют по фазе, а классы приоритета или SLA и локальность адаптеров могут входить в ту же оценку. Это не то же самое, что маршрутизация с выбором модели между уровнями моделей, о которой рассказано в разделе агентные паттерны.
Не всякая нагрузка интерактивна. Построение эмбеддингов для корпусов, дозаполнение классификаций, массовое реферирование и прогоны оценок допускают часы задержки, и это полностью меняет цель оптимизации: насытить оборудование, использовать свободные мощности или время вне пиков (провайдеры продают удешевлённые пакетные тарифы именно для этого) и добавить постобработку с проверками качества до того, как результаты пойдут в дело. Держать пакетную работу в стороне от интерактивного парка полезно ещё и потому, что это защищает ваши SLO по задержкам.