Глава 8 — KV-кэш следующего поколения
Восьмой пост поглавного разбора LLM Primer VI: Scaling AI Systems. Глава, переносящая понимание операционно-системного пагинга в движок инференса — и превращающая KV-кэш из слэба зарезервированных байтов в разделяемый, вытесняемый, префиксно кэшируемый ресурс.
Зачем эта глава существует
Глава 7 оставила continuous batching с долгом. Последовательности входят и выходят на каждой итерации; наивная разметка даёт каждому слоту собственный слэб максимального размера, большая часть которого пропадает; выигрыш батчинга частично отдаётся обратно. Долг — внутренняя фрагментация, ровно тот режим отказа, который операционные системы решили пагингом в 1960-х. Глава 8 — о применении этого решения к serving-у LLM: разделить KV-кэш на маленькие физические блоки, отвязать их от логических позиций токенов через таблицу страниц и дать политикам вытеснения и кэширования возвращать или делить блоки между последовательностями. PagedAttention — основополагающее движение; H2O и InfiniGen — политики вытеснения; префиксное кэширование — техника, позволяющая продакшен-кластеру обслуживать миллионы агентных запросов на дюжине GPU.
8.1 PagedAttention — виртуальная память для KV-кэша
Работа vLLM про PagedAttention (2023) прямо переносит OS-инсайт в движок. KV-кэш разбивается на блоки фиксированного размера — обычно по 16 токенов — в плоском физическом пуле. Последовательность представлена таблицей блоков: массивом указателей, отображающим логические позиции на физические ID блоков. Ядро внимания принимает таблицу блоков как дополнительный вход и собирает ключи и значения через непрямую адресацию, а не непрерывным срезом; на Hopper L2 достаточно хорошо поглощает случайный доступ, чтобы ядро работало в пределах нескольких процентов от слэб-версии. Выигрыш большой. Внутренняя фрагментация падает с 60–80 процентов примерно до 4 процентов (один частичный хвостовой блок на последовательность), что поднимает доступную параллельность в 2–4 раза. Ссылочно-считаемое разделение блоков делает сложное сэмплирование почти бесплатным — best-of-8 на промпте в 2 000 токенов падает с 16 800 до 2 800 токен-блоков — и это подложка, на которой строится префиксное кэширование.
8.2 H2O и InfiniGen вытесняют токены, которые не имеют значения
PagedAttention решает фрагментацию, но не решает контексты, перерастающие VRAM при любой разметке. Контекст на 200 000 токенов у Llama-3-70B требует 60 ГБ KV параллельно с весами. H2O («Heavy Hitter Oracle») наблюдает, что веса внимания во время декодинга концентрируются на маленьком множестве исходных позиций — недавние токены, attention-sink токены в самом начале и разреженное множество контентно-релевантных попаданий, — тогда как большинство исторических позиций получает практически нулевой вес. Движок отслеживает накопленный скор внимания на позицию; когда KV-бюджет последовательности подходит к пределу, он вытесняет самые низкоскоровые позиции, кроме гарантированно сохраняемого окна недавних и sink-токенов. Экономия велика; цена — необратимость: если поздний запрос потребует вытесненной позиции, движок не сможет её восстановить. InfiniGen уточняет обмен динамическим, восстановимым выбором: вместо полного отбрасывания токенов он выгружает их KV в память CPU и подкачивает обратно, если внимание снова начинает на них концентрироваться. Правильная политика вытеснения зависит от того, насколько нагрузка перезапрашивает собственную длинную историю; агентные нагрузки наказывают постоянное вытеснение и вознаграждают восстановление в стиле InfiniGen.
8.3 Префиксное кэширование — самый мощный рычаг, открытый PagedAttention
В реальном трафике первые тысячи токенов большинства промптов идентичны между запросами. Чат-сервис использует один и тот же системный промпт для каждого разговора. RAG-сервис вставляет один и тот же извлечённый контекст в промпт для каждого пользователя, искавшего то же. Агент вставляет одни и те же описания инструментов и рассуждательные скаффолды на каждом шаге. PagedAttention делает разделение механическим: хешировать промпт по чанкам размером с блок; если хеш есть в глобальном кэше уже вычисленных блоков, направить таблицу блоков нового запроса на закэшированный блок и полностью пропустить prefill этого префикса; если нет — запустить prefill, а результирующий блок зарегистрировать. Продакшен-хит-рейты драматичны — выше 99 процентов для системного промпта чат-сервиса, 30–60 процентов для префиксов, зависящих от RAG-извлечения, около 1,0 для агентного скаффолда. RadixAttention в SGLang идёт дальше с радикс-деревом, ключующим общие префиксы любой длины, а не только выровненные по блокам. Префиксное кэширование — единственный приём, который чаще всего превращает превышающий бюджет serving-кластер в укладывающийся в бюджет.
Что подготавливает глава 8
Пагинг, вытеснение и префиксное кэширование ужали KV-след на токен и сделали поведение памяти движка управляемым при высокой параллельности. Чего ни одно из них не адресует — так это фундаментальной последовательной зависимости декодинга: один выходной токен за итерацию на последовательность, сколько бы слотов ни было активно. Глава 9 берётся за это ограничение спекулятивным декодингом — семейством приёмов, предсказывающих несколько токенов вперёд дешёвым черновиком и верифицирующих догадку одним дорогим прямым проходом, ломая пол «один токен за шаг» для последовательностей, которые сильнее всего важны для воспринимаемой пользователем задержки.
Дальше — Глава 9: Спекулятивный декодинг. Черновик, верификация и арифметика того, когда спекуляция окупается.