TL;DR
Prompt caching (кэш промпта) — это скидка от провайдера на повторяющееся начало запроса. Если новый запрос побайтово совпадает с предыдущим от первого символа, провайдер не пересчитывает эту часть и берёт за неё примерно в десять раз меньше. Задержка падает до 80%. Для агентов это важно: системная инструкция, описания инструментов и история диалога почти не меняются от вызова к вызову. Авторы разобрали 120 исправлений в 10 популярных open-source агентах и составили каталог типовых поломок кэша. Сверху они сделали детектор CacheLint, который ищет эти поломки в коде.
Главная находка: 90% поломок кэша тихие. Агент отвечает правильно, тесты зелёные, ошибок нет. Меняется только счёт за API и скорость. Типичный случай: в начало системного промпта положили datetime.now() с секундами. Каждый запрос получает новое начало, кэш никогда не срабатывает, а деньги уходят. Самая частая причина (около трети случаев) — проверка по имени модели. Модель переименовали или добавили новую, и кэш отключился. Остальное — нестабильное начало промпта: меняющееся значение, другой порядок сборки, непредсказуемая сериализация.
Метод CacheLint сводится к двум шагам. Сначала находим место, где код включает кэш. Потом проверяем набор предусловий (то, что должно быть верно, чтобы кэш сработал): поддерживает ли провайдер этот режим для этой модели, стабильно ли начало промпта, правильно ли считаются кэшированные токены. Для читателя без CodeQL главная ценность — каталог из 8 причин. Его можно скормить LLM как чек-лист для ревью своего агента или автоматизации.
Схема метода
ШАГ 1: Найти места, где агент включает кэш (cache_control, cachedContent и т.п.)
→ список мест вызова
ШАГ 2: Для каждого места проверить предусловия:
a) Провайдер/модель: поддерживает ли режим? Нет ли жёсткой привязки к имени модели?
b) Стабильность начала: нет ли времени, UUID, случайного порядка, разного порядка сборки?
c) Мутации между ходами: не переписывается ли уже закэшированный кусок?
d) Учёт: правильно ли читаются и суммируются кэшированные токены?
→ список нарушений + подсказка, как исправить
В оригинале шаг 1 делает CodeQL (статический анализ кода). Шаг 2 делает справочник возможностей провайдеров (для пункта a) и LLM-проверка по контексту вызова (для b–d). В чате можно выполнить оба шага одним запросом: вставить кусок кода и чек-лист.
Пример применения
Задача: Вы собрали бота поддержки для селлеров Wildberries. Он работает на Claude API через небольшой Python-скрипт, который сделал Cursor. В системном промпте — 6000 токенов правил возврата и тарифов. Бот отвечает отлично, но счёт за API вдвое выше расчётного. Вы подозреваете, что кэш не работает.
Промпт:
Ты — аудитор интеграции prompt caching (кэша промпта) в LLM-агентах.
Ниже код моего бота поддержки. Провайдер: Anthropic API (Claude).
Найди все места, где собирается системный промпт и запрос к модели,
и места, где включается кэш (cache_control).
Для каждого места проверь по списку:
1. Привязка к имени модели: не включается ли кэш условием вроде
"если имя начинается с claude". Новая или переименованная модель
может тихо отключить кэш.
2. Меняющееся значение в начале промпта: время с секундами/минутами,
UUID, ID запроса, счётчики, имя пользователя до стабильных правил.
3. Порядок сборки: одинаков ли порядок частей префикса при каждом вызове
(словари, наборы, список инструментов).
4. Сериализация: даёт ли одинаковое содержимое одинаковые байты
(несортированные ключи JSON, случайные ID вызовов).
5. Маркер кэша: стоит ли он на стабильной части, а не на последнем
сообщении пользователя.
6. Мутации между ходами: не обрезается ли и не переписывается ли
история так, что закэшированное начало меняется.
7. Учёт: правильно ли читаются и суммируются токены чтения и записи кэша.
Формат ответа: таблица «пункт — нарушено/ок/не могу определить —
строка кода — как исправить». Если данных в коде не хватает, так и пиши,
не додумывай.
Код:
{код_бота}
Результат: Модель выдаст таблицу по 7 пунктам со ссылками на строки. Если в коде есть datetime.now() в начале системного промпта, скорее всего он будет отмечен как главное нарушение. Рядом будет предложение вынести время в конец или огрубить его до даты. По пунктам, которых в коде не видно (например, учёт токенов), модель должна написать «не могу определить». После правок посмотрите в панели провайдера долю кэшированных токенов: это единственный надёжный способ убедиться.
Почему это работает
Слабость. Кэш сравнивает запросы по байтам с первого символа. Любое изменение, вставка или перестановка в начале обнуляет совпадение для всего, что идёт дальше. При этом сломанный кэш ничего не ломает в поведении: модель просто считает всё заново и отвечает так же. Поэтому тесты и «посмотрел, работает» не ловят проблему. Заметна она только на счёте.
Сильная сторона LLM. Ей легко читать код и настройки и сопоставлять их со списком известных паттернов. Паттернов мало: восемь причин, и большинство фиксов маленькие и локальные. Авторы показали, что по причине почти всегда предсказывается способ исправления: по самой частой связке верно угадывается 79% случаев.
Как метод использует это. Он превращает «странно дорого» в проверку по чек-листу из конкретных предусловий. Сначала находим точку включения кэша, потом проверяем каждое условие отдельно. LLM хорошо справляется с такой узкой проверкой по контексту.
Рычаги управления: - Провайдер в промпте. Anthropic и Bedrock требуют явного включения кэша, OpenAI и Gemini кэшируют автоматически. Укажите свой, и пункты про маркеры станут точнее. - Список пунктов. Для автоматизации без кода (n8n, Make) оставьте пункты 2, 3, 4 и 7. Именно там чаще всего ломается кэш. - Строгость ответа. «Не додумывай, пиши "не могу определить"» снижает ложные срабатывания. В самой статье у детектора около 71% точности на размеченных случаях. - Контекст. Чем больше кода вокруг вызова вы дадите, тем лучше проверка. Одной строки мало.
Шаблон промпта
Это не авторский промпт CacheLint, а переложение его предусловий в формат чек-листа для чата. Структура «место вызова → предусловия → вердикт по каждому» сохранена.
Ты — аудитор интеграции prompt caching в LLM-агентах.
Провайдер: {провайдер}
Модели, которые используются: {список_моделей}
Что делает агент: {краткое_описание}
1. Найди в коде все места включения кэша и сборки префикса запроса
(системная инструкция, описания инструментов, история диалога).
2. Для каждого места проверь предусловия:
P1_ProviderCompat: кэш включается по возможностям провайдера,
а не по жёстко прописанному имени модели; формат маркера
принимается провайдером.
P2_PrefixStability: в закэшированной части нет значений,
меняющихся от запроса к запросу (время, UUID, счётчики);
порядок сборки частей всегда одинаков;
сериализация детерминирована (сортировка ключей);
маркер стоит на стабильной части, а не на меняющемся сообщении.
P3_CrossTurn: между ходами не переписывается уже закэшированный
фрагмент (обрезка истории, замена вложений, пересборка промпта).
P4_Accounting: токены чтения и записи кэша читаются из ответа
и суммируются верно.
3. Для каждого предусловия верни вердикт: OK / НАРУШЕНО / НЕ ВИДНО В КОДЕ.
Таблица: место в коде | предусловие | вердикт | почему | как исправить.
После таблицы — до 3 самых дорогих нарушений по приоритету.
Не додумывай то, чего нет в коде.
Код:
{код}
Подставьте:
- {провайдер}: Anthropic, OpenAI, Gemini, Bedrock или шлюз вроде OpenRouter;
- {список_моделей}: все модели, включая запасные;
- {краткое_описание}: одна фраза о том, что делает агент;
- {код}: куски, где собирается запрос, и конфигурация.
🚀 Быстрый старт — вставь в чат:
Вот шаблон аудита prompt caching. Адаптируй под мою задачу: [опиши своего агента или автоматизацию].
Задавай вопросы, чтобы заполнить поля.
[вставить шаблон выше]
LLM спросит, какой у тебя провайдер, какие модели и где собирается запрос. Эти ответы нужны, потому что режим кэша зависит от провайдера и модели. Остальное она возьмёт из паттерна шаблона.
Ограничения
⚠️ Нужен доступ к коду или настройкам: метод про ошибки интеграции через API. Если вы работаете только в чате ChatGPT или Claude, кэшем вы не управляете. Здесь вам нечего чинить.
⚠️ Ложные срабатывания: детектор в исследовании примерно в трети предупреждений ошибался на размеченных проектах. Вердикт LLM — гипотеза. Проверяйте по счёту и по доле кэшированных токенов в панели провайдера.
⚠️ Ответ про пользу кэша авторы не измеряют. Размер выигрыша от каждого исправления в статье не посчитан. Есть отдельные случаи вроде «+75% стоимости из-за пересборки промпта», но сводной цифры нет.
⚠️ Правила устаревают. Провайдеры меняют условия: срок жизни кэша, поддерживаемые модели. Один из них сократил срок по умолчанию с часа до пяти минут, и попадания упали без единой правки кода. Чек-лист придётся перепроверять.
⚠️ Лишь часть пунктов касается текста промпта. Остальное — код: порядок сборки, сериализация, учёт токенов. Если у вас готовый инструмент без доступа к коду, воздействовать можно только на содержимое инструкций.
Как исследовали
Исследователи нашли через GitHub 581 репозиторий с признаками кэширования промптов и оставили 10 самых популярных агентов (OpenClaw, Hermes-Agent, AutoGPT, OpenCode, Cline, OpenHands, Aider и др.). Из 148 947 слитых pull request они отобрали по ключевым словам 622 кандидата. Три автора вручную разобрали их, согласие составило 0,76 по Fleiss' κ. Осталось 120 реальных исправлений, а 502 оказались ложными совпадениями.
Каждую ошибку классифицировали по причине, симптому и способу исправления. Вышло два типа и восемь причин. На стороне запроса — 97 случаев (81%): привязка к имени модели (37), пересборка префикса (15), меняющееся значение (13), нестабильная сериализация (10), несовместимый маркер (10), мутации между ходами (9) и неверно поставленный маркер (3). На стороне чтения — 23 случая (19%): неверный подсчёт кэшированных токенов.
Удивило, что 108 из 120 (90%) молча: ни исключения, ни падения теста. Падением заканчивались только 12 случаев, в основном из-за маркера, который провайдер отверг. Вывод из этого практический: классические проверки «упало/не упало» тут бесполезны, нужно смотреть на структуру запроса. Исправления оказались маленькими и локальными, и по причине предсказывается способ исправления в 79% случаев.
Затем авторы построили детектор CacheLint. На 120 размеченных случаях он дал точность 0,71 и полноту 0,78. На 571 свежем репозитории нашёл 32 новые ошибки с точностью 0,86. 21 подтвердили мейнтейнеры, 18 исправили, включая официальный SDK Anthropic. В статье, которую вы видите, текст обрывается на разборе сложности патчей, поэтому детали оценки сложности я не пересказываю.
Адаптации и экстраполяции
🔧 Техника: грубее значение → стабильнее начало. Авторы показывают пример из PrivateGPT. datetime.now().isoformat() в начале промпта заменили на .date().isoformat(). Начало осталось одинаковым весь день, а агент по-прежнему знает дату. Если нужно именно время, вынесите его в конец запроса, в последнее пользовательское сообщение, а не в системный промпт.
Следующий блок — моя экстраполяция, в статье этого нет. Принцип «стабильное идёт вперёд, меняющееся — назад» можно перенести на инструкции агентов (CLAUDE.md, AGENTS.md, системные промпты в кастомных ботах):
Структура инструкции, дружелюбная к кэшу:
1. Неизменные правила, роль, формат ответа ← ставим в начало
2. Описания инструментов (в одном порядке) ← не переставлять
3. Редко меняющиеся справочники, база знаний
4. ───── граница кэша ─────
5. Дата, имя пользователя, текущая задача, свежие данные ← в конец
Не вписывайте в начало инструкции текущее время, случайные ID и счётчики. Не редактируйте начало посреди сессии. Это следует из механики побайтового совпадения, но проверять на своём инструменте нужно самому.
Ресурсы
- Работа: Silent and Costly: Characterizing and Detecting Prompt-Caching Mis-Integration in LLM Agents
- Авторы: Ying Zhang (Wake Forest University), Ruoqi Guo, Yi Liu, Leo Zhang (Griffith University), Yuekang Li (UNSW), Yepang Liu (SUSTech), Gelei Deng (NTU)
- Инструмент: CacheLint (CodeQL + справочник возможностей провайдеров + LLM-проверка на gpt-5.4-mini); датасет из 120 исправлений авторы выложили публично
- Разобранные проекты: OpenClaw, Hermes-Agent, AutoGPT, OpenCode, LobeHub, OpenHands, Cline, Goose, Aider, Nanobot
- Документация провайдеров по prompt caching: Anthropic, OpenAI, Gemini, Amazon Bedrock
