Перейти к содержанию
Новое AiManual теперь в MAX Подписаться
Публикация AiManual

Оптимизация расходов на LLM в продакшене: как мы перешли с Claude Sonnet на Qwen 3.5 Flash и сократили счёт с $2000 до $30 в месяц

Практический кейс миграции с Claude Sonnet на Qwen 3.5 Flash: как мы сократили расходы на LLM с $2000 до $30 в месяц на задаче структурирования вакансий. Методо

Коротко

Что будет в материале

  1. 01

    Введение: почему мы решили искать альтернативу Claude Sonnet

  2. 02

    Методология выбора: как мы сравнивали модели без иллюзий

  3. 03

    Скрытые грабли дешёвых моделей: что пошло не так после миграции

  4. 04

    Проблемы на стороне агрегатора: OpenRouter и его сюрпризы

Введение: почему мы решили искать альтернативу Claude Sonnet

Наша задача - структурирование вакансий. На вход подаётся сырой текст с HeadHunter, LinkedIn или корпоративного сайта, на выходе - строгий JSON с полями: должность, зарплатная вилка, требования, условия. Объём - несколько тысяч запросов в месяц. Первая версия пайплайна работала на Claude Sonnet 3.5 через API Anthropic. Качество было близко к эталонному: модель чётко следовала схеме, не путала валюты, корректно разделяла годовой и месячный доход. Проблема - счёт. При среднем объёме в 5000 вакансий и расходе ~40 000 токенов на один запрос (промпт плюс ответ) месячный прогноз упирался в $2000. Масштабировать такой пайплайн на 20 000 вакансий означало бюджет в $8000 ежемесячно - неприемлемо для задачи, которая не генерирует прямую выручку, а обслуживает внутренний продукт.

Мы поставили цель: найти модель, которая сохранит приемлемое качество структурирования при радикальном снижении стоимости. Это не была простая замена одной LLM на другую. Потребовалась инженерная работа: методология сравнения, слой защиты от типовых ошибок дешёвых моделей, пересмотр контракта с провайдером. Итог: переход на Qwen 3.5 Flash через OpenRouter сократил расходы до $30 в месяц. В этой статье - полный разбор процесса, от эвала до продакшен-решений.

Методология выбора: как мы сравнивали модели без иллюзий

Базовое правило: бенчмарки общего назначения вроде MMLU или HumanEval не предсказывают качество на узкой задаче. Мы собрали собственный датасет из 50 реальных вакансий, покрывающих основные паттерны: IT-вакансии с вилкой в рублях и долларах, позиции с бонусами, вакансии без указания зарплаты, описания с избыточной информацией о компании. Для каждой вакансии вручную подготовили эталонный структурированный JSON.

Кандидатов было пять: Claude Sonnet (базовый уровень), GPT-4o mini, Gemini 1.5 Flash, Qwen 2.5 72B и Qwen 3.5 Flash. Каждая модель получала идентичный промпт с JSON-схемой и инструкцией. Ответы прогонялись через слепого судью - Claude Opus, который не знал, какая модель сгенерировала конкретный результат. Opus оценивал три параметра: точность заполнения полей (совпадение с эталоном), полнота (все ли значимые атрибуты извлечены), соответствие схеме (валидный JSON, корректные типы).

Почему 50 примеров достаточно для первого решения

Выборка из 50 вакансий - компромисс между скоростью принятия решения и статистической значимостью. Мы не проводили академическое исследование, нам нужен был рабочий инструмент для выбора модели за 2-3 дня. Разнообразие вакансий в выборке перекрывало 90% типовых кейсов из нашего потока. Для задач с более высокой вариативностью входных данных размер выборки стоит увеличить до 100-200 примеров. Но для первого раунда отсева 50 хватило: разрыв в качестве между лидерами и аутсайдерами был очевиден уже после 30 примеров.

Слепой судья Opus: почему мы доверили оценку другой LLM

Использование LLM в роли оценщика вызывает скепсис. Мы провели предварительную калибровку: три инженера независимо оценили 20 ответов, затем сравнили их оценки с вердиктом Opus. Корреляция составила 0.89 - достаточно для практических целей. Промпт для судьи требовал попарного сравнения ответа модели с эталоном по каждому полю, с жёстким требованием аргументировать любое расхождение. Opus склонен к излишней строгости в оценке креативных формулировок, но для задачи с жёсткой схемой этот недостаток не критичен.

Результаты эвала:

Модель Точность полей Полнота Соответствие схеме Цена за 1M токенов (вход/выход)
Claude Sonnet 3.5 94% 91% 99% $3 / $15
GPT-4o mini 89% 87% 96% $0.15 / $0.6
Gemini 1.5 Flash 85% 82% 93% $0.075 / $0.3
Qwen 2.5 72B 88% 85% 91% $0.9 / $0.9
Qwen 3.5 Flash 87% 84% 90% $0.02 / $0.06

Qwen 3.5 Flash показала точность на 7 процентных пунктов ниже Sonnet, но при этом стоила в 150 раз дешевле по входным токенам и в 250 раз - по выходным. Разрыв в качестве был достаточно мал, чтобы попробовать компенсировать его инженерными решениями. Мы выбрали Qwen 3.5 Flash.

Скрытые грабли дешёвых моделей: что пошло не так после миграции

Первая неделя в продакшене принесла отрезвление. Эвал на 50 примерах не выявил целый класс проблем, которые проявились на реальном потоке из тысяч запросов. Дешёвые модели страдают от слабой выравненности (alignment) и нестабильного следования инструкциям. Вот что мы обнаружили в логах.

Пустые ответы при статусе 200: когда API врёт

Самый опасный режим отказа. Модель возвращает HTTP 200 и пустое тело ответа - ни символа. Наш пайплайн, рассчитанный на то, что 200 означает успех, пытался распарсить пустую строку как JSON и падал с невнятной ошибкой. Частота: примерно 3 запроса из 100. Причина не в сетевых проблемах, а в отказе модели генерировать ответ - вероятно, срабатывают внутренние фильтры безопасности на некоторые формулировки в вакансиях. Решение: проверка длины ответа до парсинга JSON, при пустом ответе - немедленный ретрай.

Опечатки в полях схемы: почему строгая типизация обязательна

Модель выдавала валидный JSON, но с ошибками в названиях ключей: salary вместо salary, expirience вместо experience, requirments вместо requirements. Частота: 8-10% ответов содержали хотя бы одну опечатку в ключах. Наш downstream-сервис, ожидавший строго определённые поля, молча игнорировал такие ключи, и в базу попадали записи с пустыми полями. Решение: слой fuzzy matching на стороне постпроцессинга - расстояние Левенштейна между фактическим ключом и ожидаемым, с порогом в 2 символа. Плюс явный маппинг для частых ошибок.

Путаница годовых и месячных зарплат: бизнес-логика под угрозой

Семантическая ошибка, которая чуть не исказила аналитику по рынку труда. Модель извлекала из текста «от 200 000 рублей» и помечала это как месячную зарплату, хотя в контексте вакансии речь шла о годовом доходе. Выявили по статистическим выбросам: медианная зарплата по выборке внезапно выросла в 12 раз. Решение: эвристика - если числовое значение зарплаты превышает 500 000 рублей, принудительно проверяем контекст на наличие маркеров «годовая», «в год», «annual». При неоднозначности - помечаем поле флагом salary_period_ambiguous: true и отправляем на ручную верификацию.

Проблемы на стороне агрегатора: OpenRouter и его сюрпризы

Мы использовали OpenRouter как единый шлюз к разным провайдерам моделей. Удобно: один API-ключ, единый биллинг, fallback между провайдерами. Но агрегатор добавляет свой слой нестабильности.

Маскировка мёртвого ключа под 502/529: как мы теряли часы на дебаг

Ситуация: наш API-ключ OpenRouter был случайно отозван из-за сбоя в биллинге на их стороне. Вместо HTTP 401 (Unauthorized) или 403 (Forbidden) мы получали 502 Bad Gateway и 529 Too Many Requests. Логика была такой: 502 - проблема на стороне провайдера, ретрай с экспоненциальной задержкой. 529 - превышение лимита, увеличиваем задержку. Мы потратили четыре часа, пытаясь диагностировать несуществующую проблему с сетью, пока не проверили ключ напрямую через curl. Решение: на старте каждого воркера выполнять проверочный запрос к API с минимальным количеством токенов. Если возвращается 401 или 403 - алерт и остановка пула. Отдельный мониторинг кодов ответа с группировкой по провайдерам.

Биллинг: когда счёт приходит не вовремя

OpenRouter использует постоплатную модель с пополнением баланса. Задержка в отображении расходов достигала 48 часов. Мы настроили дневной лимит в $5, но из-за лага в биллинге фактический расход за выходные перевалил за $20 - система не успела заблокировать ключ. Решение: дублировать учёт расходов на своей стороне через подсчёт токенов в ответах API. Настроить алерт при достижении 80% дневного лимита по собственным метрикам, а не по данным OpenRouter.

Архитектурные решения для надёжной интеграции дешёвых LLM

После двух недель сбора ошибок мы спроектировали защитный слой, который компенсирует нестабильность Qwen 3.5 Flash. Три компонента работают последовательно в постпроцессинге.

Слой коэрции данных: последний рубеж обороны

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

  • Парсинг JSON с обработкой исключений. Если ответ не парсится - попытка извлечь JSON из текста через регулярное выражение.
  • Fuzzy matching ключей: для каждого ожидаемого ключа ищем ближайший фактический ключ с расстоянием Левенштейна не более 2.
  • Приведение типов: строку "50000" превращаем в число 50000, null в обязательном поле заменяем на дефолтное значение.
  • Нормализация зарплат: если поле salary содержит строку "50 000 руб.", извлекаем число и валюту, приводим к единому формату {value: 50000, currency: "RUB"}.

Этот слой не исправляет семантические ошибки вроде путаницы год/месяц, но устраняет 70% синтаксических проблем.

Ретраи с умом: когда и как переспрашивать модель

Стратегия повторных запросов напрямую влияет на стоимость. Мы настроили три условия для ретрая:

  • Пустой ответ или ответ не является JSON.
  • Ошибка валидации после коэрции: отсутствуют обязательные поля, типы не приводятся.
  • Сработала эвристика подозрительной зарплаты (значение > 1 000 000 рублей без маркера «годовая»).

Максимум 3 попытки с задержкой 1, 3 и 9 секунд. На каждом ретрае немного варьируем промпт: добавляем «Убедись, что зарплата указана в месяц, если не сказано иное» или «Проверь названия полей JSON по схеме». После трёх неудач - отказ. Среднее количество ретраев на 1000 запросов: 120 первых попыток, 40 вторых, 15 третьих. Дополнительные расходы на ретраи - около 15% от базовой стоимости, что всё ещё укладывается в $30/мес.

Fail-closed: почему лучше отказать, чем навредить

Для действий от имени пользователя или данных, которые попадают в публичный доступ, стратегия «пропустить как есть» неприемлема. Если после трёх ретраев ответ не прошёл валидацию, мы не публикуем частично структурированную вакансию. Запись помечается флагом status: "failed" и попадает в очередь на ручную обработку. Это создаёт операционную нагрузку на команду, но предотвращает показ пользователям вакансий с зарплатой $500 000 в месяц из-за ошибки модели. За месяц работы очередь ручной обработки составила 2.3% от общего потока - приемлемый уровень.

Результаты: что мы получили за $30 в месяц

Итоговые метрики после трёх месяцев работы в продакшене:

Показатель Claude Sonnet (прогноз) Qwen 3.5 Flash (факт)
Месячный бюджет $2000 $30
Стоимость обработки одной вакансии $0.40 $0.006
Процент успешных структурирований 98.5% 95.7%
Ошибки в зарплатах (год/месяц) 0.2% 1.1%
Записи, требующие ручной обработки 1.5% 2.3%

Качество снизилось на 2.8 процентных пункта по успешным структурированиям. Это осознанная плата за снижение стоимости в 66 раз. Для нашего продукта такое соотношение приемлемо: ручная обработка дополнительных 0.8% записей обходится дешевле, чем $1970 экономии. Семантические ошибки в зарплатах выросли с 0.2% до 1.1%, но эвристики и ручная верификация не позволяют им попасть в прод.

Ограничения подхода и когда не стоит повторять этот кейс

Успех миграции обеспечили три фактора, специфичных для нашей задачи. Первый: структурирование - это извлечение информации, а не генерация нового контента. Метрики качества объективны и измеримы. Второй: у нас есть возможность валидации ответа - JSON-схема и проверка типов отсекают большую часть ошибок. Третий: бизнес-логика допускает небольшой процент отказов с передачей на ручную обработку.

Для каких задач дешёвые модели не подойдут:

  • Сложные многошаговые рассуждения - модели уровня Qwen 3.5 Flash проваливаются на задачах, требующих цепочки логических выводов из 5+ шагов. Здесь по-прежнему нужны Claude Sonnet или GPT-4o.
  • Креативные тексты, где качество оценивается субъективно - маркетинговые описания, слоганы, сценарии. Разрыв с дорогими моделями слишком велик.
  • Задачи с жёсткими требованиями к безопасности и отсутствием права на ошибку - медицинские или юридические данные. Fail-closed не спасёт, если цена даже одной ошибки неприемлема.
  • Сценарии с длинным контекстом - Qwen 3.5 Flash имеет окно 32K токенов, но качество следования инструкциям падает после 8-10K.

Рынок моделей меняется стремительно. То, что верно для Qwen 3.5 Flash в июле 2026 года, может устареть через месяц. 20B Looping Model уже показывает 10-кратную эффективность обучения, а техники дистилляции вроде A.L.F.R.E.D. позволяют малым моделям обходить гигантов. Принципиальный подход - эвал на своих данных, слой коэрции, мониторинг - остаётся неизменным.

Заключение: дешёвые LLM - это реально, но требует инженерной культуры

Миграция с Claude Sonnet на Qwen 3.5 Flash сократила наши расходы в 66 раз при падении качества на 2.8 п.п. Это не drop-in замена, а системная инженерная работа. Ключевые выводы:

  • Эвал на собственных данных с чёткими метриками - единственный способ выбрать модель. Бенчмарки общего назначения не релевантны для узких задач.
  • Слой коэрции данных обязателен. Дешёвые модели ошибаются в типах, названиях полей и форматах, и это нужно исправлять автоматически.
  • Ретраи на уровне бизнес-логики с вариацией промпта повышают итоговое качество ценой 15% дополнительных токенов.
  • Fail-closed для критичных данных: лучше отправить запись на ручную обработку, чем показать пользователю неверную информацию.
  • Агрегаторы вроде OpenRouter экономят время на интеграции, но добавляют риски: маскировка ошибок аутентификации, задержки биллинга. Нужен собственный мониторинг.

Тестируйте модели на своих данных. Не бойтесь мигрировать, если цифры сходятся. Но закладывайте инженерный ресурс на защитный слой - он окупается. Оптимизация расходов на LLM в продакшене возможна, и этот кейс - прямое тому подтверждение.

Подписаться на канал