KV cache проти prompt cache: різниця та помилки
KV cache займає RAM або VRAM вашого сервера й може спричинити помилку завантаження моделі. Prompt cache провайдера лише знижує ціну повторних запитів.
KV cache і prompt cache провайдера: коротка відповідь
KV cache і prompt cache провайдера мають спільне слово в назві, але майже нічого більше. KV cache — це робоча пам’ять окремого запиту. Вона зберігається в RAM або VRAM вашого сервера протягом усього життєвого циклу одного запиту та збільшується разом із довжиною контексту й кількістю одночасних запитів. Prompt caching у провайдера — це функція для оптимізації вартості та затримки. Стабільний префікс промпту зберігається на серверах провайдера, а під час повторного надсилання оплачується за зниженою ціною.
Перше — це пам’ять, яку ви купуєте як апаратний ресурс. Друге — пам’ять, яку зберігає інша сторона та здає вам в оренду.
Практична різниця важливіша за визначення. KV cache може заповнитися. У такому разі модель не завантажується або запит відхиляється. Prompt cache не може заповнитися з вашого боку. Ви можете лише не отримати cache hit, після чого непомітно сплатите повну вартість.
Що містить KV cache і навіщо він потрібен
Під час генерації токена номер 500 transformer має врахувати всі 499 попередніх токенів. Для кожного з них кожен шар потребує key vector і value vector. Повторне обчислення всіх цих векторів для кожного нового токена призвело б до квадратичного зростання часу генерації зі збільшенням довжини послідовності, тому runtime зберігає їх. Це сховище називається KV cache (key/value cache).
KV cache зберігає стан окремого запиту, оскільки формується на основі точної послідовності токенів цього запиту. Два користувачі з різними prompt не можуть спільно використовувати цей кеш, якщо runtime не підтримує prefix caching. Це окрема функція, описана далі.
Обслуговування запиту відбувається у двох фазах. Prefill читає весь prompt і заповнює кеш; його швидкість обмежена обчислювальною потужністю. Decode генерує по одному токену та додає його до кешу; його швидкість обмежена пропускною здатністю пам’яті. Саме тому під час вимірювання кількості токенів за секунду на власному сервері обробка prompt і генерація токенів мають різні показники швидкості.
Скільки пам’яті використовує KV cache?
Не шукайте таблицю від виробника. Розмір можна обчислити для будь-якої моделі:
bytes per token = 2 * layers * kv_heads * head_dim * bytes per elementЧисло 2 враховує key і value. Усі інші числа беруться з config.json моделі, опублікованої на її сторінці Hugging Face.
Візьмімо Llama 3.1 8B. У її конфігурації вказано num_hidden_layers 32 і num_key_value_heads 8. Значення hidden_size 4096, розподілене між 32 attention heads, дає розмір head 128. У f16 кожен елемент займає 2 байти:
2 * 32 * 8 * 128 * 2 = 131072 bytes = 128 KiB per tokenПомножте це значення на потрібний контекст, а потім — на кількість запитів, які ви обробляєте одночасно.
The data behind this chart
[
{
"label": "2k context",
"one_request_gib": 0.25,
"four_requests_gib": 1
},
{
"label": "8k context",
"one_request_gib": 1,
"four_requests_gib": 4
},
{
"label": "32k context",
"one_request_gib": 4,
"four_requests_gib": 16
},
{
"label": "128k context",
"one_request_gib": 16,
"four_requests_gib": 64
}
]Для контексту 8k cache становить 1 GiB на один запит. Для 32k він становить 4 GiB, тобто приблизно стільки само, як і самі 4-бітні ваги. За максимального для моделі контексту 128k cache становить 16 GiB для одного запиту та 64 GiB, якщо чотири запити повністю використовують цей контекст. Ваги не змінилися. Змінився лише cache.
Grouped query attention (GQA) істотно впливає на це значення. Llama 3.1 8B має 8 key/value heads, які обслуговують 32 query heads, тому чотири query heads спільно використовують одну збережену пару key/value. Модель, у якої num_key_value_heads дорівнює num_attention_heads, використовує вчетверо більше cache за тієї самої кількості параметрів. Перевірте це поле, перш ніж вважати, що дві моделі 8B мають однакову вартість обслуговування.
Чому модель, яка працювала на 2k, відмовляється завантажуватися на 32k
Runtime резервує KV cache під час завантаження моделі. Розмір кешу визначається налаштованою довжиною контексту, а не фактичною довжиною prompt, який ви надсилаєте. Стандартне context window в Ollama — 4096 tokens. Якщо збільшити його до 32k, до надходження першого токена потрібно виділити додаткові 4 GiB.
OLLAMA_CONTEXT_LENGTH=32768 ollama serveТе саме налаштування для окремої сесії можна вказати в інтерактивному prompt:
ollama run llama3.1:8b
/set parameter num_ctx 32768На різних stack помилка виглядає по-різному. vLLM перевіряє розрахунок під час запуску й відмовляється працювати:
ValueError: The model's max seq len (131072) is larger than the maximum number of tokens that can be stored in KV cache (78336). Try increasing `gpu_memory_utilization` or decreasing `max_model_len` when initializing the engine.На VPS лише з CPU такої перевірки немає, оскільки виділяється звичайна системна RAM. Натомість kernel OOM killer завершує процес і залишає запис у kernel ring buffer:
dmesg -T | grep -i "killed process"Рядок із назвою вашого serving process означає, що серверу було потрібно більше пам’яті, ніж він мав. Виправлення — зменшити context, а не збільшувати swap file: KV cache, paged до диска, зчитується під час генерації кожного токена, тому швидкість генерації падає до непридатного рівня. Як вибрати розумне значення, описано в нашому посібнику щодо num_ctx і довжини контексту в Ollama.
Вплив конкурентності на кількість
Кожен запит, що виконується, має власний KV-кеш. Саме це найчастіше не враховують у планах визначення місткості. Чотири користувачі, кожен із контекстом 32k, потребують загалом 16 GiB на додаток до ваг моделі.
Різні runtime по-різному керують цією пам’яттю. Ollama і llama.cpp резервують запитаний вами контекст під час завантаження моделі, тому пам’ять виділяється незалежно від того, чи використовується вона. vLLM розподіляє пул на блоки фіксованого розміру та виділяє їх у міру збільшення кожного запиту, тому запит на 500 токенів займає пам’ять лише для 500 токенів. У будь-якому разі пул має обмежений розмір. Коли він заповнюється, нові запити стають у чергу, а не виконуються одразу. Вплив цієї черги на час відповіді розглянуто в матеріалі про кількість одночасних користувачів, яких може обслуговувати self-hosted LLM.
Чотири способи зменшити KV-кеш
- Зменште довжину контексту. Це найдієвіший і зазвичай найдешевший спосіб. Більшість чат-запитів не наближається до 32k.
- Квантизуйте сам кеш. Значення
OLLAMA_KV_CACHE_TYPEв Ollama за замовчуванням —f16. Також підтримуютьсяq8_0, для якого потрібно приблизно вдвічі менше пам’яті, іq4_0, для якого потрібно приблизно в чотири рази менше. Еквіваленти в llama.cpp —-ctk q8_0і-ctv q8_0. - Виберіть модель із меншою кількістю голів key/value або меншою кількістю шарів. Ознайомтеся з
config.json, перш ніж завантажувати ваги обсягом 40 GB. - Обслуговуйте менше запитів одночасно, а решту ставте в чергу.
У q4_0 показник для Llama 3.1 8B зменшується зі 128 KiB на токен приблизно до 32 KiB. Тому контекст обсягом 32k потребує близько 1 GiB замість 4 GiB. Це зменшення витрат не є безкоштовним. Ключі та значення зберігаються з нижчою точністю, тому перевірте результати на власних запитах, перш ніж залишати це налаштування.
Що насправді дає кешування промптів на рівні провайдера
Кешування промптів на рівні провайдера — це окремий продукт із власною одиницею обліку. Ви позначаєте стабільний префікс, провайдер зберігає його, а наступні запити, які точно повторюють цей префікс, тарифікуються за зниженою ставкою, а не за повною ціною вхідних токенів.
Опубліковані Anthropic множники станом на August 2026: запис у кеш на 5 хвилин коштує 1.25 базової ціни вхідного токена. Запис на 1 годину коштує 2 рази дорожче, а читання з кешу — 0.1 базової ціни. Якщо застосувати ці значення до системного промпту на 20,000 токенів, перевага схеми стає очевидною.
The data behind this chart
[
{
"label": "No caching, every call",
"billed_token_equivalents": "20,000"
},
{
"label": "First call, 5 minute cache write",
"billed_token_equivalents": "25,000"
},
{
"label": "First call, 1 hour cache write",
"billed_token_equivalents": "40,000"
},
{
"label": "Every later call, cache hit",
"billed_token_equivalents": "2,000"
}
]Розглянемо це як арифметику. Підвищена ціна запису в кеш на 5 хвилин становить 5,000 еквівалентів токенів для першого запиту: 25,000 проти 20,000 за надсилання без кешування. Кожен наступний запит у межах цього вікна тарифікується як 2,000, а не як 20,000, тобто економія становить 18,000. Отже, кеш на 5 хвилин стає вигідним уже з другого запиту.
Кеш на 1 годину — це інший розрахунок. За запис тарифікується 40,000, тобто премія становить 20,000 еквівалентів токенів. Тому він стає вигідним після двох звернень протягом години. Це залежить від характеру вашого трафіку, а не від моделі. Повний розрахунок, зокрема вибір тривалості вікна, наведено в матеріалі розрахунок точки беззбитковості для кешування промптів Claude.
Чи спрацює кеш, визначають дві деталі. По-перше, префікс, коротший за мінімальну довжину моделі, тихо не кешується: станом на August 2026 задокументований мінімум становить 512 токенів для Claude Opus 5 і 1,024 токени для Claude Sonnet 5. Коротший запит обробляється у звичайному режимі, без повернення помилки. По-друге, час життя вимірюється від початку запиту, який записує або читає запис, а кожне читання поновлює його без додаткової плати. Тому активний endpoint може підтримувати кеш на 5 хвилин необмежено довго. Endpoint, який викликається раз на десять хвилин, щоразу сплачує премію за запис і не отримує жодної вигоди.
Перевіряйте відповідь, а не покладайтеся на припущення. Об’єкт usage містить cache_creation_input_tokens і cache_read_input_tokens. Якщо кількість читань дорівнює нулю в кожному запиті, ви оплачуєте записи, але не отримуєте результату.
Де стикаються два кеші
Довгий системний промпт — це місце, де вони стикаються, і він одночасно збільшує витрати з обох боків.
Локально системний промпт на 20,000 токенів займає приблизно 2.4 GiB KV-кешу на сервері з Llama 3.1 8B за f16. Він займає цей обсяг окремо для кожного одночасного запиту, який його містить. На віддаленому сервісі той самий префікс потребує одного запису в кеш, а під час кожного наступного виклику тарифікується як 0.1 від вартості вхідних даних. Локальна вартість зростає разом із кількістю користувачів. Віддалена вартість зростає разом із трафіком і скидається під час простою.
Є локальна функція, схожа на кешування промптів провайдером, і її постійно з ним плутають: кешування префіксів. Документація vLLM описує автоматичне кешування префіксів як кешування "KV-кешу наявних запитів, щоб новий запит міг безпосередньо повторно використати KV-кеш, якщо має спільний префікс з одним із наявних запитів". Сервер llama.cpp за замовчуванням зберігає кеш промпта для кожного слота, а --cache-reuse N визначає найменший фрагмент, який він намагатиметься повторно використати.
Кешування префіксів заощаджує обчислення під час prefill. Системний промпт на 20,000 токенів обробляється один раз, а не під час кожного запиту, тому час до отримання першого токена істотно скорочується. У vLLM спільні блоки повторно використовуються, а не дублюються, тому використання пам’яті також покращується. Але це не зменшує обсяг кешу, який потрібно утримувати для токенів, що наразі активні. Збереження ваг у пам’яті між запитами — пов’язаний, але окремий механізм. Його описано в розділі як залишити модель Ollama завантаженою між запитами.
Що вимірювати на власному сервері
Завантажте модель із цільовим розміром контексту, а потім перевірте фактичні значення замість того, щоб покладатися на оцінку.
ollama ps
nvidia-smi --query-gpu=memory.used,memory.total --format=csv
free -gollama ps показує завантажену модель, її розмір і те, чи працює вона на GPU або CPU. Якщо модель, яка, як ви очікували, мала повністю розміщуватися на GPU, частково працює на CPU, це означає, що KV-кеш витіснив частину моделі. Через це швидкість генерації знизиться. nvidia-smi показує фактичний обсяг використаної VRAM, а free -g виконує ту саму функцію на VPS лише з CPU. Збільшуйте контекст поетапно, щоразу перезавантажуйте модель і стежте, як змінюється значення. Результат ваших розрахунків і показане значення мають бути близькими. Якщо це не так, різниця зазвичай пояснюється власними буферами обчислень runtime, а не помилкою у формулі.
Якщо ці значення змушують вас орендувати обладнання, від якого ви хотіли б відмовитися, порівняння з оплатою за токени наведено в розділі GPU VPS проти API-токенів.
FAQ
Чи є KV-кеш тим самим, що й кешування промптів?
Ні. KV-кеш — це пам’ять для окремого запиту всередині процесу обслуговування. Він зберігає вектори key і value для кожного токена в поточному контексті. Він розміщується в RAM або VRAM і звільняється після завершення запиту. Кешування промптів провайдером — це функція білінгу. Вона зберігає стабільний префікс промпту в інфраструктурі провайдера та застосовує нижчу тарифікацію, коли ви надсилаєте його повторно. Вичерпання KV-кешу не дає моделі завантажитися. Відсутність кешу промпту лише збільшує рахунок і час до отримання першого токена.
Чому моя модель завантажується з контекстом 2k, але не запускається з 32k?
Тому що runtime виділяє весь KV-кеш під час завантаження. Його розмір визначається налаштованою довжиною контексту, а не промптом, який ви надсилаєте. Для Llama 3.1 8B у f16 кеш займає 128 KiB на токен, тому контекст 2k потребує 0.25 GiB, а 32k — 4 GiB. Ваги моделі вміщуються в обох випадках. Помилка виникає під час резервування пам’яті. vLLM повідомляє про це через ValueError, де вказано максимальну кількість токенів, яку вдалося зберегти, і пропонує збільшити gpu_memory_utilization або зменшити max_model_len. На сервері лише з CPU процес натомість завершує kernel out-of-memory killer. Це можна підтвердити за допомогою dmesg -T | grep -i "killed process".
Як розрахувати розмір KV-кешу для моєї моделі?
Помножте 2 на кількість шарів, кількість key/value heads, розмірність голови та кількість байтів на елемент. Ви отримаєте кількість байтів на токен. Потім помножте це значення на довжину контексту та кількість одночасних запитів. Кількість шарів і голів зчитуйте з config.json моделі. Для одного елемента використовуйте 2 байти у f16 або bf16. Кеш q8_0 має приблизно вдвічі менший розмір, а q4_0 — приблизно вчетверо менший.
Чи зменшує кешування промптів обсяг пам’яті, потрібний моєму серверу?
Кешування промптів провайдером не впливає на ваше обладнання, оскільки сховище розташоване на боці провайдера. Локальний аналог — prefix caching, який підтримують і vLLM, і сервер llama.cpp. Він повторно використовує вже обчислені key і value vectors для спільного префікса. Це зменшує обчислення під час prefill і скорочує час до отримання першого токена. У vLLM спільні блоки повторно використовуються, а не дублюються, тому також зменшується споживання пам’яті. Жодна з цих функцій не зменшує кеш, потрібний для токенів, які зараз обробляються. Тому мінімальний обсяг пам’яті й надалі визначається розрахунком контексту та кількості одночасних запитів.
Чи варто кешувати промпт, який я надсилаю лише один раз?
Ні. Запис у кеш коштує дорожче, ніж звичайне введення: станом на August 2026 для варіанта на 5 хвилин тариф становить 1.25 базового тарифу. Тому префікс, який ви більше не надсилаєте протягом цього періоду, призводить лише до зайвих витрат. Кешування вигідне, коли той самий префікс повторюється. Наприклад, це може бути довгий системний промпт або документ, щодо якого ви поставите кілька запитань. Перевірте cache_read_input_tokens у відповіді API, щоб переконатися, що кеш використовується, а не оплачуються операції запису.