Запись архива

Как настроить локальное кеширование контекста в Ollama для LLM-агентов: архитектура, память и реальная экономия

Разбираем внутреннюю архитектуру кеширования контекста в Ollama, настраиваем параметры KV-cache для автономных агентов и замеряем реальное ускорение генерации при многошаговых вызовах.

Архитектура KV-cache в сервере Ollama для локальных LLM-агентов
Архитектура KV-cache в сервере Ollama для локальных LLM-агентов
Hormozgantoday.jpg | by Hormozgantv | wikimedia_commons | CC BY-SA 4.0

Автономные 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 и проанализируйте логи сервера на предмет попадания в кеш.

Источники