lenec ru

← все посты

Claude API с кэшированием промптов: практический гайд

18K

Год назад я бы написал статью «как уменьшить счёт от Anthropic в два раза», но тема устарела: с Claude API кэширование стало обыденностью, и любой живой проект обязан его включить. Расскажу, как это устроено технически, на что обращать внимание и где у меня грабли.

Что вообще кэшируется

Claude API кэширует префиксы. Запрос состоит из system, tools, messages — и всё это идёт в модель в виде одной длинной последовательности токенов. Кэш можно поставить на любую точку этой последовательности, и Anthropic запоминает посчитанное «состояние» модели до этой точки.

На следующих запросах с тем же префиксом Anthropic берёт это состояние из кэша и доделывает только остаток. Платишь за чтение из кэша — это в разы дешевле обычного входа.

Кэш работает по точному совпадению: одна лишняя запятая или пробел — кэш не сработает. Это важно: если у тебя в system-промпте текущая дата, кэш будет инвалидироваться каждый день.

Базовый пример

import Anthropic from '@anthropic-ai/sdk';

const client = new Anthropic();

const response = await client.messages.create({
  model: 'claude-sonnet-4-5',
  max_tokens: 1024,
  system: [
    {
      type: 'text',
      text: VERY_LONG_SYSTEM_PROMPT, // 8 000 токенов
      cache_control: { type: 'ephemeral' }
    }
  ],
  messages: [
    { role: 'user', content: userInput }
  ]
});

console.log(response.usage);
// первый раз:
//   input_tokens: 12
//   cache_creation_input_tokens: 8000
//   cache_read_input_tokens: 0
// второй раз:
//   input_tokens: 12
//   cache_creation_input_tokens: 0
//   cache_read_input_tokens: 8000

Первый запрос дороже обычного на ~25%, потому что запись в кэш стоит чуть больше. Второй и далее — в 10 раз дешевле обычного входа.

Где ставить точки кэша

В одном запросе можно поставить до 4 точек cache_control. Я обычно ставлю в таком порядке:

  1. В конце system-промпта.
  2. В конце tools.
  3. На последнем сообщении предыдущего разговора (для длинных диалогов).

Каждая точка кэша означает «всё до меня и я сам — кэшируется». Можно делать «слоистый» кэш: меняется только последний кусок, а 90% префикса берётся из кэша.

TTL — 5 минут или 1 час

По умолчанию кэш живёт 5 минут с момента последнего использования. С 2024 года Anthropic дал опцию «кэш на 1 час» — он стоит дороже при записи, но если у тебя редкие, но дорогие запросы — это окупается.

cache_control: { type: 'ephemeral', ttl: '1h' }

Я держу 1h-кэш на admin-панелях продукта: туда заходят редко, но system-промпт у меня тяжёлый.

Tools тоже кэшируются

Это упускают чаще всего. Если у тебя 15 инструментов с подробными schemas — это легко 4–6к токенов. Без кэша ты их платишь на каждом запросе.

const tools = TOOL_DEFS.map((t, i, arr) => ({
  ...t,
  // последний tool помечаем cache_control,
  // он распространяется на ВСЕ tools и system перед ним
  ...(i === arr.length - 1 ? { cache_control: { type: 'ephemeral' } } : {})
}));

Минимальный размер

Кэшируется только префикс длиной от 1024 токенов (Sonnet/Opus) или 2048 (Haiku). Если system у тебя 500 токенов — нет смысла ставить cache_control, оно не сработает. Это сделано, чтобы кэш не тратился на мелочи.

Метрики

В response.usage есть три поля по кэшу:

  • cache_creation_input_tokens — записано в кэш.
  • cache_read_input_tokens — прочитано из кэша.
  • input_tokens — обычные входные, мимо кэша.

Я кладу все три в свой Postgres и ежедневно строю простой отчёт «cache hit ratio». Если он ниже 70% — что-то с префиксом меняется чаще, чем нужно. Иду смотреть.

Где у меня были грабли

1. В system-промпт случайно затёк текущий timestamp. Кэш инвалидировался каждую секунду. Поймал на счёте — он не упал. Перенёс таймстемп в user-сообщение, кэш заработал.

2. Пользователь зашёл и сделал один запрос. Через 7 минут — следующий. 5-минутный TTL истёк, кэш пересоздан. Подумал — поставил TTL 1h на сценариях с редкими запросами. Стало лучше.

3. В диалоговом интерфейсе я отправлял всю историю сообщений. После 30 сообщений вход растёт до 30к токенов. Без cache_control на последнем сообщении предыдущего хода я платил за 30к на каждом запросе. С cache_control — за 30к один раз, потом за пару сотен токенов нового сообщения.

Когда не стоит кэшировать

  • Очень короткие префиксы. Не сработает или не окупится.
  • Префиксы, которые меняются в каждом запросе (например, RAG-документы для конкретного юзера, которые свои каждый раз).
  • Тестирование/отладка. На стейдже проще без кэша, чтобы видеть полный счёт и не путать «промпт работает» с «промпт случайно совпал».

Что в итоге

Если у тебя Claude API в проде и ты не настроил кэш промптов — ты переплачиваешь, иногда в 3–5 раз. Кэш ставится одной строкой cache_control: { type: 'ephemeral' }, главное — стабильный префикс и достаточная длина. Замеряй cache hit ratio и счёт до/после, и не забывай про TTL и точку кэша на инструментах. Эти вещи окупаются за день.

Комментарии 0

  • Будьте первым, кто оставит комментарий.

Войдите, чтобы оставить комментарий.