Source: https://aiprimetech.io/ru/blog/prompt-caching-explained/ 17 июня, 2026 · 6 мин · API # Как работает кэширование промптов: когда оно экономит деньги, а когда нет A Автор: [AI Prime Tech](https://aiprimetech.io/ru/) · При участии ИИ В понедельник в 9:12 утра расходы на одного из наших агентов поддержки оказались на 4x выше ожидаемых. Модель не галлюцинировала, график трафика был верным, и никто случайно не переключился с Haiku на Opus. Проблема была проще: каждый запрос содержал одно и то же руководство по правилам объёмом 42,000 токенов, но доля попаданий в кэш промптов была фактически нулевой, потому что перед руководством мы добавляли новую временную метку и метаданные конкретного пользователя. То же содержимое. Та же модель. То же приложение. Никакой экономии от кэша. Кэширование промптов — одна из тех функций, которые кажутся автоматическими, пока вы не попытаетесь уменьшить счёт. На практике оно приносит пользу при вполне определённой структуре промпта: большом неизменном префиксе, который повторно используется во многих запросах. Если вы понимаете смысл этого предложения, то обычно можете предсказать, сэкономит ли кэширование деньги или незаметно окажется бесполезным. ## Что на самом деле кэшируется при кэшировании промптов Кэширование промптов — это не семантическая память. Провайдер не говорит: «Это похоже на то, что вы отправляли раньше». Скорее, логика такая: «Начало этого запроса достаточно точно совпадает с предыдущей последовательностью токенов с учётом модели и политики кэширования, поэтому мы можем повторно использовать внутренние вычисления для этого префикса». Это различие важно. Кэширование промптов обычно помогает, когда вы многократно отправляете один и тот же длинный префикс: - Системные инструкции - Схемы инструментов - Большие наборы документации - Каталоги продуктов - Контекст кодовой базы - Юридические документы или руководства по правилам - Примеры для обучения по нескольким образцам - Статические результаты поиска, повторно используемые во многих запросах Обычно оно мало помогает, если каждый запрос начинается по-разному: - Динамические временные метки в начале - Данные конкретного пользователя перед общим содержимым - Случайный порядок примеров - Уникальные UUID для каждого запроса внутри кэшируемого раздела - Фрагменты результатов поиска, у которых меняется порядок или форматирование - История чата перед неизменными инструкциями Ключевой инженерный приём — размещать неизменный контекст, обработка которого обходится дорого, в начале, а меняющийся контекст — после него. ## Anthropic и OpenAI: схожая цель, разные средства управления И Anthropic, и OpenAI поддерживают кэширование промптов, но удобство работы для разработчика различается. В Anthropic кэширование промптов управляется более явно. Вы можете помечать блоки содержимого параметрами управления кэшем, а затем проверять поля статистики использования, такие как cache_creation_input_tokens и cache_read_input_tokens. Так проще понять, создаёте ли вы записи кэша или читаете из них. В OpenAI кэширование промптов на поддерживаемых моделях более автоматизировано. При повторном использовании префикса промпта кэшированные входные токены могут тарифицироваться иначе и отражаться в метаданных использования. Обычно вы не задаёте явные границы кэширования таким же образом; вместо этого вы строите запросы так, чтобы повторно используемый префикс оставался неизменным на уровне байтов и токенов. Практическое различие — в соотношении контроля и удобства. | Параметр | Явное кэширование в стиле Anthropic | Автоматическое кэширование в стиле OpenAI | Контроль со стороны разработчика | Выше; можно помечать кэшируемые блоки | Ниже; провайдер обнаруживает повторно используемые префиксы | Удобство отладки | Обычно выше благодаря счётчикам создания и чтения кэша | Зависит от метаданных использования, доступных через модель или API | Значимость структуры промпта | Очень высокий | Очень высокий | Оптимальное применение | Большие статические блоки, инструменты, документация, примеры | Длинные префиксы, повторно используемые при последовательных вызовах | Типичная причина сбоя | Граница кэширования размещена после динамического содержимого | Префикс меняется до того, как удаётся найти совпадение в кэше | Мысленная модель | «Я записываю и читаю префикс, у которого есть своего рода имя» | «Провайдер распознаёт этот повторяющийся префикс» Детали реализации зависят от модели и провайдера и продолжают меняться. Но архитектурное правило остаётся неизменным: кэширование опирается на повторяющиеся префиксы, а не на похожие промпты. ## Модель ценообразования: создание и чтение Чтобы разобраться в кэшировании промптов, удобно разделить входные токены на три категории: - Обычные входные токены: тарифицируются по обычной цене входных токенов. - Токены создания кэша: токены, используемые для создания записи кэша; часто тарифицируются с наценкой или по специальной ставке записи. - Токены чтения кэша: токены, считываемые из существующей записи кэша; обычно тарифицируются по сниженной ставке. Anthropic напрямую отражает это различие в полях статистики использования, таких как: ``` { "usage": { "input_tokens": 812, "cache_creation_input_tokens": 42000, "cache_read_input_tokens": 0, "output_tokens": 684 } } ``` Если в последующем запросе префикс найден в кэше, вы хотите увидеть примерно следующее: ``` { "usage": { "input_tokens": 936, "cache_creation_input_tokens": 0, "cache_read_input_tokens": 42000, "output_tokens": 711 } } ``` Первый вызов создаёт кэш. Последующие вызовы читают из него. Экономический эффект зависит от текущих цен провайдера, TTL кэша и модели. Поскольку цены меняются, я предпочитаю моделировать это с помощью переменных в коде, а не жёстко задавать числа в проектной документации. Вот небольшая функция на Python, которую я использую, когда решаю, стоит ли внедрять кэширование для конкретного маршрута: ``` def cache_savings( cached_tokens: int, normal_input_per_mtok: float, cache_write_per_mtok: float, cache_read_per_mtok: float, requests: int, ) -> dict: mtok = cached_tokens / 1_000_000 no_cache = requests * mtok * normal_input_per_mtok with_cache = ( mtok * cache_write_per_mtok + (requests - 1) * mtok * cache_read_per_mtok ) return { "no_cache": round(no_cache, 6), "with_cache": round(with_cache, 6), "savings": round(no_cache - with_cache, 6), "savings_pct": round((1 - with_cache / no_cache) * 100, 2), } print(cache_savings( cached_tokens=42_000, normal_input_per_mtok=3.00, cache_write_per_mtok=3.75, cache_read_per_mtok=0.30, requests=100, )) ``` Здесь используются цены только для иллюстрации. Важен сам принцип. При повторно используемом префиксе объёмом 42,000 токенов и 100 запросах кэширование обычно даёт отличные результаты. При том же префиксе и всего одном запросе кэширование может оказаться дороже, если цена записи выше обычной цены входных токенов. Это первая серьёзная ловушка: кэширование промптов окупается за счёт распределения затрат между запросами. Если вы не используете кэшированный префикс повторно, выгоды не будет. ## Формула порога окупаемости Порог окупаемости можно оценить так: ``` no_cache_cost = N * T * normal_price cache_cost = T * write_price + (N - 1) * T * read_price ``` Где: - N — количество запросов с одним и тем же префиксом - T — количество кэшируемых токенов - normal_price — обычная цена входного токена - write_price — цена создания кэша - read_price — цена чтения кэша Кэширование экономит деньги, когда: ``` T * write_price + (N - 1) * T * read_price < N * T * normal_price ``` В T сокращается при расчёте порога окупаемости только по затратам, поэтому решение определяется количеством повторных использований и соотношением цен. Но количество токенов по-прежнему важно на практике: экономия 80% на 500 токенах почти незаметна; та же экономия на 80,000 токенах — уже отдельная статья расходов. Полезная формула для приблизительной оценки: ``` break_even_requests = (write_price - read_price) / (normal_price - read_price) ``` Если запись в кэш лишь немного дороже обычного ввода, а чтение намного дешевле, порог окупаемости может быть очень низким. Если запись в кэш дорогая или ваш префикс редко повторяется, выгода от кэширования ненадёжна. ## Как структурировать промпты для неизменных префиксов Лучшая оптимизация кэширования промптов — это не флаг API, а расположение содержимого промпта. Неудачная структура: ``` Request ID: req_8f19a Current time: 2026-02-14T09:12:33Z User: customer_4812 Locale: en-US SYSTEM INSTRUCTIONS: ... POLICY MANUAL: [42,000 tokens of stable text] USER QUESTION: Can I get a refund after 45 days? ``` Это мешает кэшированию префикса, потому что промпт начинает различаться с самого начала. Более удачная структура: ``` SYSTEM INSTRUCTIONS: ... POLICY MANUAL: [42,000 tokens of stable text] DYNAMIC REQUEST METADATA: Request ID: req_8f19a Current time: 2026-02-14T09:12:33Z User: customer_4812 Locale: en-US USER QUESTION: Can I get a refund after 45 days? ``` Неизменный блок идёт первым. Динамический блок — после него. Для явного кэширования в стиле Anthropic структура концептуально может выглядеть так: ``` { "model": "claude-sonnet-4-6", "max_tokens": 800, "system": [ { "type": "text", "text": "You are a support policy assistant..." }, { "type": "text", "text": "Refund policy manual v2026-02-01:\n\n...", "cache_control": { "type": "ephemeral" } } ], "messages": [ { "role": "user", "content": "Can I get a refund after 45 days?" } ] } ``` Точная схема запроса зависит от версии API и SDK, поэтому воспринимайте это как пример структуры, а не как код для копирования. Главное, чтобы большой неизменный блок был явно помечен как кэшируемый и не менялся между вызовами. Для автоматического кэширования в стиле OpenAI структура промпта столь же важна, даже если вы не помечаете блок вручную: ``` { "model": "gpt-5.5", "messages": [ { "role": "system", "content": "You are a support policy assistant...\n\nRefund policy manual v2026-02-01:\n\n..." }, { "role": "user", "content": "Can I get a refund after 45 days?" } ] } ``` Если системное сообщение меняется при каждом запросе, не стоит ожидать стабильного чтения из кэша. ## Практический архитектурный шаблон В производственных системах я предпочитаю явно выделять кэшируемые префиксы промптов в коде приложения. Один простой шаблон: ``` prompt_prefix/ support_policy_v17.txt tool_schema_v4.json examples_v9.md runtime_request/ user_question user_profile retrieved_recent_orders ``` Затем собирайте запросы так: ``` from pathlib import Path POLICY_PREFIX = Path("prompt_prefix/support_policy_v17.txt").read_text() TOOL_SCHEMA = Path("prompt_prefix/tool_schema_v4.json").read_text() EXAMPLES = Path("prompt_prefix/examples_v9.md").read_text() def build_prompt(user_question: str, user_profile: dict) -> str: stable_prefix = f""" You are a support policy assistant. TOOLS: {TOOL_SCHEMA} POLICY: {POLICY_PREFIX} EXAMPLES: {EXAMPLES} """.strip() dynamic_suffix = f""" USER PROFILE: {user_profile} USER QUESTION: {user_question} """.strip() return stable_prefix + "\n\n--- DYNAMIC REQUEST ---\n\n" + dynamic_suffix ``` На практике я также задаю версию префикса. Если руководство по правилам меняется, я хочу, чтобы это было осознанным событием инвалидации кэша: ``` sha256sum prompt_prefix/support_policy_v17.txt ``` Этот хеш записывается в журналы рядом с именем модели, количеством токенов создания кэша, количеством токенов чтения кэша и маршрутом запроса. Без такой наблюдаемости ошибки кэша трудно диагностировать, потому что ответ по-прежнему работает — просто обходится дороже. Полезная строка журнала выглядит так: ``` { "route": "support.answer", "model": "claude-sonnet-4-6", "prefix_hash": "9d3a4a...", "input_tokens": 932, "cache_creation_input_tokens": 0, "cache_read_input_tokens": 42000, "output_tokens": 688, "latency_ms": 1840 } ``` Не оптимизируйте, ориентируясь только на счета. Записывайте поведение кэша в журналы по каждому маршруту. ## Задержка: часто меньше, но чудес не бывает Кэширование промптов может уменьшить задержку, потому что провайдер модели может повторно использовать вычисления для кэшированного префикса. Но я бы не закладывал в SLA фиксированное снижение задержки, пока не измерил его на собственной рабочей нагрузке. В производственной среде всё происходит сложнее: - При коротких промптах заметного изменения задержки может не быть. - Длинные кешированные префиксы часто сокращают время до первого токена. - Во многих запросах длина ответа по-прежнему сильнее всего влияет на время выполнения. - Вызовы инструментов, сетевая задержка и ожидание в очереди могут скрывать преимущества кеширования. - Промахи кеша вызывают всплески задержки в хвосте распределения, если запись медленнее чтения. Реалистичная схема тестирования проста: ``` # warm cache python run_eval.py --case support_refund --repeat 1 # measure cache reads python run_eval.py --case support_refund --repeat 50 --jsonl out.jsonl # inspect p50/p95 by cache_read_input_tokens > 0 python analyze_latency.py out.jsonl ``` Измеряйте запросы с попаданием в кеш и с промахом кеша отдельно. Если смешать их, получится число, которое не объясняет ни те, ни другие. ## Подводные камни, которые я встречаю в реальных системах ### 1. Динамический контент перед стабильным Это самая распространённая ошибка. В начало системного промпта помещают временную метку, идентификатор запроса, дамп флагов функций, локаль пользователя или назначенную ему экспериментальную группу. Переместите эти данные ниже. ### 2. «Эквивалентный» JSON не означает эквивалентность Эти два фрагмента семантически идентичны, но не обязательно идентичны для кеша: ``` {"name":"refund_lookup","timeout":3,"strict":true} ``` ``` { "strict": true, "timeout": 3, "name": "refund_lookup" } ``` Если вы включаете схемы инструментов или конфигурацию в кешируемый префикс, сериализуйте их детерминированно: ``` import json def stable_json(data: dict) -> str: return json.dumps(data, sort_keys=True, separators=(",", ":")) ``` Это позволяет избежать случайных промахов кеша из-за изменения порядка ключей или пробельных символов. ### 3. Поиск может сделать кеширование невозможным RAG-системы часто строят промпты так: ``` Retrieved documents: [doc A] [doc B] [doc C] Instructions: ... ``` Если результаты поиска различаются для каждого запроса, префикс тоже различается. Это нормально, если найденный контекст действительно динамический, но не размещайте стабильные инструкции после него. Лучше так: ``` Instructions: ... Long-lived product documentation: [stable docs] Query-specific retrieved documents: [doc A] [doc B] [doc C] ``` Для систем с большим объёмом запросов рассмотрите разделение контекста на: - Общие стабильные инструкции - Документацию, стабильную в рамках клиента - Результаты поиска для конкретного пользователя или запроса Каждый слой кешируется по-разному. ### 4. Время жизни кеша имеет значение У некоторых записей кеша истекает срок действия. Если трафик поступает всплесками, префикс может активно использоваться повторно в течение десяти минут, а затем перестать использоваться. Более длительное время жизни кеша может помочь, но его стоимость и доступность могут различаться в зависимости от провайдера и модели. Здесь важно распределение запросов. Фраза «Мы получаем 10,000 запросов в день» менее полезна, чем «Мы получаем 200 запросов в минуту с этим конкретным префиксом между 9 и 10 часами утра». ### 5. Смена модели делает прежние предположения недействительными Не следует считать, что префикс, кешированный для одной модели, можно повторно использовать для другой. Если вы маршрутизируете запросы между Claude Opus 4.8, Sonnet 4.6, GPT-5.5, Gemini 3 или открытыми моделями, такими как Llama, Qwen, DeepSeek, MiniMax или Kimi, отслеживайте поведение кеша для каждой модели. Маршрутизация между несколькими моделями полезна, но усложняет окупаемость кеширования. Если трафик разделён между пятью моделями, каждой из них может доставаться меньше повторяющихся префиксов. ### 6. Персонализация промптов может дать обратный эффект Команды часто персонализируют системные промпты: ``` You are helping {{customer_name}}, who is on plan {{plan_name}}. ``` Это кажется безобидным, но если персонализация расположена перед кешируемым контентом, каждый клиент получает свой префикс. Размещайте персонализацию позже, если только она действительно не меняет то, как модель интерпретирует стабильный блок. ## Когда кеширование промптов экономит деньги Кеширование обычно хорошо подходит, когда: - Кешируемый префикс велик и часто содержит тысячи или десятки тысяч токенов. - Один и тот же префикс многократно используется повторно. - Префикс остаётся стабильным от запроса к запросу. - Запросы поступают в пределах времени жизни кеша. - Вы можете отслеживать токены создания кеша и чтения из кеша. - Состав промптов на маршруте предсказуем. Конкретные примеры: - Помощник по программированию многократно включает одну и ту же карту репозитория и руководство по стилю. - Бот поддержки включает один и тот же справочник правил в каждый вопрос о возврате средств. - Агент использует большую статическую схему инструментов в каждом запросе. - Внутренний исследовательский помощник включает один и тот же обзор корпуса материалов для команды. Для таких нагрузок кеширование промптов может стать одним из самых эффективных способов оптимизации затрат, поскольку не требует снижать качество контекста. Вы сохраняете длинный промпт, но перестаёте каждый раз платить полную цену за входные токены. ## Когда кеширование промптов не помогает Кеширование малоэффективно или невыгодно, когда: - Промпт короткий. - Префиксы редко используются повторно. - Большую часть контекста составляют результаты поиска для конкретного запроса. - Динамические данные расположены перед стабильными. - Вы постоянно меняете инструкции в ходе экспериментов. - Трафик распределён небольшими объёмами между множеством моделей, клиентов или вариантов промптов. - Запись в кеш стоит дороже, а чтения происходят слишком редко, чтобы окупить её. Распространённая ловушка при оценке: кеширование промптов выглядит невыгодным в ноутбуке, потому что каждый сценарий запускается один раз. Затем оно показывает отличные результаты в рабочей среде, потому что тысячи пользователей используют один и тот же стабильный префикс. Бывает и наоборот: демонстрация повторяет один и тот же промпт 100 раз и показывает большую экономию, но в рабочей среде настройки для каждого клиента препятствуют повторному использованию. Тестируйте на реальном распределении запросов. ## Простой контрольный список готовности к кешированию Прежде чем включать кеширование промптов или полагаться на него, я проверяю: - Есть ли хотя бы один стабильный префикс длиной более нескольких тысяч токенов? - Расположен ли он перед всем динамическим контентом? - Детерминирована ли сериализация? - Есть ли у префикса версия и хеш? - Могу ли я записывать в журнал количество токенов создания кеша и чтения из кеша? - Знаю ли я ожидаемое число повторных использований за время жизни кеша? - Измерял ли я задержку отдельно для попаданий в кеш и промахов? Если на три или более вопросов вы ответили «нет», кеширование всё ещё может работать, но вы действуете наугад. ## Практические рекомендации Кеширование промптов — не волшебное сжатие. Это повторное использование стабильного префикса токенов, а экономия достигается за счёт однократной оплаты создания кеша и многократной оплаты чтения по более низкой цене. Порядок инженерных действий прост: - Сначала размещайте большой стабильный контент: инструкции, инструменты, документацию, примеры. - Переместите временные метки, метаданные пользователей, результаты поиска и идентификаторы запросов после кешируемого префикса. - Отслеживайте cache_creation в сравнении с cache_read токены по каждому маршруту и модели. - Используйте детерминированную сериализацию для схем инструментов и конфигурации в формате JSON. - Рассчитайте точку безубыточности с учётом фактических цен вашего провайдера и распределения трафика. - Будьте осторожны с маршрутизацией между несколькими моделями, настройками для отдельных клиентов и короткими промптами. - Измеряйте задержку для попаданий в кеш и промахов отдельно, вместо того чтобы полагаться на средние значения. Лучшая оптимизация кеша промптов, которую я видел, была совсем простой: мы переместили 42,000 стабильных токенов выше 12 динамических токенов. Поведение модели не изменилось. Сумма счёта — изменилась. [Инференс](/ru/blog/tag/inference/)[Промпты](/ru/blog/tag/prompts/)[RAG](/ru/blog/tag/rag/)[API](/ru/blog/tag/api/) A [AI Prime Tech](https://aiprimetech.io/ru/) Этот блог публикует AI Prime Tech. Статьи готовятся с помощью ИИ; прежде чем полагаться на сведения, зависящие от версии, такие как идентификаторы моделей, цены и лимиты, сверяйте их с официальной документацией. Получите более дешёвый доступ к API Claude Один ключ API для Claude Opus 5.5, Sonnet 5, Haiku 4.5 и Fable 5.1, а также GPT-6 моделей. Оплата по мере использования, без подписки. [Получить ключ API →](/register) AI Prime Tech — независимый сторонний API-шлюз. Claude™ и Anthropic® — товарные знаки Anthropic, PBC. Связь с этой компанией или одобрение с её стороны не подразумеваются.