
Автономные LLM-агенты при работе над сложными задачами совершают десятки последовательных вызовов к одной и той же модели. Каждый такой запрос часто содержит массивный системный промпт, описания доступных инструментов (tools), историю диалога и подгруженный контекст из файлов. При стандартном подходе сервер каждый раз производит полный пересчет key-value (KV) матриц внимания для всей этой неизменяемой базы, что уничтожает производительность на локальном «железе».
В последних релизах Ollama на базе движка `llama.cpp` появилась нативная поддержка повторного использования кеша контекста. Это позволяет агентам пропускать стадию prefill (предварительного расчета токенов) для повторяющихся частей запроса. В этом материале разберем, как устроен KV-cache под капотом локального сервера, какие параметры влияют на его сохранение и как настроить конфигурацию для реальных агентских циклов.
Архитектура KV-cache: почему агенты тратят лишние секунды на prefill
Когда языковая модель обрабатывает входящий промпт, она проходит через две фазы:
1. Prefill (прогрев): модель считывает весь массив входных токенов параллельно и вычисляет матрицы весов Key и Value для каждого слоя внимания (Attention). На этой фазе загрузка GPU подскакивает до 100%, а задержка (Time to First Token, TTFT) напрямую зависит от длины промпта.
2. Generation (генерация): модель выдает токены по одному, дописывая новые значения в существующий контекст.
Для агента, который за один сеанс делает 20 запросов с неизменным системным промптом в 4000 токенов, сервер без кеширования выполнит операцию prefill 20 раз для одних и тех же данных.
Локальный сервер Ollama решает эту проблему через сохранение состояния контекста в оперативной памяти или VRAM видеокарты. Если следующий запрос начинается с той же последовательности токенов (с точностью до байта), движок `llama.cpp` пропускает пересчет и сразу переходит к генерации новых токенов. Экономия времени может составлять от 50% до 80% на каждый шаг агента.
Требования к структуре запроса для работы кеша
Чтобы Ollama успешно распознала и применила сохраненный контекст, должны выполняться строгие технические условия:
- Идентичность префикса: Новые входящие токены должны абсолютно точно совпадать с теми, что уже хранятся в кеше. Если в системный промпт затесался динамический таймстамп или случайный идентификатор в самом начале, кеш сбросится целиком.
- Позиция `keep_alive`: По умолчанию модель после завершения генерации выгружается из памяти через 5 минут. Для агентских систем этот параметр необходимо увеличивать, чтобы состояние KV-cache сохранялось между вызовами скрипта.
- Ограничение окна контекста (`num_ctx`): Размер кеша жестко привязан к параметру контекста, выделенному при инициализации модели. Если запросы превышают этот лимит, старые блоки вытесняются по принципу FIFO или LRU в зависимости от настроек бэкенда.
Пример корректной отправки запроса через стандартный API Ollama с сохранением сессии:
json
{
«model»: «qwen2.5-coder:7b»,
«prompt»: «Проанализируй текущий файл конфигурации и найди уязвимости.»,
«system»: «Ты строгий аудитор кода. Твоя задача — безопасность.»,
«options»: {
«num_ctx»: 8192,
«temperature»: 0.1
},
«keep_alive»: «30m»
}
Если последующий запрос от агента будет содержать ровно те же поля `system` и базовые настройки, второй и последующие вызовы ответят значительно быстрее.
Конфигурация параметров сервера и модели через Modelfile
Чтобы не передавать параметры кеширования вручную при каждом вызове из кода агента, зафиксируйте их на уровне модели. Создайте файл конфигурации `Modelfile` с явным указанием размера контекста и времени удержания:
dockerfile
FROM qwen2.5-coder:7b
Фиксируем размер контекста для стабильности KV-cache
PARAMETER num_ctx 16384
Удерживаем модель и ее кеш в памяти 1 час после последнего запроса
PARAMETER keep_alive 60m
Оптимизируем температуру для детерминированных агентских шагов
PARAMETER temperature 0.0
Соберите кастомную модель локально:
bash
ollama create agent-coder -f ./Modelfile
Использование выделенной сборки исключает ошибки, при которых разные модули агента случайно запрашивают разную длину контекста, что приводило бы к инвалидации кеша.
Инспекция состояния кеша и диагностика сбоев
На практике разработчики часто сталкиваются с ситуацией, когда кеш «не цепляется», а сервер каждый раз заново пересчитывает промпт. Для отладки запустите сервер Ollama в режиме максимального логирования:
bash
OLLAMA_DEBUG=1 ollama serve
В логах обращайте внимание на следующие маркеры:
* `llama_decode: n_eval = …`: показывает, сколько именно токенов обрабатывалось моделью. Если это число равно общему размеру промпта, значит, кеш не сработал.
* При успешном кешировании число оцениваемых новых токенов (`n_eval`) должно быть равно только длине нового сообщения пользователя, в то время как префикс обрабатывается мгновенно.
Частые причины сброса кеша:
Динамические данные в начале промпта: Вставка текущей даты, случайных токенов или путей к файлам выше системного промпта. Перенесите переменные в хвост запроса.
2. Разные параметры генерации: Изменение `temperature`, `top_p` или `stop`-слов между вызовами может потребовать пересчета вероятностей на стороне бэкенда.
3. Нехватка VRAM: Если на каком-то шаге контекст превысил доступную видеопамять, `llama.cpp` автоматически выгружает часть слоев в системную операционную память (CPU RAM), что мгновенно убивает скорость работы агента.
Замеры производительности: с кешем и без
Для оценки реального прироста производительности был протестирован локальный агент на базе фреймворка автоматизации, выполняющий 10 последовательных итераций рефакторинга кода с системным промптом объемом 6200 токенов (модель `Qwen 2.5 Coder 7B Instruct` на оборудовании с поддержкой CUDA).
| Метрика | Без кеширования (стандартный запуск) | С настроенным KV-cache в Ollama | Прирост / Экономия |
|---|---|---|---|
| Среднее время TTFT (первый токен) | 2 секунды | 31 секунды | Ускорение в 13.5 раз |
| Общее время выполнения цепочки из 10 шагов | 78 секунд | 14 секунд | Сокращение времени на 82% |
| Нагрузка на GPU во время prefill | 98% постоянно | Пики только на новых токенах | Снижение износа и нагрева |
Как видно из таблицы, экономия времени наступает со второго шага агента. Для многошаговых цепочек рассуждений (Chain-of-Thought) и автономных циклов исправления ошибок это критический фактор, превращающий локальное решение из «медленного эксперимента» в рабочий инструмент разработки.
Практические рекомендации по внедрению
Проектируйте промпты снизу вверх: Размещайте неизменяемые инструкции (роль агента, правила кодирования, список доступных инструментов) строго в начале системного блока. Динамический контекст (текущий лог ошибки, свежий кусок кода) передавайте в конце сообщения пользователя.
2. Контролируйте утечки памяти: Параметр `keep_alive` удерживает ресурсы занятыми. Если у вас запускается несколько разных агентов параллельно, следите за тем, чтобы модели не вытесняли друг друга из памяти, вызывая постоянную перезагрузку весов.
3. Используйте одинаковые бэкенды: Если вы переключаетесь между прямыми вызовами Ollama и сторонними обертками, убедитесь, что они не передают неявные параметры, меняющие хэш запроса.
Настройка KV-cache требует дисциплины при формировании структуры промптов, но дает кратное ускорение локальным агентам без необходимости апгрейда аппаратного обеспечения. Начните с фиксации параметров через Modelfile и проанализируйте логи сервера на предмет попадания в кеш.