Мінус 90% до вартості повторюваних промптів одним рядком кешування
Як увімкнути автоматичне кешування промптів одним полем, перевірити влучання в блоці usage і не потрапити в пастки з префіксом і мінімальною довжиною, які непомітно з'їдають економію.
Знову платимо за текст, який не змінюється
Десь у вашому коді лежить шматок тексту, за який ви заплатили десять тисяч разів, хоча він жодного разу не змінився. Відкрийте панель використання й порівняйте вчорашні вхідні токени з кількістю запитів. Якщо співвідношення близьке до розміру вашого системного промпту, це про вас. Ви платили повну ціну за те, щоб знову й знову надсилати ту саму стіну інструкцій, а модель щоразу читала її з нуля, ніби бачить вас уперше.
Візьмімо бота підтримки, у якого в системному промпті близько 9000 токенів документів із правилами, і приблизно 40 000 викликів на місяць. Кожен виклик тягнув увесь цей блок мережею. Виправлення займає один рядок. Але є й пастка, через яку цей рядок нічого не дає, про неї нижче, і саме на ній більшість втрачає економію, яку, як їм здається, вони увімкнули.
На сервері ніщо не пам'ятає ваш контекст
Messages API не зберігає стан. Ніде не висить сесія, яка тримала б ваш промпт напоготові між викликами. Кожен запит збирає промпт заново, токенізує його, проганяє через модель і викидає результат. Наступний виклик повторює ту саму роботу за ту саму ціну.
without caching
call 1 [ 9,000 tok system ][ 40 tok question ] full price
call 2 [ 9,000 tok system ][ 35 tok question ] full price
call 3 [ 9,000 tok system ][ 52 tok question ] full price
^^^^^^^^^^^^^^^^^
same bytes, billed three times
Зміна в один рядок
Ось як цей виклик пише більшість:
resp = client.messages.create(
model="claude-sonnet-5",
max_tokens=1024,
system=DOCS,
messages=[{"role": "user", "content": q}],
)
А ось усе виправлення — одне додаткове поле над system:
cache_control={"type": "ephemeral"},
Це поле верхнього рівня вмикає автоматичне кешування. API ставить точку розриву на останній блок, який можна кешувати, і зсуває її вперед, коли діалог росте.
Перевірте блок usage
Не вірте відчуттю, що стало швидше. Дивіться дані про використання, які API повертає з кожною відповіддю:
creation read input
call 1 cold 9012 0 40
call 2 warm 0 9012 35
Уся суть у другому рядку. Дев'ять тисяч токенів віддано з кешу за десяту частину ціни, а input_tokens скоротилися до частини після точки розриву.
Пастка
Поставте на початок системного промпту мітку часу, ім'я користувача чи поточну дату, бо це здавалося безневинним, і префікс змінюватиметься в кожному запиті. Хеш ніколи не збігатиметься, ви безкінечно платитимете надбавку за запис і не отримаєте жодного читання. Це гірше, ніж нічого не робити.
Для API важливий фіксований порядок. Стабільний вміст іде першим, усе змінне — останнім:
tools -> system -> messages
[ stable stuff ----------------- | volatile ]
^
breakpoint lives here
Коли читань із кешу немає
Є мінімальна довжина, і якщо до неї не дотягнути, вам ніхто про це не скаже. Мінімум — 512 токенів для Opus 5, 1024 для Sonnet 5 і 4096 для Haiku 4.5. Нижче кешування немає, помилки теж немає, є лише рахунок, якого ви намагалися уникнути.
Кеш живе 5 хвилин і безкоштовно продовжується з кожним влучанням, тож рівний трафік сам тримає його теплим. Якщо виклики йдуть рідше, запросіть TTL на годину. І пам'ятайте, що збіг перевіряється до байта: один зайвий пробіл, переставлене визначення інструмента чи змінене налаштування повертають вас до повної ціни без жодного попередження.
Далі одного рядка
Згодом можна перейти на явні точки розриву і вішати cache_control на окремі блоки, їх дозволено чотири. Розумно ставити їх на визначення інструментів і в кінець документів: інструменти змінюються рідко, а документи — щотижня. Але все одно почніть з одного рядка: викотіть його, стежте за полями usage і лише потім мудруйте.
У циклах агентів ефект накопичується. Задача з десятьма викликами інструментів читає той самий префікс десять разів, тож до останнього проходу кешування вже не трохи заощаджує, а взагалі робить фічу доступною за ціною.