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

# Руководство по контекстному кэшу Gemini

> Создавайте и повторно используйте контекстный кэш Gemini (Context Cache) через OpenAI-совместимый Chat Completions API или нативный Gemini API. Кэшируйте стабильный префикс с помощью cache_control, чтобы снизить затраты на токены при повторной передаче длинного контента.

В этом руководстве описано, как создавать и повторно использовать контекстный кэш Gemini (Context Cache) через OpenAI-совместимый Chat Completions API или нативный Gemini API.

Перед началом работы:

```bash theme={null}
export API_KEY="ваш API-ключ"
```

<Note>В примерах этого руководства используется `gemini-3.6-flash`. Сведения о поддержке Context Cache другими моделями см. в описании моделей и на странице цен платформы.</Note>

## Сценарии использования

Если в нескольких запросах многократно передаётся один и тот же большой фрагмент контента, можно кэшировать его стабильный префикс, например:

* очень длинный системный промпт
* неизменяемую базу знаний или документацию продукта
* стабильную историю сообщений в многошаговом диалоге
* многократно используемые определения и описания инструментов

Context Cache подходит для запросов, в которых «начальный контент остаётся неизменным, а последний вопрос постоянно меняется».

## Основное использование

Добавьте `cache_control` в content block последнего сообщения стабильного префикса:

```json theme={null}
{
  "type": "text",
  "text": "Это последний фрагмент стабильного префикса",
  "cache_control": {
    "type": "ephemeral",
    "ttl": "5m"
  }
}
```

Поддерживаемые значения TTL:

| TTL  | Значение               |
| ---- | ---------------------- |
| `5m` | кэширование на 5 минут |
| `1h` | кэширование на 1 час   |

<Note>Если `ttl` не указан, по умолчанию используется `5m`.</Note>

## Структура сообщений

Рекомендуется следующая структура:

```text theme={null}
system
→ стабильный длинный текст или история сообщений
→ граница стабильного префикса с cache_control
→ текущий вопрос пользователя (не кэшируется)
```

Сообщение с `cache_control` и все предшествующие ему сообщения образуют префикс кэша. После него должно оставаться как минимум одно актуальное сообщение.

## Пример OpenAI-совместимого запроса

```bash theme={null}
curl "https://api.apimart.ai/v1/chat/completions" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gemini-3.6-flash",
    "stream": false,
    "messages": [
      {
        "role": "system",
        "content": "Отвечайте на вопросы строго на основе предоставленных справочных материалов."
      },
      {
        "role": "user",
        "content": "Здесь размещается длинный справочный материал для многократного использования……"
      },
      {
        "role": "assistant",
        "content": [
          {
            "type": "text",
            "text": "Я прочитал и понял приведённые выше справочные материалы.",
            "cache_control": {
              "type": "ephemeral",
              "ttl": "5m"
            }
          }
        ]
      },
      {
        "role": "user",
        "content": "Кратко изложите три ключевых положения справочных материалов."
      }
    ]
  }'
```

При первой отправке система попытается создать кэш и обработает текущий запрос с использованием нового кэша.

<Note>Отдельно вызывать API создания кэша не нужно. `cache_control` одновременно задаёт «границу кэша» и «срок действия кэша».</Note>

## Пример нативного запроса Gemini

Нативный интерфейс Gemini `generateContent` также позволяет добавлять `cache_control` в `contents[].parts[]`:

```bash theme={null}
curl "https://api.apimart.ai/v1beta/models/gemini-3.6-flash:generateContent" \
  -H "x-goog-api-key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "systemInstruction": {
      "parts": [
        {
          "text": "Отвечайте на вопросы строго на основе предоставленных справочных материалов."
        }
      ]
    },
    "contents": [
      {
        "role": "user",
        "parts": [
          {
            "text": "Здесь размещается длинный справочный материал для многократного использования……"
          }
        ]
      },
      {
        "role": "model",
        "parts": [
          {
            "text": "Я прочитал и понял приведённые выше справочные материалы.",
            "cache_control": {
              "type": "ephemeral",
              "ttl": "5m"
            }
          }
        ]
      },
      {
        "role": "user",
        "parts": [
          {
            "text": "Кратко изложите три ключевых положения справочных материалов."
          }
        ]
      }
    ]
  }'
```

`cache_control` — это поле, которым платформа расширяет формат запросов Gemini. Распознав границу, платформа удаляет это поле перед переадресацией и автоматически создаёт либо повторно использует кэшированный контент (`cachedContent`).

Для потокового интерфейса используется то же тело запроса; достаточно изменить URL:

```bash theme={null}
curl -N "https://api.apimart.ai/v1beta/models/gemini-3.6-flash:streamGenerateContent?alt=sse" \
  -H "x-goog-api-key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "contents": [
      {
        "role": "user",
        "parts": [
          {
            "text": "Здесь размещается длинный справочный материал для многократного использования……",
            "cache_control": {
              "type": "ephemeral",
              "ttl": "5m"
            }
          }
        ]
      },
      {
        "role": "user",
        "parts": [
          {
            "text": "Кратко изложите три ключевых положения справочных материалов."
          }
        ]
      }
    ]
  }'
```

При повторном использовании не изменяйте `systemInstruction`, `contents` перед границей, TTL и tools; изменяйте только актуальный контент после границы.

## Процесс создания и повторного использования

При первой отправке запроса с `cache_control`:

```text theme={null}
Распознавание стабильного префикса
→ Создание Context Cache
→ Ссылка на новый кэш в текущем запросе
→ Возврат результата модели
```

При повторной отправке того же стабильного префикса:

```text theme={null}
Распознавание того же стабильного префикса
→ Повторное использование действующего Context Cache
→ Отправка только текущего актуального контента
→ Возврат результата модели
```

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

## Повторное использование кэша

При повторном запросе не изменяйте:

* модель
* все сообщения перед `cache_control`
* `cache_control.ttl`
* определения инструментов (если используются tools)
* `systemInstruction` в нативном запросе Gemini

Изменяйте только актуальный вопрос после границы:

```json theme={null}
{
  "role": "user",
  "content": "Какие риски упоминаются в справочных материалах?"
}
```

Если стабильный префикс совпадает, а срок действия кэша не истёк, система повторно использует существующий кэш.

Следующие изменения приведут к созданию другого кэша:

* изменение текста или порядка сообщений в стабильном префиксе
* смена модели
* изменение `5m` на `1h`
* изменение tools или определений параметров инструментов
* использование другого пользователя API или канала

## Пример на Python

```python theme={null}
from openai import OpenAI

client = OpenAI(
    api_key="YOUR_API_KEY",
    base_url="https://api.apimart.ai/v1",
)

stable_messages = [
    {
        "role": "system",
        "content": "Отвечайте на вопросы строго на основе предоставленных справочных материалов.",
    },
    {
        "role": "user",
        "content": "Здесь размещается длинный справочный материал для многократного использования……",
    },
    {
        "role": "assistant",
        "content": [
            {
                "type": "text",
                "text": "Я прочитал и понял приведённые выше справочные материалы.",
                "cache_control": {
                    "type": "ephemeral",
                    "ttl": "5m",
                },
            }
        ],
    },
]

response = client.chat.completions.create(
    model="gemini-3.6-flash",
    messages=[
        *stable_messages,
        {
            "role": "user",
            "content": "Кратко изложите три ключевых положения справочных материалов.",
        },
    ],
)

print(response.choices[0].message.content)
print(response.usage)
```

В последующих запросах повторно используйте тот же `stable_messages`, заменяя только последнее сообщение user.

## Проверка попадания в кэш

### OpenAI-совместимый ответ

Проверьте следующие поля ответа:

```json theme={null}
{
  "usage": {
    "prompt_tokens": 14430,
    "prompt_tokens_details": {
      "cached_tokens": 14420,
      "cache_write_tokens": 0
    }
  }
}
```

Описание полей:

| Поле                 | Значение                                                   |
| -------------------- | ---------------------------------------------------------- |
| `prompt_tokens`      | все входные токены текущего запроса                        |
| `cached_tokens`      | входные токены текущего запроса, прочитанные из кэша       |
| `cache_write_tokens` | токены, записанные в кэш; значение `0` является нормальным |

Даже при первом запросе значение `cached_tokens` может быть большим, поскольку система может сначала создать кэш, а затем сослаться на него в рамках того же вызова модели.

### Нативный ответ Gemini

Проверьте `usageMetadata.cachedContentTokenCount` в ответе:

```json theme={null}
{
  "usageMetadata": {
    "promptTokenCount": 13926,
    "cachedContentTokenCount": 13916,
    "totalTokenCount": 13954
  }
}
```

Описание полей:

| Поле                      | Значение                                                     |
| ------------------------- | ------------------------------------------------------------ |
| `promptTokenCount`        | все входные токены текущего запроса                          |
| `cachedContentTokenCount` | входные токены текущего запроса, прочитанные из кэша         |
| `totalTokenCount`         | общее количество входных и выходных токенов текущего запроса |

`streamGenerateContent` возвращает те же данные `usageMetadata` в кадре SSE-ответа. Клиент должен прочитать кадр ответа, содержащий это поле, а не проверять только первый текстовый фрагмент.

## Рекомендации

<Tip>
  1. Кэшируйте только действительно стабильный длинный контент, который будет использоваться многократно.
  2. Размещайте изменяющийся при каждом запросе вопрос после границы `cache_control`.
  3. Не добавляйте в стабильный префикс временные метки, случайные ID или динамические сведения о пользователе.
  4. Если ожидаются повторные вызовы в течение короткого времени, используйте `5m`.
  5. Если требуется более длительный период повторного использования, выберите `1h`.
  6. Если префикс слишком короткий, модель не поддерживается или кэш временно недоступен, запрос может быть автоматически выполнен в обычном режиме.
  7. В нативном формате Gemini граница кэша должна находиться в `contents[].parts[]`, а не в `systemInstruction`.
</Tip>

## Часто задаваемые вопросы

<AccordionGroup>
  <Accordion title="Можно ли автоматически создать кэш в нативном формате запросов Gemini?">
    Да. `generateContent` и `streamGenerateContent` используют одну и ту же структуру `cache_control`. Граница должна находиться в `contents[].parts[]`, а после content с границей должен оставаться как минимум один актуальный content.

    Если в запросе явно указано имя нативного ресурса `cachedContent`, платформа отдаёт приоритет предоставленному пользователем ресурсу и не выполняет автоматическое создание кэша.
  </Accordion>

  <Accordion title="Почему запрос не попал в кэш?">
    Распространённые причины:

    * стабильный префикс не полностью совпадает с предыдущим запросом
    * срок действия TTL истёк
    * модель или tools были изменены
    * объём кэшируемого контента не достиг минимального количества токенов, требуемого моделью
    * `cache_control` находится в последнем сообщении, поэтому актуального вопроса после него нет
  </Accordion>

  <Accordion title="Можно ли поместить cache_control в последнее сообщение?">
    Не рекомендуется. Последнее сообщение обычно содержит текущий актуальный вопрос и не должно кэшироваться. Если после границы нет актуального сообщения, запрос выполняется в обычном режиме.
  </Accordion>

  <Accordion title="Можно ли задать другое значение TTL?">
    Нет. Сейчас поддерживаются только `5m` и `1h`. Другие значения приводят к ответу HTTP 400.
  </Accordion>

  <Accordion title="Можно ли задать несколько границ кэша?">
    Да, но для всех границ должен использоваться один и тот же TTL, а система выберет последнюю границу. Обычно рекомендуется задавать только одну границу на запрос, чтобы сохранить понятную структуру.
  </Accordion>

  <Accordion title="Приведёт ли недоступность кэша к ошибке запроса?">
    Обычно нет. Если условия создания или повторного использования кэша не выполнены, система автоматически отправляет обычный запрос. Исключения — ошибки параметров, такие как недопустимый TTL или одновременное использование разных TTL.
  </Accordion>

  <Accordion title="Что произойдёт, если для модели не включён Context Cache?">
    Запрос автоматически выполняется в обычном режиме без создания явного кэша и платы за его хранение. Обычные входные и выходные данные, а также возможный неявный кэш продолжают тарифицироваться по стандартным правилам этой модели.
  </Accordion>

  <Accordion title="Почему cache_write_tokens равен 0?">
    Это нормальное поведение контекстного кэша Gemini. Стоимость создания кэша учитывается как отдельная плата за его хранение; для обозначения объёма созданного кэша не используется `cache_write_tokens` в стиле OpenAI/Claude.
  </Accordion>

  <Accordion title="Означает ли cached_tokens больше 0, что явный кэш точно был создан?">
    Не обязательно. Может сработать и собственный неявный кэш системы. Обычный пользователь может определить применение чтения из кэша по количеству прочитанных из него токенов. Чтобы проверить стоимость создания явного кэша, найдите запись Context Cache storage в журнале расходов платформы.
  </Accordion>

  <Accordion title="Как тарифицируется кэш?">
    При создании кэша может однократно взиматься плата за его хранение. При использовании кэша попавшие в него токены тарифицируются по цене чтения из кэша. Актуальные цены указаны в тарифах соответствующей модели на платформе.
  </Accordion>
</AccordionGroup>
