Назад в блог

128k контекста на десктопе — ложь. Его съел KV-кэш.

22 сентября 2026 г.

Каждая карточка локальной модели теперь хвастается окном в 128k. На десктопе эта цифра — договор аренды, который ваша RAM подписывает не читая. Что решает, докуда вы дотянете длинный документ, — не веса. Это KV-кэш, и он масштабируется с контекстом как налог, согласованный в чужой валюте.

Окно контекста — не функция, которую включают. Это аренда памяти, которую вы платите каждую секунду работы сервера.

Сколько RAM на самом деле стоит контекст 128k?

Арифметика публичная и короткая. Как раскладывает Transformer Inference Arithmetic, KV-кэш хранит два тензора — ключи и значения — для каждого слоя, каждой KV-головы, каждого токена:

cache_bytes = 2 × слои × контекст × kv_головы × head_dim × байт_на_элемент

Возьмём Llama 3.1 8B: 32 слоя, 8 KV-голов, head_dim 128 — прямо из config.json на Hugging Face. При 131 072 токенах в fp16 (2 байта):

2 × 32 × 131072 × 8 × 128 × 2 = 17 179 869 184 байта ≈ 16 GiB

Веса той же модели в fp16 весят около 16 GiB. При максимальном контексте кэш так же велик, как модель, к которой он относится. «8B-модель, помещающаяся в 16 GiB» молча превращается в проблему на 32 GiB, как только вы поднимаете num_ctx до 128k.

Почему кэш растёт вместе с окном?

Потому что внимание обязано сравнить каждый токен со всеми предыдущими, а инференс авторегрессионен — ничего не пересчитывается, всё запоминается. В этом весь трюк, делающий генерацию быстрой: ключи и значения каждого токена вычисляются один раз и сохраняются. Память на токен постоянна, значит общий расход линеен по контексту. 128k — не «число побольше». Это 128× кэша окна в 1k, выделенного на всю сессию.

Grouped-query attention (GQA) — скидка на стороне модели: меньше KV-голов, стройнее кэш. Qwen2.5 7B использует 28 слоёв и всего 4 KV-головы (config здесь), поэтому то же окно 128k стоит около 7 GiB в fp16 — настоящее облегчение и одна из причин, почему эти модели дружелюбнее к скромным машинам.

Модель (fp16)Слои × KV-головыKV-кэш @ 128kВесаКэш к весам
Llama 3.1 8B32 × 8~16 GiB~16 GiB~100 %
Qwen2.5 7B28 × 4~7 GiB~15 GiB~47 %

Посчитайте сами — вся проверка умещается вот в этом:

def kv_cache_gib(layers, kv_heads, head_dim, ctx, bytes_per=2):
    return 2 * layers * ctx * kv_heads * head_dim * bytes_per / 2**30

print(kv_cache_gib(32, 8, 128, 131_072))  # Llama 3.1 8B  -> 16.0
print(kv_cache_gib(28, 4, 128, 131_072))  # Qwen2.5 7B    -> 7.0

О чём маркетинговая цифра умалчивает

Вот честная бухгалтерия этого аргумента — включая места, где он гнётся:

  • Prefill — второй счёт. Прежде первого токена ответа весь prompt обрабатывается разом. Prompt на 100k токенов — это 100k токенов пережевать до первого символа. На 3060 это минуты, а не миллисекунды.
  • Sliding-window модели ломают расчёт — в вашу пользу. Архитектуры типа Mistral ограничивают внимание фиксированным окном на слой, и кэш перестаёт расти. Простая формула их переоценивает. Этот текст — про трансформеры с полным вниманием, то есть большинство того, что люди запускают.
  • Квантование KV реально, но частично. llama.cpp умеет держать KV в q8_0 — кэш примерно вдвое меньше при некотором риске для качества. Половина от 16 GiB — всё ещё 8 GiB.
  • В спеках редко указывают KV-головы. Придётся копаться в config.json — что само по себе говорит, как эта цифра задумана для чтения.

Ничто из этого не делает длинный контекст бесполезным. RAG существует именно потому, что забивать окно — дорогой способ сказать «прочитай раздел 4». Но карточка, печатающая «128k» без счёта за память, продаёт машину по максимальной скорости и ни словом о бензобаке.

Никто не читает 128 000 токенов. Ваша RAM платит за них всё равно — за каждый.

Лекарство скучное: выставляйте контекст по тому, что ваша нагрузка реально использует. Окно 32k стоит четверть кэша 128k и покрывает почти любой prompt, который разработчик-одиночка действительно отправляет. Это та же дисциплина учёта, что в арифметике RAM для локальных LLM: размер модели — лишь половина бюджета, а уровни квантования ужимают веса, но расчёт кэша не трогают.

Если кэш — настоящая цена контекста, почему карточки продают окно и никогда — счёт? И раунд исповеди: какой самый большой контекст вы реально заполнили до последнего токена — и оправдал ли результат гигабайты? Комментарии открыты; следующая часть серии встанет на сторону проигравшего.

FAQ

Сколько RAM требует окно контекста 128k?

Для Llama 3.1 8B в fp16 один лишь KV-кэш весит около 16 GiB при 131 072 токенах — примерно столько же, сколько веса модели. Формула: 2 × слои × контекст × KV-головы × head_dim × байты.

Почему длинный контекст расходует больше памяти?

Каждый токен в кэше хранит тензоры ключей и значений для каждого слоя внимания. Удвоили контекст — удвоился кэш. Аллокация существует, даже если окно вы никогда не заполните.

Как уменьшить память KV-кэша в локальных LLM?

Выставите контекст по реальному использованию, берите модели с grouped-query attention (меньше KV-голов), квантуйте KV-кэш в q8 там, где поддерживает рантайм, или используйте sliding-window и гибридные архитектуры.

— mrsaynothing

— mrsaynothing

Мнения прогружены тестом до публикации. В основном.

Следующий аргумент — на почту

Одно письмо на пост. Согласиться или разобрать.

self-hosted · никаких третьих сторон · отписка в один клик

что это?

git stash: один файл, не трогая остальные

Нравятся заметки? Я зарабатываю этим на жизнь. нанять меня