> ## Documentation Index
> Fetch the complete documentation index at: https://docs.apiyi.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Руководство Claude по кэшированию промптов

> Начните работу с Prompt Cache в нативном формате Anthropic: как писать запросы, пригодные для кэширования, как читать ваш счет и почему ваш процент попаданий равен нулю. Снижает стоимость до 90%.

Если вы используете Claude Code, Cline, Cursor или вручную пишете собственные вызовы Claude API, **кэширование промптов — самый эффективный способ снизить ваш счет** — входные token из кэша тарифицируются всего по **0.1×**, то есть со скидкой 90%.

Эта страница основана на официальной документации Anthropic (`docs.claude.com/en/docs/build-with-claude/prompt-caching`) и адаптирована под настройку APIYI с примерами, готовыми к копированию и вставке.

## В одном предложении

Пометьте **длинный, повторно используемый префикс prompt** (системные инструкции / длинный документ / few-shot примеры) с помощью `cache_control`. Сервер сохраняет его; при следующем запросе с тем же префиксом он пропускает повторную обработку — **примерно в 10× дешевле и быстрее**. Он истекает после периода неактивности.

## Зачем это нужно — посмотрите на коэффициенты

Относительно базовой цены входных token у модели (`1×`):

| Тип                            | Цена      | Примечания                             |
| ------------------------------ | --------- | -------------------------------------- |
| Обычный ввод                   | **1×**    | Все, что не кэшировано, по полной цене |
| Запись в кэш (TTL 5 минут)     | **1.25×** | Первая запись стоит на 25% дороже      |
| Запись в кэш (TTL 1 час)       | **2×**    | Платите больше, чтобы хранить дольше   |
| **Чтение из кэша (попадание)** | **0.1×**  | В этом и смысл. Дальше скидка 90%      |

**Точки безубыточности:**

* **TTL 5 минут**: достаточно всего **2 повторных использования** одного и того же префикса, чтобы выйти в ноль (1.25 + 0.1 = 1.35, дешевле, чем 2.0 за два запроса без кэша).
* **TTL 1 час**: нужно **3 повторных использования**, чтобы выйти в ноль (2 + 0.2 = 2.2, дешевле, чем 3.0).

<Info>
  TTL — это **скользящее окно**: каждое попадание в кэш сбрасывает таймер истечения, поэтому активные разговоры не истекают у вас под носом. Только реальное бездействие сверх TTL приводит к вытеснению.
</Info>

### Хорошо подходит

* Один и тот же длинный системный prompt вызывается много раз (агенты, чат-боты)
* Многоходовые разговоры (каждый предыдущий ход становится повторно используемым префиксом)
* Пакетная обработка одного документа (50 вопросов по одному контракту)
* RAG, где стабильные извлеченные фрагменты формируют префикс

### Плохо подходит

* Каждый prompt отличается с первой же буквы
* Все очень короткое и ни разу не превышает минимальный порог для конкретной модели (ниже)

## Три жестких требования

Все три обязательны.

### 1. Явный маркер `cache_control`

`content` не может быть простой строкой. Это должен быть **массив блоков содержимого**, с `cache_control`, прикрепленным к блоку, который вы хотите кэшировать:

```python theme={null}
# ❌ Wrong: plain string is never cached
"content": "a long passage..."

# ✅ Right: content block + cache_control
"content": [
    {
        "type": "text",
        "text": "a long passage...",
        "cache_control": {"type": "ephemeral"},
    },
    {"type": "text", "text": "the question"},
]
```

### 2. Длина должна превышать минимальное значение для каждой модели

Если содержимое короче минимума модели, **оно не будет кэшироваться даже с маркером** (ошибки не будет, просто будет пропущено без уведомления). Проверено по официальной документации Anthropic:

| Модель                      | Минимум tokens |
| --------------------------- | -------------- |
| Claude Sonnet 4.5           | 1,024          |
| Claude Sonnet 4.6           | 2,048          |
| Claude Opus 4.5 / 4.6 / 4.7 | 4,096          |
| Claude Haiku 4.5            | 4,096          |

<Tip>
  Английский текст в среднем составляет примерно 0.75 слова на token, поэтому для Sonnet 4.6 нужно около **1,500+ слов** стабильного содержимого, чтобы кэширование имело смысл. Всегда обращайтесь к официальной документации Anthropic за актуальными порогами — они могут меняться между версиями модели.
</Tip>

### 3. Префикс должен совпадать побайтно

Кэширование основано на **префиксе**: от начала запроса до маркера `cache_control` поток байтов должен быть **идентичным** предыдущему запросу. Любое изменение одного символа — пробельные символы, порядок ключей JSON, временная метка — считается новым префиксом и создает новую запись вместо попадания в кэш.

**Практическое правило: стабильные данные — в начале, изменчивые — в конце.**

```python theme={null}
# ❌ Wrong: question first means the prefix changes every turn; never hits
content = [
    {"type": "text", "text": "Please answer this question: " + question},  # volatile
    {"type": "text", "text": long_doc, "cache_control": {"type": "ephemeral"}},
]

# ✅ Right: long stable content first with marker, question after
content = [
    {"type": "text", "text": long_doc, "cache_control": {"type": "ephemeral"}},  # stable
    {"type": "text", "text": question},                                            # volatile
]
```

## Минимальный рабочий пример

Отправьте два запроса, используя один и тот же длинный документ, но разные вопросы. Первый записывает, второй попадает в кэш:

```python theme={null}
import json, os, requests

URL = "https://api.apiyi.com/v1/messages"
KEY = os.environ["APIYI_API_KEY"]
HEADERS = {
    "content-type": "application/json",
    "x-api-key": KEY,
    "anthropic-version": "2023-06-01",
}

# Must be long enough. Sonnet 4.6 needs >= 2,048 tokens (~1,500+ English words).
LONG_TEXT = open("long_document.txt").read()


def ask(question: str, label: str):
    payload = {
        "model": "claude-sonnet-4-6",
        "max_tokens": 256,
        "messages": [{
            "role": "user",
            "content": [
                {"type": "text", "text": LONG_TEXT, "cache_control": {"type": "ephemeral"}},
                {"type": "text", "text": question},
            ],
        }],
    }
    r = requests.post(URL, headers=HEADERS, data=json.dumps(payload), timeout=120)
    u = r.json().get("usage", {})
    print(f"[{label}] input={u.get('input_tokens')} "
          f"write={u.get('cache_creation_input_tokens')} "
          f"read={u.get('cache_read_input_tokens')}")


ask("Summarize the main idea", "1st")  # expect write>0, read=0
ask("Give 3 keywords",        "2nd")    # expect write=0, read>0
```

Ожидаемый вывод:

```text theme={null}
[1st] input=35 write=6512 read=0
[2nd] input=22 write=0    read=6512
```

Во втором вызове `read` ≈ в первом вызове `write` — тот же префикс используется повторно.

## Как определить, было ли попадание в кэш — три поля usage

В каждом ответе, `usage` сообщает:

| Поле                          | Значение                                  | Коэффициент тарификации |
| ----------------------------- | ----------------------------------------- | ----------------------- |
| `input_tokens`                | Входные tokens без кэша                   | 1×                      |
| `cache_creation_input_tokens` | tokens, записанные в кэш в этом вызове    | 1.25× или 2×            |
| `cache_read_input_tokens`     | tokens, прочитанные из кэша в этом вызове | **0.1×**                |

**Итого входные tokens = сумма всех трех.** Пока `cache_read_input_tokens > 0`, вы экономите деньги.

## Самые распространенные подводные камни

| Симптом                                                          | Причина                                                                                                                                                                        |
| ---------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `write` всегда `0` или поле отсутствует                          | Нет маркера `cache_control` / ниже минимального порога / использован формат, совместимый с OpenAI                                                                              |
| Во 2-м запросе по-прежнему есть `write > 0` и `read = 0`         | Префикс изменился. Частые причины: `datetime.now()`, UUID, периодически меняющиеся user ID в prompt; недетерминированная сериализация JSON; system prompt с временными метками |
| Сначала работало, а потом через некоторое время снова записывает | Простой дольше TTL. Используйте `{"type": "ephemeral", "ttl": "1h"}` для более длительного хранения                                                                            |
| Один и тот же prompt, другая модель — попадания нет              | Кэши изолированы по моделям. Переключение моделей = новый ключ кэша                                                                                                            |
| Недавние ходы в длинном разговоре не дают попадания              | Максимум **4** `cache_control` точки разбиения на запрос; каждая точка разбиения смотрит назад только на **20 блоков контента** для предыдущих записей кэша                    |

<Warning>
  **Кэширование промптов работает только с нативным форматом Anthropic (`/v1/messages`).** Когда вы вызываете Claude через формат, совместимый с OpenAI (`/v1/chat/completions`), поля кэша не вернутся независимо от того, что вы отправляете. Для Claude Code, Cline, Cursor и подобных клиентов с высокой частотой запросов нативный формат обязателен, если вы хотите контролировать свой счет.
</Warning>

## Продвинутое: многоходовые диалоги

Разместите `cache_control` на **последнем блоке контента последнего сообщения пользователя**. Каждый новый ход автоматически расширяет кэшированный диапазон чтения до конца предыдущего хода:

```python theme={null}
# When constructing the Nth turn's request
messages[-1]["content"][-1]["cache_control"] = {"type": "ephemeral"}
```

Два жёстких ограничения, о которых следует помнить:

* Не более **4** `cache_control` точек разрыва на запрос.
* Окно поиска префикса у каждой точки разрыва — **не более 20 блоков контента назад**; все, что старше, не будет учитываться при попадании в кэш. Иными словами, в очень длинных диалогах отметка только последнего хода не покроет всю предыдущую историю.

Распространенный шаблон: размещайте по одной точке разрыва на определениях инструментов, system prompt, длинных документах и последнем ходе диалога — используя все 4 слота, чтобы разделы, изменяющиеся с разной скоростью, не делали кэш друг друга недействительным.

## Об APIYI и кэшировании

<Info>
  **APIYI передает поля кэша сквозным образом.** `cache_control`, который вы отправляете, без изменений передается во upstream Claude (AWS Claude или Claude Official), а возвращаемые `cache_creation_input_tokens` / `cache_read_input_tokens` напрямую возвращаются вам — в вашем коде не требуется никакой специальной адаптации.
</Info>

Как проверить самостоятельно:

1. При первом запросе, `usage.cache_creation_input_tokens > 0` (запись выполнена).
2. Через несколько секунд отправьте тот же префикс еще раз — вы должны увидеть `usage.cache_read_input_tokens > 0` (попадание).
3. На панели тарификации будут отдельно указаны **cache writes** и **cache reads** с теми же официальными коэффициентами (1.25× / 2× / 0.1×).

## Краткое повторение

<CardGroup cols={2}>
  <Card title="1. Пометьте это" icon="tag">
    `cache_control: {"type": "ephemeral"}` на блоке контента — **обычная строка `content` никогда не кэшируется**.
  </Card>

  <Card title="2. Достаточно длинно" icon="ruler">
    Sonnet 4.6 ≥ 2,048 tokens; Opus 4.x / Haiku 4.5 ≥ 4,096 tokens, иначе пропускается без предупреждения.
  </Card>

  <Card title="3. Стабильный префикс" icon="lock">
    Стабильное в начале, изменчивое в конце; один символ расхождения убивает попадание в кэш.
  </Card>

  <Card title="4. Проверьте использование" icon="search">
    Только `cache_read_input_tokens > 0` доказывает, что вы действительно сэкономили.
  </Card>
</CardGroup>

## Связанные ссылки

* Родительская страница: [Основы Claude API](/ru/api-capabilities/claude)
* Руководства по настройке клиента: [Интеграция Claude Code](/ru/scenarios/programming/claude-code) · [Интеграция Cherry Studio](/ru/scenarios/chat/cherry-studio)
* Получение / управление token: `https://api.apiyi.com/token`
* Официальная документация Anthropic: `docs.claude.com/en/docs/build-with-claude/prompt-caching`
