Почему ваш prompt caching не работает (и вы об этом даже не знаете)
Вы запускаете llama-server с флагом --cache-prompt, ожидая волшебного ускорения. Системный монитор показывает активность, модель отвечает. Кажется, всё работает. Но если замерить время первого токена - цифры те же. Память не экономится. Кэш не работает.
Проблема в том, что prompt caching в llama.cpp - это не просто "включил и забыл". Это сложная система с тремя уровнями кэширования, каждый со своими правилами и ограничениями. Большинство разработчиков включают флаг и думают, что сделали всё правильно. Реальность жестче.
На 08.02.2026 в llama.cpp версии 0.14.0+ система кэширования промптов пережила серьёзный рефакторинг. Старые гайды 2024-2025 годов больше не актуальны. Если вы читаете статью про --prompt-cache (с дефисом), а не --cache-prompt (с подчёркиванием), вы смотрите на устаревшую информацию.
Три слоя кэширования: что на самом деле происходит под капотом
Когда вы отправляете промпт в llama.cpp, происходит вот что:
- Static prompt caching - кэширование статических частей промпта (системных инструкций, шаблонов)
- Dynamic lookup cache - кэш для часто повторяющихся последовательностей токенов
- KV cache paging - механизм свопинга ключей и значений в память (тот самый, о котором мы писали в статье про пейджинг KV cache)
Каждый слой работает по своим правилам. И каждый может сломаться независимо от других.
1 Диагностика: как понять, что кэш не работает
Запустите llama-server с дополнительными флагами логирования:
./llama-server -m models/llama-3.2-3b-instruct-q4_K_M.gguf \
--cache-prompt \
--lookup-cache-dynamic \
--log-format json \
--verbose-prompt
Теперь отправьте одинаковый промпт дважды. В логах ищите:
"prompt_cache_hits": 0- это плохо. Должно быть больше нуля"prompt_tokens":сравните значения для первого и второго запроса"timings": {"prompt_ms":- время обработки промпта должно сократиться
2 Настройка static prompt caching (--cache-prompt)
Вот как НЕ надо делать:
# Неправильно: только флаг без параметров
./llama-server -m model.gguf --cache-prompt
Почему это не работает? Потому что по умолчанию кэш хранится только в оперативной памяти и сбрасывается при перезапуске. Нужно указать файл для сохранения:
# Правильно: с указанием файла кэша
./llama-server -m models/llama-3.2-3b-instruct-q4_K_M.gguf \
--cache-prompt cache.bin \
--cache-prompt-size 104857600 # 100MB
| Параметр | Значение по умолчанию | Рекомендация для 2026 |
|---|---|---|
| --cache-prompt | (нет) | Всегда указывайте файл: cache.bin или prompt_cache.dat |
| --cache-prompt-size | 16777216 (16MB) | 100-500MB для production |
| --cache-prompt-type | f16 | f16 для баланса, q4_0 для экономии памяти |
Важный нюанс: static prompt caching работает ТОЛЬКО для идентичных промптов. Даже один изменённый символ - и кэш промахнется. Вот почему многие думают, что кэширование не работает: они отправляют "Привет, как дела?" и "Привет, как дела?" (с разной пунктуацией или пробелами).
3 Dynamic lookup cache (--lookup-cache-dynamic) - секретное оружие
Этот механизм умнее. Он кэширует не целые промпты, а последовательности токенов. Если у вас есть повторяющиеся фразы в разных промптах, lookup cache их запомнит.
./llama-server -m model.gguf \
--lookup-cache-dynamic \
--lookup-cache-size 1000 \
--lookup-cache-max-entries 10000
Параметры:
--lookup-cache-size- максимальная длина последовательности для кэширования (в токенах)--lookup-cache-max-entries- сколько последовательностей хранить--lookup-cache-chunk-size(новое в 0.14.0) - размер чанка для группировки токенов
На 08.02.2026 в llama.cpp добавлена экспериментальная функция --lookup-cache-dynamic-tokens. Она позволяет кэшировать не по позициям токенов, а по их содержанию. Включите её, если у вас много вариативных промптов с одинаковой семантикой.
Типичные ошибки, которые ломают кэширование
Ошибка 1: Разные параметры генерации
Вы думаете: "Я отправляю одинаковый промпт, почему нет кэширования?" А llama.cpp думает иначе. Если в первом запросе был temperature=0.7, а во втором temperature=0.8 - это РАЗНЫЕ запросы с точки зрения кэширования.
Решение: стандартизируйте параметры или используйте отдельные кэши для разных конфигураций.
Ошибка 2: Случайные seed значения
Каждый запрос с --seed -1 (случайный сид) уникален. Кэш не сработает.
Решение: используйте фиксированные seed для повторяющихся промптов или отключайте кэширование для случайных запросов.
Ошибка 3: Контекстное окно меняется
Вы кэшируете промпт длиной 1000 токенов, потом отправляете тот же промпт, но с --ctx-size 2048. Не сработает. Размер контекста - часть ключа кэша.
Об этой проблеме мы подробно писали в статье "Когда промпт длиннее мозга".
Продвинутая настройка: комбинируем кэши
Для production-системы нужна многоуровневая стратегия:
#!/bin/bash
# production-llama-server.sh
MODEL="models/llama-3.2-11b-vision-q4_K_M.gguf"
CACHE_FILE="/var/cache/llama/prompt_cache_$(date +%Y%m).bin"
./llama-server \
-m "$MODEL" \
--cache-prompt "$CACHE_FILE" \
--cache-prompt-size 536870912 # 512MB \
--cache-prompt-type q4_0 \
--lookup-cache-dynamic \
--lookup-cache-size 512 \
--lookup-cache-max-entries 50000 \
--lookup-cache-chunk-size 64 \
--parallel 4 \
--cont-batching \
--flash-attn \
--no-mmap # Важно для стабильности кэша
Обратите внимание на --no-mmap. В некоторых версиях llama.cpp memory-mapped файлы конфликтуют с кэшированием промптов. Если видите странные ошибки - отключайте mmap.
Мониторинг и метрики
Кэширование без мониторинга - это слепая оптимизация. Настройте сбор метрик:
- Hit rate: процент попаданий в кэш. Цель: 70%+ для статических промптов
- Cache size: как быстро растёт файл кэша
- Time saved: среднее экономия времени на запрос
- Memory overhead: сколько дополнительной памяти ест кэш
Используйте Prometheus + Grafana или простой скрипт:
#!/usr/bin/env python3
# monitor_cache.py
import json
import time
from collections import defaultdict
class PromptCacheMonitor:
def __init__(self):
self.hits = 0
self.misses = 0
self.start_time = time.time()
def parse_log_line(self, line: str):
try:
data = json.loads(line)
if "prompt_cache_hits" in data:
self.hits += data["prompt_cache_hits"]
self.misses += data.get("prompt_tokens", 0) - data["prompt_cache_hits"]
hit_rate = self.hits / (self.hits + self.misses) if (self.hits + self.misses) > 0 else 0
print(f"Hit rate: {hit_rate:.2%} | Hits: {self.hits} | Misses: {self.misses}")
except json.JSONDecodeError:
pass
# Запуск: tail -f llama.log | python3 monitor_cache.py
Когда кэширование бесполезно (и даже вредно)
Не всё нужно кэшировать. Вот ситуации, когда лучше отключить --cache-prompt:
- Чат-боты с уникальными диалогами: каждый диалог уникален, кэш будет только занимать память
- Маленькие промпты: если промпт короче 50 токенов, overhead кэширования может быть больше выгоды
- Ограниченная дисковая память: кэш-файлы растут быстро. На SSD с малым объёмом это проблема
- Часто меняющиеся системные промпты: если вы каждый день обновляете инструкции, старый кэш становится мусором
Для таких случаев используйте только --lookup-cache-dynamic или вообще откажитесь от кэширования.
Интеграция с внешними системами
Если вы используете обёртки над llama.cpp (AnythingLLM, CLINE, Ollama), кэширование нужно настраивать на уровне llama-server, а не через API обёртки.
Например, в AnythingLLM нужно модифицировать конфигурационный файл запуска:
{
"llama_cpp": {
"server_args": [
"--cache-prompt",
"/path/to/anythingllm_cache.bin",
"--cache-prompt-size",
"268435456",
"--lookup-cache-dynamic"
]
}
}
Будущее prompt caching (прогноз на 2026-2027)
По данным разработчиков llama.cpp, в roadmap на 2026 год:
- Distributed prompt cache: общий кэш для кластера llama.cpp серверов
- Semantic caching: кэширование по смыслу, а не по точному совпадению токенов
- Adaptive cache sizing: автоматический подбор размера кэша на основе паттернов использования
- GPU cache offloading: хранение горячих промптов в GPU памяти для instant-доступа
Уже сейчас в экспериментальных сборках есть --cache-prompt-compression (сжатие кэша с потерями) и --cache-prompt-ttl (время жизни записей).
Важный совет: не обновляйте llama.cpp в production без тестирования кэширования. В версии 0.13.0 → 0.14.0 формат кэш-файлов изменился. Старые кэши стали нечитаемыми. Всегда делайте бэкап cache.bin перед обновлением.
И последнее: самый эффективный способ ускорить инференс - это не только кэширование, но и правильная сборка llama.cpp под ваше железо. Если вы ещё не читали нашу статью "Сборка llama.cpp не для всех", сделайте это прямо сейчас. Потому что даже идеально настроенный кэш не спасёт от медленной сборки с неправильными флагами компиляции.
Кэширование промптов - это не магия, а инженерная дисциплина. Настраивайте осознанно, мониторьте постоянно, тестируйте при каждом обновлении. Только тогда вы получите реальное ускорение, а не просто галочку "включено" в конфигурации.