ideipro logotyp

Prompt Caching в Claude: Как мы снизили затраты на AI в 2 раза

Prompt Caching в Claude: Как мы снизили затраты на AI в 2 раза

Кейс по оптимизации затрат на Claude API в проекте по автоматизации поиска работы. AI анализировал вакансии и генерировал сопроводительные письма. При 100 пользователях затраты достигали $180/месяц. Решение: Prompt Caching от Anthropic. Экономия 52% ($0.51 → $0.245 за batch из 50 вакансий). Теперь можно делать в 2 раза больше AI-вызовов с тем же бюджетом.

Кому полезно: всем, кто работает с LLM API и хочет оптимизировать затраты.

История: Когда AI начал съедать бюджет

Делал проект по автоматизации поиска работы — платформа анализирует вакансии с помощью AI и сопоставляет их с резюме пользователя. Даёт score от 0 до 100 и объясняет, почему вакансия подходит или нет.

Логика простая:

  1. Пользователь ищет вакансии (например, «Product Manager в Москве»)

  2. Система находит 50-100 вакансий через HH API

  3. Claude AI анализирует каждую вакансию относительно резюме пользователя

  4. Возвращаем список с оценками и рекомендациями

Звучит круто, пока не начинаешь считать затраты.

Считаем: Сколько это стоит?

Дано:

  • Модель: Claude Sonnet (умная, но дорогая)

  • Один поиск: 50 вакансий

  • Один пользователь делает ~10 поисков в месяц

Токены на один анализ вакансии:

  • System prompt: 500 токенов (инструкции для AI)

  • Резюме пользователя: 1,500 токенов (опыт, навыки, образование)

  • Описание вакансии: 400 токенов (требования, обязанности)

  • Ответ AI: 200 токенов (оценка + объяснение)

  • Итого: ~2,600 токенов на вакансию

Стоимость Claude Sonnet:

  • Input: $3 за 1M токенов

  • Output: $15 за 1M токенов

Batch из 50 вакансий:

Input: 50 × 2,400 токенов = 120,000 токенов = $0.36 Output: 50 × 200 токенов = 10,000 токенов = $0.15 Итого: $0.51 за один поиск

Стоп. Это много. Очень много.

Если у нас 100 пользователей, и каждый делает 10 поисков в месяц:

100 пользователей × 10 поисков × $0.51 = $510/месяц

Пятьсот долларов только на AI. При том что вся инфраструктура (сервер, база данных, домен) обходится в ~$35/месяц.

Так не пойдёт.

Первая оптимизация: Используем Haiku для простых задач

Первое, что пришло в голову — не все задачи требуют самой умной модели. Для простых вопросов (например, «сколько стоит подписка?») можно использовать Claude Haiku — он в 5 раз дешевле.

Новая стратегия:

  • Haiku (дешёвый) — для FAQ, простых вопросов, базовой фильтрации

  • Sonnet (дорогой) — для сложного анализа резюме и генерации писем

Помогло, но не сильно. Основные затраты всё равно шли на matching вакансий, где без Sonnet никак.

Нужно было что-то другое.

Открытие: Prompt Caching

Копаясь в документации Anthropic, нашёл фичу Prompt Caching. Суть простая: если отправляешь в Claude один и тот же контекст много раз подряд, можно его закешировать на 5 минут. Anthropic берёт плату только за новую часть запроса.

Как это работает:

Обычный запрос выглядит так:

response = client.messages.create( model=»claude-sonnet-4-20250514″, system=»Ты анализируешь вакансии…», # 500 токенов messages=[ { «role»: «user», «content»: f»Резюме: {resume}nВакансия: {vacancy}» } ] )

Каждый раз Claude читает ВСЁ заново: system prompt, резюме, вакансию. Платим за все токены.

С Prompt Caching:

response = client.messages.create( model=»claude-sonnet-4-20250514″, system=[ { «type»: «text», «text»: «Ты анализируешь вакансии…», # 500 токенов «cache_control»: {«type»: «ephemeral»} # ← Кешируем! }, { «type»: «text», «text»: f»Резюме пользователя: {resume}», # 1,500 токенов «cache_control»: {«type»: «ephemeral»} # ← Кешируем! } ], messages=[ { «role»: «user», «content»: f»Вакансия: {vacancy}» # 400 токенов — НЕ кешируем } ] )

Теперь:

  • Первый запрос: платим за всё (500 + 1,500 + 400 токенов)

  • Следующие запросы (в течение 5 минут): платим только за новую вакансию (400 токенов)

System prompt и резюме читаются из кеша — стоимость снижается в 10 раз для cached токенов!

Реализация: Что мы закешировали

1. System Prompt (всегда одинаковый)

SYSTEM_PROMPT = «»»Ты — AI-ассистент для анализа вакансий. ЗАДАЧА: Оценить соответствие вакансии резюме кандидата по шкале 0-100. КРИТЕРИИ ОЦЕНКИ: — Совпадение навыков (40%) — Опыт работы (30%) — Образование (15%) — Зарплатные ожидания (15%) ВАЖНО: — Учитывай уровень позиции (Junior/Middle/Senior/Lead) — Если кандидат overqualified (например Senior на Middle позицию), снижай оценку — Если underqualified, тоже снижай оценку ФОРМАТ ОТВЕТА: { «score»: 85, «reasoning»: «Объяснение оценки», «pros»: [«Плюс 1», «Плюс 2»], «cons»: [«Минус 1»] } «»»

Этот промпт не меняется между вызовами → кешируем целиком.

2. Резюме пользователя (меняется редко)

У каждого пользователя есть резюме. Оно не меняется в рамках одной сессии поиска. Более того — пользователь может делать 5-10 поисков подряд с одним и тем же резюме.

Кешируем его тоже:

resume_text = f»»» ИМЯ: {user.name} ДОЛЖНОСТЬ: {user.title} ОПЫТ: {format_experience(user.experience)} НАВЫКИ: {‘, ‘.join(user.skills)} ОБРАЗОВАНИЕ: {user.education} «»»

3. Описание вакансии (всегда новое)

Это единственная часть, которая меняется для каждого вызова. Её НЕ кешируем — она всегда уникальна.

Код: Как это выглядит в FastAPI

Вот реальный код из нашего проекта (упрощённая версия):

from anthropic import AsyncAnthropic class VacancyMatcher: def __init__(self): self.client = AsyncAnthropic(api_key=settings.ANTHROPIC_API_KEY) async def match_vacancy( self, vacancy: dict, resume: dict, use_cache: bool = True ) -> dict: «»» Анализирует одну вакансию относительно резюме Args: vacancy: Данные вакансии из HH API resume: Резюме пользователя use_cache: Использовать ли Prompt Caching «»» # 1. Форматируем резюме в текст resume_text = self._format_resume(resume) # 2. Форматируем вакансию vacancy_text = self._format_vacancy(vacancy) # 3. Формируем system prompt с кешированием if use_cache: system = [ { «type»: «text», «text»: SYSTEM_PROMPT, «cache_control»: {«type»: «ephemeral»} }, { «type»: «text», «text»: f»РЕЗЮМЕ КАНДИДАТА:n{resume_text}», «cache_control»: {«type»: «ephemeral»} } ] else: # Без кеширования (для сравнения) system = f»{SYSTEM_PROMPT}nnРЕЗЮМЕ КАНДИДАТА:n{resume_text}» # 4. Вызываем Claude response = await self.client.messages.create( model=»claude-sonnet-4-20250514″, max_tokens=1024, system=system, messages=[ { «role»: «user», «content»: f»ВАКАНСИЯ:n{vacancy_text}nnОцени соответствие.» } ] ) # 5. Парсим ответ result = json.loads(response.content[0].text) return { «vacancy_id»: vacancy[«id»], «score»: result[«score»], «reasoning»: result[«reasoning»], «pros»: result[«pros»], «cons»: result[«cons»], «tokens_used»: { «input»: response.usage.input_tokens, «cache_read»: getattr(response.usage, «cache_read_input_tokens», 0), «output»: response.usage.output_tokens } }

Batch Processing: Обрабатываем 50 вакансий параллельно

Чтобы не ждать 50 секунд (по 1 секунде на вакансию), делаем batch processing:

async def match_batch( self, vacancies: list[dict], resume: dict, batch_size: int = 5 ) -> list[dict]: «»» Обрабатываем вакансии батчами параллельно Args: vacancies: Список вакансий resume: Резюме пользователя batch_size: Сколько вакансий обрабатывать одновременно «»» results = [] # Разбиваем на батчи по 5 вакансий for i in range(0, len(vacancies), batch_size): batch = vacancies[i:i + batch_size] # Запускаем параллельно tasks = [ self.match_vacancy(vacancy, resume, use_cache=True) for vacancy in batch ] batch_results = await asyncio.gather(*tasks) results.extend(batch_results) # Небольшая пауза между батчами (чтобы не упереться в rate limit) if i + batch_size < len(vacancies): await asyncio.sleep(0.5) return results

Результат:

  • 50 вакансий обрабатываются за ~20 секунд (вместо 50)

  • Prompt Cache hit rate: 60-80% (зависит от того, как быстро пользователь делает запросы)

Результаты: Что получили

До Prompt Caching

Один batch (50 вакансий):

Input: 50 × 2,400 токенов = 120,000 токенов × $3/1M = $0.36 Output: 50 × 200 токенов = 10,000 токенов × $15/1M = $0.15 Итого: $0.51 за batch

100 пользователей × 10 поисков/месяц:

$0.51 × 1,000 = $510/месяц

После Prompt Caching

Первый запрос (cache miss):

Input: 2,400 токенов × $3/1M = $0.0072 Output: 200 токенов × $15/1M = $0.003 Итого: $0.0102

Следующие 49 запросов (cache hit):

Cached tokens (system + resume): 2,000 токенов × $0.30/1M = $0.0006 New tokens (vacancy): 400 токенов × $3/1M = $0.0012 Output: 200 токенов × $15/1M = $0.003 Итого за вакансию: $0.0048

Batch из 50 вакансий:

Первая: $0.0102 Остальные 49: 49 × $0.0048 = $0.235 Итого: $0.245 за batch (вместо $0.51)

Экономия: 52% 

100 пользователей × 10 поисков/месяц:

$0.245 × 1,000 = $245/месяц (вместо $510)

Сэкономили $265 в месяц. Или $3,180 в год.

Когда Prompt Caching работает лучше всего

Идеальные сценарии:

  1. Batch processing — обрабатываете много похожих запросов подряд

    • Пример: анализ вакансий, модерация контента, генерация описаний товаров

  2. Длинный контекст — system prompt или reference материалы занимают много токенов

    • Пример: база знаний компании, документация, техническая спецификация

  3. Повторяющиеся запросы — пользователь делает несколько запросов за короткое время

    • Пример: поиск с разными фильтрами, итеративное редактирование

Когда кеширование не поможет:

  1. Уникальные запросы — каждый раз новый контекст

    • Пример: генерация креативов для разных клиентов

  2. Редкие запросы — между вызовами проходит >5 минут

    • Пример: чат-бот с низкой активностью

  3. Короткие промпты — кешировать нечего (меньше 1024 токенов)

Подводные камни и нюансы

1. Кеш живёт только 5 минут

Если пользователь долго думает между запросами, кеш протухает. Приходится платить по полной за следующий запрос.

Решение: Группируем запросы. Например, в нашем случае пользователь сначала ищет все вакансии, а потом мы анализируем их batch’ами. Вероятность cache hit высокая.

2. Минимальный размер для кеширования: 1024 токена

Нельзя кешировать маленькие промпты. Если ваш system prompt короткий, кеширование не сработает.

Решение: Объединяйте несколько блоков в один cached блок. Например, мы кешируем system prompt + резюме вместе.

3. Порядок имеет значение

Кешировать можно только последние блоки в system prompt. Нельзя сделать так:

# Не сработает system = [ {«text»: «Часть 1», «cache_control»: {«type»: «ephemeral»}}, {«text»: «Часть 2»}, # НЕ cached {«text»: «Часть 3», «cache_control»: {«type»: «ephemeral»}} ]

Правильно:

# Работает system = [ {«text»: «Часть 1»}, # НЕ cached {«text»: «Часть 2», «cache_control»: {«type»: «ephemeral»}}, {«text»: «Часть 3», «cache_control»: {«type»: «ephemeral»}} ]

4. Cache hit не гарантирован

Даже если делаете запросы быстро, cache hit rate может быть 60-80%, а не 100%. Зависит от нагрузки на серверах Anthropic.

Решение: Считайте среднюю экономию, а не максимальную.

Мониторинг: Как считать реальную экономию

Anthropic возвращает детальную статистику по токенам:

response.usage: { «input_tokens»: 400, # Новые токены «cache_creation_input_tokens»: 2000, # Записали в кеш «cache_read_input_tokens»: 2000, # Прочитали из кеша «output_tokens»: 200 }

Считаем стоимость:

def calculate_cost(usage) -> float: «»» Считает стоимость запроса с учётом кеширования Цены Claude Sonnet (на февраль 2025): — Input: $3.00 / 1M tokens — Output: $15.00 / 1M tokens — Cache write: $3.75 / 1M tokens (на 25% дороже обычного input) — Cache read: $0.30 / 1M tokens (в 10 раз дешевле!) «»» input_cost = usage.input_tokens * 3.00 / 1_000_000 cache_write_cost = usage.cache_creation_input_tokens * 3.75 / 1_000_000 cache_read_cost = usage.cache_read_input_tokens * 0.30 / 1_000_000 output_cost = usage.output_tokens * 15.00 / 1_000_000 return input_cost + cache_write_cost + cache_read_cost + output_cost

Логируем каждый запрос:

logger.info( «Claude API call», extra={ «vacancy_id»: vacancy[«id»], «input_tokens»: usage.input_tokens, «cache_read_tokens»: usage.cache_read_input_tokens, «output_tokens»: usage.output_tokens, «cost»: cost, «cache_hit»: usage.cache_read_input_tokens > 0 } )

Дальше можно строить дашборды в Grafana или анализировать логи:

— Средний cache hit rate за последний день SELECT DATE(created_at) as date, COUNT(*) as total_requests, SUM(CASE WHEN cache_read_tokens > 0 THEN 1 ELSE 0 END) as cache_hits, ROUND( 100.0 * SUM(CASE WHEN cache_read_tokens > 0 THEN 1 ELSE 0 END) / COUNT(*), 2 ) as hit_rate_percent FROM ai_calls WHERE created_at > NOW() — INTERVAL ‘7 days’ GROUP BY DATE(created_at) ORDER BY date DESC;

Наши результаты за неделю:

date | total_requests | cache_hits | hit_rate_percent ————|—————-|————|—————— 2025-02-08 | 1,247 | 982 | 78.75 2025-02-07 | 1,893 | 1,456 | 76.93 2025-02-06 | 2,104 | 1,687 | 80.18

Cache hit rate ~78%. Значит экономим не ровно 52%, а ~46% (с учётом cache miss). Всё равно отлично!

Выводы: Стоит ли оно того?

Да, если:

  1. У вас batch processing — обрабатываете десятки запросов подряд

  2. Длинный контекст — system prompt + reference документы >2000 токенов

  3. Частые запросы — пользователи делают много действий за короткое время

Возможно стоит, если:

  1. Средний контекст — 1000-2000 токенов

  2. Умеренная нагрузка — пользователи делают запросы, но не очень часто

Не стоит, если:

  1. Короткие промпты — меньше 1024 токенов

  2. Редкие запросы — между вызовами проходит много времени

  3. Всегда уникальный контекст — нечего кешировать

Наш случай:

  • Batch processing

  • Длинный контекст (system prompt + резюме = 2000+ токенов)

  • Частые запросы (пользователь делает 5-10 поисков подряд)

Итог: Сэкономили $265/месяц при текущей нагрузке. При росте до 1000 пользователей — это будет $2,650/месяц экономии. Вполне достаточно, чтобы покрыть всю инфраструктуру.

Полезные ссылки

  • Anthropic Prompt Caching docs

  • Claude API Pricing

Источник: habr.com

✅ Найденные теги: новости, Промпт

ОСТАВЬТЕ СВОЙ КОММЕНТАРИЙ

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Каталог бесплатных опенсорс-решений, которые можно развернуть локально и забыть о подписках

галерея

Фото сгенерированных лиц: исследование показывает, что люди не могут отличить настоящие лица от сгенерированных
Нейросети построили капитализм за трое суток: 100 агентов Claude заперли…
Скетч: цифровой осьминог и виртуальный мир внутри компьютера с человечком.
Сцена с жестами пальцами, где один жест символизирует "VPN", а другой "KHP".
‼️Paramount купила Warner Bros. Discovery — сумма сделки составила безумные…
Скриншот репозитория GitHub "Claude Scientific Skills" AI для научных исследований.
Структура эффективного запроса Claude с элементами задачи, контекста и референса.
Эскиз и готовая веб-страница платформы для AI-дизайна в современном темном режиме.
ideipro logotyp
Image Not Found
Звёздное небо с галактиками и туманностями, космос, Вселенная, астрофотография.

Система оповещения обсерватории Рубина отправила 800 000 сигналов в первую ночь наблюдений.

Астрономы будут получать оповещения о небесных явлениях в течение нескольких минут после их обнаружения. Теренс О'Брайен, редактор раздела «Выходные». Публикации этого автора будут добавляться в вашу ежедневную рассылку по электронной почте и в ленту новостей на главной…

Мар 2, 2026
Женщина с длинными тёмными волосами в синем свете, нейтральный фон.

Расследование в отношении 61-фунтовой машины, которая «пожирает» пластик и выплевывает кирпичи.

Обзор компактного пресса для мягкого пластика Clear Drop — и что будет дальше. Шон Холлистер, старший редактор Публикации этого автора будут добавляться в вашу ежедневную рассылку по электронной почте и в ленту новостей на главной странице вашего…

Мар 2, 2026
Черный углеродное волокно с текстурой плетения, отражающий свет.

Материал будущего: как работает «бессмертный» композит

Учёные из Университета штата Северная Каролина представили композит нового поколения, способный самостоятельно восстанавливаться после серьёзных повреждений.  Речь идёт о модифицированном армированном волокном полимере (FRP), который не просто сохраняет прочность при малом весе, но и способен «залечивать» внутренние…

Мар 2, 2026
Круглый экран с изображением замка и горы, рядом электронная плата.

Круглый дисплей Waveshare для креативных проектов

Круглый 7-дюймовый сенсорный дисплей от Waveshare создан для разработчиков и дизайнеров, которым нужен нестандартный экран.  Это IPS-панель с разрешением 1 080×1 080 пикселей, поддержкой 10-точечного ёмкостного сенсора, оптической склейкой и защитным закалённым стеклом, выполненная в круглом форм-факторе.…

Мар 2, 2026

Впишите свой почтовый адрес и мы будем присылать вам на почту самые свежие новости в числе самых первых