3,583 papers
arXiv:2610.34817 77 26 окт. 2026 г. FREE

Prompt-Caching Mis-Integration: почему кэш промпта в агентах молча перестаёт работать, и как это поймать

КЛЮЧЕВАЯ СУТЬ
Обнаружено: 90% поломок кэша промпта в агентах тихие. Ответы верные, тесты зелёные, ошибок нет. Растёт только счёт. Разбор 120 исправлений в 10 популярных открытых агентах даёт каталог из 8 типовых причин. Он позволяет найти, почему счёт за API выше расчётного, и проверить это за один запрос к модели. Типичный виновник: в начало системной инструкции положили datetime.now() с секундами. Каждый запрос получает новое начало, и скидка не срабатывает ни разу. Модель при этом работает как обычно, поэтому кэш никто не замечает.
Адаптировать под запрос
⚡

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

📋 Дайджест исследования

Ключевая суть

Обнаружено: 90% поломок кэша промпта в агентах тихие. Ответы верные, тесты зелёные, ошибок нет. Растёт только счёт. Разбор 120 исправлений в 10 популярных открытых агентах даёт каталог из 8 типовых причин. Он позволяет найти, почему счёт за API выше расчётного, и проверить это за один запрос к модели. Типичный виновник: в начало системной инструкции положили datetime.now() с секундами. Каждый запрос получает новое начало, и скидка не срабатывает ни разу. Модель при этом работает как обычно, поэтому кэш никто не замечает.

Принцип работы

Провайдер сравнивает запросы побайтово с первого символа. Совпало начало — за него берут примерно в десять раз меньше. Изменился хоть один символ в начале — вся скидка на остаток пропала. Что не меняется, держи в начале. Что меняется, уноси в конец. Это как рабочий стол: подшитые бумаги лежат внизу стопки, свежая записка сверху. Достанешь одну из нижних — перекладывать придётся всю стопку. Фишка: самая частая причина, около трети случаев, вообще не про текст. Код включает кэш по имени модели. Модель переименовали или добавили новую, и кэш тихо выключился.

Почему работает

Сломанный кэш ничего не ломает в поведении. Модель просто считает всё заново и отвечает так же. Поэтому проверка «посмотрел, работает» проблему не ловит. Видно её только в панели провайдера, по доле кэшированных токенов. А ловить такое удобно по списку: причин всего восемь, а исправления в основном маленькие и локальные. По причине способ исправления угадывается в 79% случаев по самой частой связке. Модель хорошо читает код и сверяет его с известными паттернами. Узкая проверка по чек-листу ей удаётся. Но осторожно: в самой статье детектор примерно в трети предупреждений ошибался, точность около 71%. Вердикт модели считай гипотезой и сверяй со счётом.

Когда применять

Агенты и автоматизации на API с длинной неизменной частью запроса (тысячи токенов правил, описания инструментов, история диалога) → конкретно для случая, когда счёт выше расчётного, а ответы в порядке. Особенно если код писал ИИ-помощник и никто не смотрел, как собирается начало запроса. НЕ подходит, если вы работаете только в чате ChatGPT или Claude: кэшем там вы не управляете. Не подходит и для коротких разовых запросов.

Мини-рецепт

1. Назови провайдера: Anthropic и Bedrock требуют явно включать кэш, OpenAI и Gemini кэшируют сами. От этого зависят пункты про маркер.
2. Дай код целиком вокруг вызова: где собирается системная инструкция, список инструментов и история. Одной строки мало.
3. Скорми модели чек-лист: привязка к имени модели, меняющееся значение в начале (время, UUID, счётчики), порядок сборки частей, одинаковые ли байты у одинаковых данных, где стоит маркер кэша, не переписывается ли история между ходами, верен ли учёт токенов.
4. Требуй честности: на каждый пункт ответ «ок», «нарушено» или «не вижу в коде». Додумывать запрещено.
5. Попроси топ-3 самых дорогих нарушений с конкретной правкой. Время обычно уезжает в конец или огрубляется до даты.
6. Проверь счётом: после правок открой панель провайдера и посмотри долю кэшированных токенов. Это единственный надёжный способ.
7. Для n8n и Make без кода оставь четыре пункта: меняющееся значение, порядок, одинаковые байты и учёт токенов. Ломается чаще всего там.

Примеры

[ПЛОХО]: `Почему мой бот так дорого стоит? Вот код, исправь.` [ХОРОШО]: `Ты — аудитор кэша промпта. Провайдер: Anthropic, модель claude. Агент: бот поддержки для продавцов маркетплейса, в системной инструкции 6000 токенов правил возврата. Найди, где собирается запрос и включается cache_control. Проверь: не привязан ли кэш к имени модели, нет ли времени с секундами или номера запроса в начале, одинаков ли порядок частей, стоит ли маркер на стабильной части. По каждому пункту ответь: ок, нарушено или не вижу в коде. Не додумывай. В конце дай до трёх самых дорогих нарушений. Код: {код}` [ПЛОХО]: `Проверь, всё ли в порядке с кэшем` и вставить одну строку кода. [ХОРОШО]: вставить весь кусок, где собирается начало запроса, и добавить в запрос фразу `если в коде чего-то не видно, так и напиши`.
Источник: Silent and Costly: Characterizing and Detecting Prompt-Caching Mis-Integration in LLM Agents
ArXiv ID: 2610.34817 | Сгенерировано: 2026-10-29 13:07

Проблемы LLM

ПроблемаСутьКак обойти
Скидка на повторяющееся начало запроса молча пропадаетПровайдер даёт скидку примерно в десять раз, если начало нового запроса совпадает с прошлым до байта. Любое изменение в начале обнуляет совпадение для всего, что дальше. Ответы при этом те же, ошибок нет. Меняется только счёт и скорость. Проблему не видно, пока не посмотришь расходДержи в начале запроса только то, что не меняется: правила, инструкции, описания инструментов. Время, номер запроса и имя пользователя уноси в конец. Проверяй долю кэшированных токенов в панели провайдера

Методы

МетодСуть
Стабильное начало запроса — дешёвые повторные вызовыСначала ставь неизменные части: роль, правила, справочные данные. Потом редкие изменения. В самом конце — то, что меняется каждый раз: вопрос пользователя, текущая дата. Если дата нужна, округляй её до дня. Почему работает: провайдер сравнивает запросы с первого символа. Пока начало одинаково, эту часть не пересчитывают и берут за неё меньше денег. Когда применять: длинная инструкция (тысячи токенов) и много повторных вызовов подряд. Когда не работает: короткий запрос, разовый вызов, работа только в чате без доступа к настройкам API
Проверка запроса по чек-листу предусловийДай модели код сборки запроса и список вопросов. Меняется ли что-то в начале? Одинаков ли порядок частей? Дают ли одинаковые данные одинаковые байты? Не переписывается ли история между ходами? Попроси ответ по каждому пункту: «ок», «нарушено» или «не вижу в коде». Запрети додумывать. Почему работает: узкая проверка по списку известных паттернов — сильная сторона модели. Когда применять: счёт за API выше расчётного. Когда не работает: кода мало, одной строки не хватает. Вердикт — гипотеза, а не факт

Тезисы

ТезисКомментарий
Порядок частей в запросе влияет на цену, а не только на смыслКогда запросы часто повторяются, значение имеет не только содержание, но и расположение. Неизменное идёт первым, меняющееся последним. Тогда повторяющаяся часть не пересчитывается. Применяй: при сборке запроса вынеси дату, идентификаторы и данные пользователя в конец
Сломанная экономия не ломает ответ, поэтому её не видно по качествуКэш может не работать месяцами, а ответы остаются правильными. Тесты на качество такую поломку не ловят. Применяй: после любой правки запроса смотри расход и долю кэшированных токенов, а не только ответы
📖 Простыми словами

Silent and Costly: Characterizing and DetectingPrompt-Caching Mis-Integration inLLMAgents

arXiv: 2610.34817

Суть проста: провайдеры дают щедрую скидку, когда начало твоего запроса не меняется. Это называется кэширование промптов, и оно требует строгого побайтового совпадения с первого символа. Достаточно вставить пробел, текущую дату или случайный ID в начало диалога, и весь кэш слетает к чертям. При этом код не падает с ошибкой, а модель отвечает идеально — происходит тихий слив бюджета, который невозможно заметить на обычных тестах.

Это как купить годовой абонемент со скидкой 90%, но контролёр на входе рвёт его каждый раз, если ты надел другие носки. Формально тебя пустили, тренировка состоялась и скандала нет, но на выходе молча списывают полную стоимость разового визита. Ты уверен, что круто сэкономил, пока в конце месяца не открываешь банковскую выписку.

Исследователи вскрыли 120 правок в 10 агентах и доказали: разработчики массово наступают на одни и те же грабли. Главный косяк — совать динамические данные перед статичной базой. Из-за одной плавающей строчки в шапке улетает скидка в 10 раз и выигрыш до 80% скорости ответа. Чтобы ловить такие баги автоматически, авторы собрали чекер CacheLint, который находит подобные тупые косяки прямо в исходниках.

Проблема касается не только сложных агентов, но и любого простого бота на Claude API или GPT. Зашил в системный промпт правила на 6000 токенов, но переставил местами описание двух инструментов или добавил таймстемп сверху — плати заново за всю простыню. Правило универсально: статичный контекст обязан быть монолитом и всегда идти строго в самом начале запроса.

Короче: пока ты радуешься, что бот работает без ошибок, он может по-тихому доить карман на пустом месте. Зафиксируй префикс запроса намертво, вынеси всё динамическое в конец и натрави на проект линтер кэша. Иначе продолжишь переплачивать вдесятеро за то, что провайдер готов отдавать за копейки.

Работа с исследованием

Адаптируйте исследование под ваши задачи или создайте готовый промпт на основе техник из исследования.

0 / 2000
~0.5-2 N-токенов ~10-30с
~0.3-1 N-токенов ~5-15с