У вашего AI-ассистента длинный системный промпт - с правилами компании, регламентами, базой знаний. Каждый запрос к нейросети пересчитывает этот промпт заново, и вы платите за одно и то же по многу раз. Если запросов много, расходы на AI могут съедать бюджет незаметно.
Prompt caching - кеширование длинных частей промпта - решает это. Сервер сохраняет вычисления для повторяющейся части и при следующем запросе читает их из кеша вместо пересчёта. Результат: экономия до 90% стоимости входных токенов и ускорение ответа на 20-40%.
Разберём на примере стройфирмы. У вас есть ассистент для менеджеров: он помогает отвечать на вопросы по типовым договорам, СНиПам и прайсам. Системный промпт - 10 000 токенов. Менеджеры задают 1000 вопросов в день. Без кеша вы платите за 10 миллионов токенов в день - это $30 на Claude Sonnet. С кешем - около $3.20. Экономия 89%. При 10 000 запросов в день - $8 100 в месяц. Это не гипотетика, это прямая экономия.
Типичные кандидаты на кеширование: промпт юридического ассистента с текстом регламентов (5 000-20 000 токенов), промпт службы поддержки с базой часто задаваемых вопросов (3 000-10 000 токенов), промпт для анализа документов с примерами правильного разбора (2 000-5 000 токенов). Во всех этих случаях кеш окупается буквально с третьего запроса.
Как это работает технически (простыми словами)
Когда языковая модель обрабатывает промпт, она вычисляет внутреннее состояние для каждого токена (токен - это примерно 0.75 слова). Это вычисление занимает время и стоит денег. При prompt caching сервер сохраняет это состояние для фиксированной части промпта. Когда приходит новый запрос с такой же начальной частью - сервер не пересчитывает, а читает из сохранённого состояния. Переменная часть (конкретный вопрос пользователя) обрабатывается как обычно.
Запись в кеш стоит немного дороже обычного: у Anthropic - в 2 раза дороже, у OpenAI - на 25% дороже. Чтение из кеша - 10% от базовой цены у обоих. Точка окупаемости: если одинаковый промпт отправляется 2-3 раза, кеш уже выгоден.
Явное кеширование в Claude: cache_control
Anthropic требует явно указывать, какие блоки промпта кешировать. Это делается через поле cache_control в структуре запроса.
Следующий код отправляет запрос с длинным системным промптом, помеченным для кеширования. После запроса проверяем статистику: сколько токенов записано в кеш, сколько прочитано из него:
import anthropic
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
system=[
{
"type": "text",
"text": "Ты юридический ассистент по трудовому праву России. [5000+ токенов нормативной базы...]",
"cache_control": {"type": "ephemeral"}
}
],
messages=[{"role": "user", "content": "Как правильно уволить сотрудника?"}]
)
print(f"Записано в кеш: {response.usage.cache_creation_input_tokens}")
print(f"Прочитано из кеша: {response.usage.cache_read_input_tokens}")
print(f"Обычные токены: {response.usage.input_tokens}")
Первый запрос: cache_creation_input_tokens больше нуля, cache_read_input_tokens равен нулю - кеш создаётся. Второй запрос с тем же системным промптом: cache_read_input_tokens больше нуля - кеш сработал.
Время жизни кеша по умолчанию - 5 минут. Для часового кеша:
"cache_control": {"type": "ephemeral", "ttl": "1h"}
5 минут - для высокочастотных сервисов (более одного запроса в минуту). 1 час - для периодических задач, где запросы идут реже.
Минимальный размер блока
Кешировать можно только достаточно большие блоки. Если блок меньше минимума, cache_control игнорируется без предупреждения.
| Модель | Минимум токенов |
|---|---|
| claude-sonnet-4-6 | 1024 |
| claude-opus-4-7 | 1024 |
| claude-haiku-4-5 | 2048 |
Если cache_creation_input_tokens равен нулю при первом запросе - блок слишком короткий. Проверьте размер заранее:
token_count = client.messages.count_tokens(
model="claude-sonnet-4-6",
messages=[{"role": "user", "content": your_text}]
)
print(f"{token_count.input_tokens} токенов")
Если системный промпт у вас короче 1024 токенов (около 750 слов) - рассмотрите добавление структурированной базы знаний или расширенных инструкций, чтобы добраться до порога.
Порядок кеширования в Claude
Кеш строится до последнего блока с cache_control включительно. Порядок обработки: сначала tools (описания функций), потом system, потом messages. Это важно для понимания что именно попадёт в кеш.
Следующий код кеширует одновременно системный промпт и большой документ в сообщениях. Первый вопрос записывает кеш для обоих блоков, следующие вопросы по тому же документу читают из него:
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=2048,
system=[
{
"type": "text",
"text": STABLE_INSTRUCTIONS,
"cache_control": {"type": "ephemeral"}
}
],
messages=[
{
"role": "user",
"content": [
{
"type": "text",
"text": LARGE_DOCUMENT_TEXT,
"cache_control": {"type": "ephemeral"}
},
{
"type": "text",
"text": "Какой главный вывод в этом документе?"
}
]
}
]
)
Автоматический кеш в OpenAI
OpenAI не требует явных аннотаций. Кеш включён автоматически для всех поддерживаемых моделей (gpt-4o и новее). Промпт длиннее 1024 токенов - кеш активируется сам.
Следующий код отправляет обычный запрос. OpenAI автоматически кеширует начало промпта. Проверить результат можно через prompt_tokens_details:
from openai import OpenAI
client = OpenAI()
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": LONG_SYSTEM_PROMPT},
{"role": "user", "content": user_question}
]
)
cached = response.usage.prompt_tokens_details.cached_tokens
print(f"Кешировано: {cached} токенов")
Условия автокеша OpenAI: промпт больше 1024 токенов, кеширование с шагом 128 токенов, начало промпта должно совпадать между запросами.
Для расширенного хранения кеша до 24 часов:
response = client.chat.completions.create(
model="gpt-4o",
messages=[...],
extra_body={"prompt_cache_retention": "24h"}
)
Кеширование документов для анализа
Кеш полезен не только для системных промптов. Если один и тот же большой документ нужно проанализировать с разных сторон, кешируйте его и задавайте несколько вопросов.
Разберём на примере юридической компании, которая проверяет договор по нескольким критериям. Договор на 50 страниц (около 15 000 токенов) кешируется один раз, потом по нему задаётся 10 вопросов. Экономия - 90% стоимости входных токенов по сравнению с отдельными запросами. При цене $3 за миллион токенов и 15 000 токенов документа: без кеша - $0.045 * 10 вопросов = $0.45. С кешем - $0.045 (запись) + $0.0045 * 9 = $0.085. Экономия 81% уже на 10 вопросах.
Следующий код реализует именно такой сценарий: один документ, несколько вопросов, кеш работает начиная со второго вопроса:
def ask_document(client, document_text: str, questions: list):
results = []
for question in questions:
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
messages=[
{
"role": "user",
"content": [
{
"type": "text",
"text": document_text,
"cache_control": {"type": "ephemeral"}
},
{
"type": "text",
"text": question
}
]
}
]
)
results.append(response.content[0].text)
return results
answers = ask_document(client, LONG_CONTRACT_TEXT, [
"Какой срок действия договора?",
"Какова сумма неустойки?",
"Кто несёт ответственность за просрочку?"
])
Стратегия максимизации попаданий в кеш
Кеш работает только при точном совпадении начала промпта. Один лишний символ - промах. Несколько правил.
Стабильное начало: длинный неизменяемый системный промпт ставьте в начало. Изменяемые части (имя пользователя, текущая дата, конкретный запрос) - в конец или в messages. Любое изменение хоть одного символа в кешируемой части сбрасывает кеш.
Фиксированный порядок инструментов: если используете function calling (описания функций доступных модели), порядок описаний должен быть одинаковым между запросами. Перестановка - промах.
Следующий пример показывает разницу: случайный порядок инструментов ломает кеш, алфавитный - обеспечивает стабильность:
# Плохо: порядок меняется между запросами
tools = sorted(get_tools(), key=lambda t: random.random())
# Хорошо: стабильный порядок
tools = sorted(get_tools(), key=lambda t: t["name"])
Измеряйте попадаемость. Целевой показатель для боевой среды - 80% и выше:
hit_rate = cache_read / (cache_read + regular_input + cache_creation)
print(f"Попадаемость кеша: {hit_rate:.1%}")
Если попадаемость ниже 60% - скорее всего, в кешируемой части промпта есть изменяемые данные. Проверьте, не вставляется ли туда дата, имя пользователя или другой динамический контент.
Кеширование в многоходовых диалогах
Ещё один важный сценарий - длинные диалоги. Каждый новый ответ пользователя добавляет токены к истории разговора. Если история не кешируется, вы платите за все предыдущие сообщения при каждом запросе.
При 20-ходовом диалоге и среднем сообщении в 100 токенов: к 20-му ходу история накапливает 2000 токенов только от пользователя. Плюс 2000 от ассистента. Плюс системный промпт. Итого 5000+ токенов за которые платите каждый раз.
С кешированием истории диалога: помечаете последнее сообщение в истории как точку кеширования. Всё до него обрабатывается из кеша, только новое сообщение - обычным способом.
Следующий код показывает как кешировать историю диалога. Каждый новый ход добавляет одно сообщение и помечает предыдущую историю для кеширования:
def chat_with_caching(client, history: list, new_user_message: str) -> str:
# Помечаем последнее сообщение в истории для кеширования
messages_with_cache = []
for i, msg in enumerate(history):
if i == len(history) - 1:
# Последнее историческое сообщение - добавляем cache_control
content = msg["content"]
if isinstance(content, str):
content = [{"type": "text", "text": content,
"cache_control": {"type": "ephemeral"}}]
messages_with_cache.append({"role": msg["role"], "content": content})
else:
messages_with_cache.append(msg)
# Добавляем новый запрос пользователя (без кеширования - он новый)
messages_with_cache.append({"role": "user", "content": new_user_message})
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
system=[{"type": "text", "text": SYSTEM_PROMPT,
"cache_control": {"type": "ephemeral"}}],
messages=messages_with_cache
)
# Добавляем ответ в историю для следующего хода
history.append({"role": "user", "content": new_user_message})
history.append({"role": "assistant", "content": response.content[0].text})
return response.content[0].text
В длинном диалоге экономия от кеширования истории сопоставима с экономией на системном промпте - или даже больше, если история становится длиннее системного промпта.
Сравнение кеширования у Anthropic и OpenAI
Ключевые различия между двумя провайдерами:
Anthropic требует явной разметки через cache_control. Это даёт полный контроль - вы точно знаете что кешируется. OpenAI делает это автоматически для промптов длиннее 1024 токенов - удобнее, но меньше контроля.
Время жизни кеша: у Anthropic по умолчанию 5 минут с опцией до 1 часа. У OpenAI - стандартно несколько минут, с расширением до 24 часов через параметр prompt_cache_retention. Если ваши запросы идут реже одного раза в 5-10 минут - уточните у провайдера фактическое время жизни для вашего тарифного плана.
Цена записи в кеш: Anthropic берёт в 2 раза больше обычной цены за первый запрос. OpenAI - на 25% больше. Это имеет значение при редких запросах с коротким временем жизни кеша.
Для большинства приложений с высокочастотными запросами разница несущественна: кеш окупается с 2-3 повторного использования при любом провайдере.
Типичные ошибки
Изменяемые данные в кешируемой части. Текущая дата, имя пользователя, идентификатор сессии - всё это не должно находиться в кешируемом блоке. Такие данные каждый раз разные, кеш никогда не сработает.
Блок меньше минимума. Если системный промпт короче 1024 токенов для Claude, кеш не создаётся. Проверяйте cache_creation_input_tokens при первом запросе - если ноль, блок слишком короткий.
Ошибка с лимитами. Токены из кеша всё равно считаются в лимит токенов в минуту. Скидка только на стоимость, не на лимиты скорости.
Частые вопросы
Кеш сбрасывается если добавить один символ в системный промпт?
Да. Кеш завязан на точное побайтовое совпадение начала промпта. Один лишний пробел или изменение формулировки - промах. Изменяемые данные держите в конце запроса.
Как узнать, что кеш сработал?
Anthropic: response.usage.cache_read_input_tokens больше нуля. OpenAI: response.usage.prompt_tokens_details.cached_tokens больше нуля. Если ноль при повторном идентичном запросе - кеш ещё не успел создаться или время жизни истекло.
Считается ли кешированный запрос в лимиты?
Да, токены из кеша считаются в лимит токенов в минуту. Планируйте лимиты исходя из полного числа токенов в запросах.
Работает ли кеш при потоковой передаче?
Да. Потоковая передача и кеш независимы. cache_control в блоках работает вне зависимости от stream=True. Статистика о кеше доступна в финальном событии потока.
Можно ли кешировать не только системный промпт, но и документ в сообщениях?
Да, именно так работает пример с ask_document. Любой блок в messages с cache_control кешируется. Главное - он должен быть не короче минимального размера и стоять до изменяемых частей запроса.
Что дальше
Следующий шаг - MCP Server: как подключить инструменты к Claude. Также смотрите материалы по работе с большими документами в контексте и анализу данных. Все материалы - ai-uchebnik.ru.
AI Компас (t.me/kosmoslab_ai) - канал для предпринимателей в РФ и СНГ, которые применяют AI в своём бизнесе без программиста. Разбираем инструменты и схемы - без курсов и теории.