# vLLM prefix caching: повторный контекст и изоляция кеша

Источник: https://modelium.tech/zhurnal/vllm-prefix-caching/

Prefix caching в vLLM повторно использует KV-блоки общего начала запросов и сокращает повторный prefill, но не ускоряет генерацию новых токенов. Проверьте реальный режим кеша в своей версии, затем сравните одинаковый длинный префикс с одним и разными `cache_salt`. Для нескольких клиентов salt нужен для ограничения совместного использования кеша; он не заменяет сетевую изоляцию и авторизацию.

**Проверено по исходникам vLLM на Git-ревизии **`**6f75cc7**`** 4 октября 2026 года.** Это инструкция для собственного стенда, а не результат теста Modelium. Версии, модели и интерфейсы позже этой ревизии сверяйте заново [s1](#src-s1)[s8](#src-s8).

## Когда повторное использование префикса действительно поможет?

У задачи может быть длинный общий вход: системные инструкции и один документ, после которого каждый сотрудник задаёт свой вопрос. В vLLM Automatic Prefix Caching (APC) хранит уже рассчитанные KV-блоки и даёт следующему запросу с **той же последовательностью начальных токенов** использовать их повторно. Это путь «документ и вопросы → совместимая модель → ваш CPU/GPU и запас памяти → vLLM → проверенное совпадение и ответ», а не отдельная модель. Начните с [проверенного пути запуска сервера](/zhurnal/vllm/) и не делайте вывода о применимости по одному заголовку документа [s1](#src-s1)[s2](#src-s2).

Кешируются только полные блоки; изменение шаблона чата, токенизации, порядка сообщений или первых токенов может уничтожить ожидаемое совпадение. Ключ блока включает хеш предыдущего блока, его токены и дополнительные компоненты вроде LoRA ID, хеша мультимодального входа и salt. Блоки при нехватке места вытесняются; второй запрос через час может не найти прежние KV-данные. Кеш не экономит фазу генерации ответа (decode) и потому не обещает выигрыш при коротком входе, разных префиксах или длинных ответах [s1](#src-s1)[s2](#src-s2).

Для пилота используйте **синтетический** длинный общий документ, который достаточно велик, чтобы занять несколько KV-блоков выбранной модели, и два различных вопроса после одинакового начала. Не отправляйте клиентские договоры или персональные данные в диагностический пример. Совпадение начала проверяйте на входных сообщениях и их сериализации выбранной моделью, а не по визуально похожим строкам. Документация допускает и многотуровый чат с повторяющейся историей, но иной chat template может изменить токены [s1](#src-s1)[s2](#src-s2).

## Как понять, включён ли prefix caching в вашей сборке?

Не копируйте тезис «по умолчанию всегда включено» между версиями. В закреплённой реализации CLI `--enable-prefix-caching` сначала имеет неопределённое значение, а затем получает default по тому, поддерживает ли выбранная модель prefix caching; конфигурация и логи запуска должны подтвердить итог. В офлайн-примере документации vLLM APC явно включают через `enable_prefix_caching=True`. Для совместимой модели на установленном сервере задайте флаг `--enable-prefix-caching` явно и убедитесь, что vLLM принял его без предупреждений; не форсируйте неподдерживаемую модель вопреки предупреждению [s8](#src-s8)[s1](#src-s1).

Пример **шаблона**, а не команды, исполненной редакцией: `vllm serve <совместимый-репозиторий> --host 127.0.0.1 --port 8000 --enable-prefix-caching`. Угловые скобки надо заменить проверенным model ID и заранее выбрать подходящую среду/железо по [основному гайду vLLM](/zhurnal/vllm/). Сам факт HTTP 200 у сервера ещё не подтверждает кеш-хит: проверьте успешный ответ модели по `/v1/chat/completions`, затем снимите показания `/metrics` до и после серии [s6](#src-s6)[s5](#src-s5)[s8](#src-s8).

## Как разделить кеш между пользователями через cache_salt?

В общем сервере запрос без salt допускает повторное использование префикса между клиентами. Разница во времени до первого токена может выдать факт существования угаданного чужого начала; разработчики vLLM описывают этот риск и вводят необязательный `cache_salt` в запросе. Соль участвует в хеше **первого** KV-блока, поэтому цепочки блоков с разными значениями не дают друг другу повторно использовать префикс. Это именно ограничение reuse и timing-побочного канала, не разделение прав на документы, не шифрование и не аудит доступа [s3](#src-s3)[s2](#src-s2).

Отправляйте `cache_salt` как отдельное поле JSON того же запроса `/v1/chat/completions`, рядом с `model` и `messages`, либо как `extra_body` у совместимого клиента. Закреплённая схема ChatCompletionRequest принимает непустую строку длиной до 1024 символов. Для продакшена создайте **случайное, непредсказуемое и защищённое** значение на пользователя или разрешённую группу и постоянно применяйте его в запросах этой области доверия. Имя пользователя, номер организации и общий демонстрационный литерал не секреты. Не пишите production salt в логи и примеры документации [s3](#src-s3)[s7](#src-s7).

Разные секретные значения для двух арендаторов исключают межарендное повторное использование блока; внутри одного арендатора одинаковая соль позволяет повторно использовать его собственный префикс. Запрос без соли остаётся отдельным решением владельца одноарендного сервера: не принимайте его автоматически для общего контура. Если одна часть клиентов вовсе не передаёт `cache_salt`, не выдавайте вашу систему за изолированную только потому, что остальные его используют [s3](#src-s3)[s2](#src-s2).

## Как проверить попадание, промах и отсутствие межклиентского reuse?

Сначала добейтесь обычного ответа от выбранной модели на синтетическом запросе. Затем на **одном незагруженном сервере** сохраните исходные показания `/metrics` и проведите три серии при одинаковой модели, chat template, длинном общем начале и лимите ответа. **А:** первый вопрос с тестовой солью арендатора А; **Б:** то же длинное начало и другая концовка с *той же* солью; **В:** то же начало и ещё один вопрос с *другой* солью арендатора Б. Сами тестовые соли не используйте позже как боевые; запишите порядок серий и конфигурацию. Успех каждой серии — корректный ответ конкретной модели, а не просто пустой HTTP 200 [s2](#src-s2)[s3](#src-s3)[s6](#src-s6).

На `/metrics` ищите `vllm:prefix_cache_queries`, `vllm:prefix_cache_hits` и показатели времени первого токена. Реализация подписывает первые два счётчика в **токенах**, а не в запросах; рост попаданий во второй серии при прочих равных поддерживает гипотезу reuse. Доля попаданий за конкретный интервал вычисляется как `(hits_после − hits_до) / (queries_после − queries_до)` при положительном знаменателе, а не как отношение общих накопленных показаний. Для отдельных моделей/движков считайте серии отдельно. Это аналитический расчёт, не наблюдавшееся Modelium число [s4](#src-s4)[s5](#src-s5).

Для серии В отсутствие нового совпадения возможно проверить только на чистом тестовом стенде при контролируемом единственном трафике: агрегированные счётчики сервера не доказывают изоляцию конкретного пользователя. Измеряйте TTFT по повторным пробам и сравнивайте с контрольной серией без тёплого префикса, фиксируя шум, очередь, вытеснение KV-блоков и длину выхода. Не делайте причинный вывод по одному времени ответа: в [гайде vLLM bench serve](/zhurnal/vllm-bench-serve/) есть отдельный путь для сопоставимого нагрузочного теста, а [гайд по Prometheus](/zhurnal/vllm-metrics-prometheus/) — для остальных метрик и интервалов [s1](#src-s1)[s2](#src-s2)[s4](#src-s4)[s5](#src-s5).

## Что делать, если ускорения нет или ответ неожиданен?

- **Попаданий нет:** проверьте итоговый режим APC и поддержку модели; далее сравните именно начальные токены, salt, LoRA/мультимодальный контекст и полные блоки. После вытеснения прежних блоков повторная обработка нормальна [s8](#src-s8)[s2](#src-s2).

- **TTFT почти не изменился:** для короткого общего начала, конкурирующей очереди или нагрузки с длинным decode экономия prefill может не проявиться в полной задержке; одинаковая длина промпта на глаз не гарантирует одинаковых токенов [s1](#src-s1)[s2](#src-s2)[s5](#src-s5).

- **Соседние клиенты видят совпадения:** проверьте, что приложение выставляет свой непредсказуемый salt **на каждом** запросе и не объединяет группы доверия в один секрет. Отдельно проверьте доступ к самому HTTP: `--api-key` у vLLM не защищает все маршруты, включая `/invocations`; ограничьте сеть, примените нужную авторизацию на границе и не публикуйте порт наружу [s3](#src-s3)[s6](#src-s6).

- **Нет места в KV-кеше:** блоки могут вытесняться по политике, описанной в конструкции кеша. Не превращайте размер файлов весов модели в обещание объёма RAM/VRAM: измеряйте фактическое потребление и запросы на своём железе [s2](#src-s2)[s5](#src-s5).

## Какой следующий шаг после трёх серий?

Сохраните ревизию vLLM и модели, железо, запуск, обезличенный шаблон входа, настройку salt, HTTP-ответы, интервал счётчиков и распределение TTFT без публикации секретов. Если ответы корректны, а серия Б выигрывает на повторном prefill без межклиентского совпадения в В, продолжите к [метрикам vLLM и проверке своей нагрузки](/zhurnal/vllm-metrics-prometheus/). Это проверяемый эксперимент на вашем сервере, **не результат Modelium** [s2](#src-s2)[s3](#src-s3)[s4](#src-s4)[s5](#src-s5).

## Источники

1. [vLLM — Automatic Prefix Caching: использование и ограничения](https://github.com/vllm-project/vllm/blob/6f75cc7d5d1b5adfb399cbf79a8231ae66844fcf/docs/features/automatic_prefix_caching.md) — получено 2026-10-04
2. [vLLM — Prefix Caching: хеши, полные блоки, вытеснение и соль](https://github.com/vllm-project/vllm/blob/6f75cc7d5d1b5adfb399cbf79a8231ae66844fcf/docs/design/prefix_caching.md) — получено 2026-10-04
3. [vLLM — Security: cache salting и ограничения API-ключа](https://github.com/vllm-project/vllm/blob/6f75cc7d5d1b5adfb399cbf79a8231ae66844fcf/docs/usage/security.md) — получено 2026-10-04
4. [vLLM — реализация и единицы метрик prefix_cache_queries/hits](https://github.com/vllm-project/vllm/blob/6f75cc7d5d1b5adfb399cbf79a8231ae66844fcf/vllm/v1/metrics/loggers.py) — получено 2026-10-04
5. [vLLM — Production Metrics: endpoint /metrics](https://github.com/vllm-project/vllm/blob/6f75cc7d5d1b5adfb399cbf79a8231ae66844fcf/docs/usage/metrics.md) — получено 2026-10-04
6. [vLLM — OpenAI-Compatible Server: chat API и защита endpoint](https://github.com/vllm-project/vllm/blob/6f75cc7d5d1b5adfb399cbf79a8231ae66844fcf/docs/serving/online_serving/openai_compatible_server.md) — получено 2026-10-04
7. [vLLM — схема ChatCompletionRequest: поле cache_salt](https://github.com/vllm-project/vllm/blob/6f75cc7d5d1b5adfb399cbf79a8231ae66844fcf/vllm/entrypoints/openai/chat_completion/protocol.py) — получено 2026-10-04
8. [vLLM — CLI и выбор default prefix caching по поддержке модели](https://github.com/vllm-project/vllm/blob/6f75cc7d5d1b5adfb399cbf79a8231ae66844fcf/vllm/engine/arg_utils.py) — получено 2026-10-04
