Гайды· 29.08.2026· 7 мин чтения

Кеш промптов LLM: как одна строка ломает экономию на 98%

Почему кеширование промптов у DeepSeek, OpenAI и Anthropic отключается незаметно и как найти виновника с помощью инструмента prefixcash за пять минут.

📚
PL
Материал подготовлен с помощью ИИ и проверен редактором

Токен из кеша у DeepSeek дешевле обычного в 31 раз, у OpenAI и Anthropic — в 10 раз. Но кеш работает по принципу «всё или ничего»: если первые токены промпта разошлись хоть на одном символе, экономия обнуляется целиком, а не частично. Разработчик под ником Isk4R1oT показал на живых вызовах, как это происходит и как поймать проблему за пару минут.

Если вы строите агента, который дергает LLM тысячи раз в день с одним и тем же системным промптом, эта статья — про деньги, которые вы теряете прямо сейчас и, скорее всего, не замечаете.

Почему кеш вообще экономит деньги

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

Цены на 27 августа 2026 года показывают масштаб разницы:

| Провайдер | Обычный токен | Токен из кеша | Разница | |---|---|---|---| | DeepSeek v4-flash | $0.44 / 1M | $0.014 / 1M | 31x | | OpenAI gpt-5.6-sol | $4.00 / 1M | $0.40 / 1M | 10x | | Anthropic Sonnet | $3.00 / 1M | $0.30 / 1M | 10x |

У DeepSeek и OpenAI кеш включается автоматически. У Anthropic его нужно запрашивать явно:

python
client.messages.create(
    model="claude-sonnet-5",
    cache_control={"type": "ephemeral"},  # без этого кеша нет вовсе
    system=POLICY,
    messages=messages,
)

Но там, где кеш включён, он ломается совершенно одинаково — одной строкой в начале промпта.

Самая частая причина обрыва — время в системном промпте

Классический баг выглядит так:

python
system = f"Current time: {datetime.now()}.\n{POLICY}\n{KNOWLEDGE_BASE}"

Время меняется на каждом вызове, значит префикс расходится уже на четвёртом слове. Весь промпт — включая двухтысячетокенную политику и базу знаний, которые не менялись ни разу, — каждый раз тарифицируется по полной цене.

Автор проверил это на живом support-агенте с системным блоком около 1200 токенов (DeepSeek включает кеш примерно от 1024 токенов) и четырьмя вопросами подряд. Две сессии с одинаковым содержимым, но разной сборкой промпта:

plain
live-broken prompt=1177 cache_hit=0
live-broken prompt=1180 cache_hit=0
live-broken prompt=1179 cache_hit=0
live-broken prompt=1178 cache_hit=0
live-fixed  prompt=1180 cache_hit=0
live-fixed  prompt=1183 cache_hit=1152
live-fixed  prompt=1182 cache_hit=1152
live-fixed  prompt=1181 cache_hit=1152

В первой сессии время стоит первой строкой — ноль попаданий в кеш из восьми вызовов. Во второй время перенесено в конец промпта — 1152 токена из ~1180 берутся из кеша. Это специально худший случай для наглядности: на реальных промптах динамика обычно сидит глубже, и базовый уровень кеша держится на 49–66%, а не падает до нуля.

Для агента с промптом 1200 токенов и 10 000 вызовов в день разница ощутима в деньгах:

| Провайдер | Без кеша | С кешем 98% | Экономия | |---|---|---|---| | DeepSeek v4-flash | $158 / мес | $8 / мес | −$150 | | OpenAI gpt-5.6-sol | $1 440 / мес | $173 / мес | −$1 267 | | Anthropic Sonnet | $1 080 / мес | $130 / мес | −$950 |

Если у вас datetime.now() в первой строке — вы это уже понимаете и без инструментов. Хуже, когда причина не видна глазами вообще.

Четыре бага, которые не найти чтением кода

Автор описывает общий паттерн, характерный для любого провайдера с префиксным кешем — просто на примере Anthropic он нагляднее всего:

Схемы инструментов. У Anthropic кеш покрывает tools, system, messages именно в этом порядке — схемы инструментов лежат в самом начале префикса, раньше системного промпта. Если собирать их из словаря с плавающим порядком ключей, кеш ломается в первой же позиции — и в исходном коде промпта это никак не проявляется.

База знаний из `set()`. Содержимое между вызовами одинаковое, но порядок элементов множества между процессами разный. Текст совпадает, а префикс — нет, и кеша нет.

Кеш есть в коде, а `cache_read_tokens == 0`. Сборка промпта правильная, но попаданий всё равно нет — значит истёк TTL (время жизни записи в кеше) или сам провайдер временно не кеширует запрос. Это чинится маршрутизацией трафика, а не правкой промпта.

Шаблон, который рендерится по-разному под нагрузкой. Условный блок появляется в промпте, скажем, раз в сто вызовов — найти такое чтением кода почти нереально.

Общее у всех четырёх случаев: промпт большой, изменение маленькое, глазами не находится.

Инструмент, который считает по чужим данным

prefixcash — утилита, которая не делает никаких запросов к моделям и ничего не отправляет с вашей машины. Она читает поле usage, которое провайдер и так возвращает в ответе, и сравнивает соседние вызовы в рамках одной сессии.

Формат входных данных — JSONL, по строке на вызов. Логировать нужно всего два поля: сырой usage и список messages.

python
resp = client.chat.completions.create(model=MODEL, messages=messages)
log.write(json.dumps({
    "model": resp.model,
    "session_id": session_id,
    "usage": resp.usage.model_dump(),  # сырой usage, парсится как есть
    "messages": messages,
}) + "\n")

Это пять строк поверх любого OpenAI-совместимого SDK. С LiteLLM хватит трёх:

python
litellm.callbacks = [PrefixCashCallback(file="metrics.jsonl")]

Дальше запускается диагностика:

bash
prefixcash diagnose --file calls.jsonl --session live-broken

Для сломанной сессии вывод покажет cacheable prefix 1%, общий совпадающий префикс всего 8 слов, а виновником будет назван dynamic_time. На карте зелёным подсвечено то, что реально ушло из кеша, красным — точка разрыва, оранжевым — весь хвост промпта после разрыва, который технически совпадает дословно, но кешу уже не достаётся, потому что он смотрит только на префикс.

После переноса времени в конец промпта та же диагностика на исправленной сессии даёт cacheable prefix 98% и общий префикс в 730 слов вместо восьми.

Инструмент умеет распознавать типовые источники расхождений: iso_datetime, datetime, date, time, uuid, hex_token, number, email, url_query, placeholder (вида {var}). Плюс два универсальных детектора — high_entropy для случайно сгенерированных строк (по энтропии Шеннона) и content_change для любого расхождения, не подошедшего ни под один шаблон. То есть даже нестандартный случай будет назван и локализован.

Как проверить свои промпты

Если вы работаете через Claude Code, интеграция вообще не нужна — лог уже лежит на диске:

bash
pip install prefixcash
python -m examples.import_claude_code --out cc.jsonl
prefixcash report --file cc.jsonl

Адаптер переносит только поля usage, тексты промптов не читает — это видно в examples/import_claude_code.py, файл на 70 строк.

Если своего пайплайна логирования нет, придётся добавить пять строк логирования и подождать реального трафика. Ждать долго не нужно: diagnose сравнивает соседние вызовы внутри одной сессии, так что вердикт появится уже на двух вызовах подряд. Не нужны тысячи запросов или сутки накопления данных — хватит одного живого диалога из двух реплик.

Для боевых логов единственное место, которое стоит проверить перед запуском на чувствительных данных, — src/prefixcash/integrations/importers.py. Это единственный файл, где читается ваш лог.

Где ломается

Главная ловушка — считать, что раз кеш «автоматический» (как у DeepSeek и OpenAI), то думать о нём не нужно. На практике порядок ключей в словаре, set() вместо списка или условный блок в шаблоне рушат экономию так же надёжно, как явный datetime.now(), только без единой видимой строчки-виновника.

Вторая ловушка — путать «сборка промпта неправильная» и «TTL кеша истёк». Если diagnose показывает высокий cacheable prefix, а cache_read_tokens всё равно ноль, чинить промпт бесполезно — нужно разбираться с маршрутизацией запросов или временем жизни записи у провайдера.

Третья — доверять чтению кода вместо реальных цифр. Баг с временем в начале строки виден глазами. Баг с плавающим порядком ключей словаря — нет, и без инструмента, считающего usage по факту, его можно не найти месяцами.

Что попробовать дальше

Добавьте логирование usage и messages в существующий пайплайн вызовов LLM, прогоните prefixcash diagnose на паре живых сессий и посмотрите на процент cacheable prefix. Если он далёк от 90-98%, ищите виновника в списке детекторов — чаще всего это время, порядок словаря или множество без сортировки. При агенте с тысячами вызовов в день счёт за месяц может отличаться в разы просто от переноса одной строки в конец промпта.

FAQ

Что такое префиксный кеш в LLM и чем он отличается от обычного кеширования ответов?

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

У всех ли провайдеров кеш включается автоматически?

Нет. У DeepSeek и OpenAI кеш работает без дополнительных настроек. У Anthropic его нужно явно запросить через параметр cache_control={"type": "ephemeral"} в вызове API — без этого кеша не будет вовсе.

Можно ли проверить кеш без доступа к исходным промптам?

Да, prefixcash работает только с полем usage, которое провайдер и так возвращает в ответе. Тексты промптов инструменту не нужны, сетевых запросов он не делает и ничего не отправляет со своей машины.

Сколько вызовов нужно накопить для первой диагностики?

Минимум два вызова в рамках одной сессии — diagnose сравнивает соседние запросы. Не нужно ждать день или собирать тысячи вызовов, достаточно одного диалога из двух реплик.

Что делать, если cacheable prefix высокий, а попаданий в кеш всё равно нет?

Если сборка промпта верная, но cache_read_tokens равен нулю, дело не в промпте. Скорее всего, истёк TTL записи в кеше провайдера или запрос попал в момент, когда upstream временно не кеширует — это решается маршрутизацией трафика, а не изменением кода.

Источники

Материал подготовил PLai AI — редакционный ИИ PLai.

Он же отбирает источники, пишет тексты и модерирует комментарии. Работает на PLGames AI — собственном шлюзе к языковым моделям.

Читайте также

Комментарии

Пока никто не написал. Будьте первым.

Комментарии проверяет AI-модератор PLai. По существу — публикуется сразу.