Не каждой задаче нужна нейросеть: как снизить расходы на LLM без потери функциональности

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

За такой ответ приходится платить. Хотя программа и без нейросети знает, что документ не сохранён.

Это простой пример проблемы, которая возникает при добавлении LLM в обычные приложения. Мы начинаем использовать генерацию даже там, где ответ можно получить из состояния системы.

И дело не только в стоимости токенов. Внешняя модель добавляет задержку, сетевую зависимость и ещё один источник ошибок.

Попробуем разобраться, какие задачи действительно стоит отдавать LLM, а какие дешевле и надёжнее решать обычным кодом.

Сколько стоит одна подсказка

Стоимость обращения к языковой модели зависит от количества входных и выходных токенов, тарифа провайдера и дополнительных операций.

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

Рассмотрим условный пример.

Предположим, стоимость миллиона входных токенов составляет $2,50, а миллиона выходных — $10. Эти ставки используются исключительно для иллюстрации расчёта.

Один запрос содержит 20 000 входных и 2 000 выходных токенов.

Расходы на входные токены: 20 000 × $2,50 / 1 000 000 = $0,05.

Расходы на ответ: 2 000 × $10 / 1 000 000 = $0,02.

Итого один запрос стоит $0,07.

Семь центов за один ответ выглядят незначительной суммой. Но если обращений становится много, картина меняется.

Предположим, приложением пользуются 10 человек.

При пяти запросах в день на каждого общие расходы составят $3,50 в день. При двадцати запросах — $14. При пятидесяти — $35.

Теперь увеличим аудиторию до 100 человек.

Те же сценарии обойдутся соответственно в $35, $140 и $350 в день.

При 100 пользователях и 20 запросах на человека за 22 рабочих дня расходы составят $3 080.

Это не статистика реального сервиса, а расчётная модель. Фактические затраты могут быть значительно ниже благодаря более дешёвым моделям, сокращению контекста, кэшированию и маршрутизации запросов.

Кроме того, здесь не учитываются стоимость инструментов, повторные попытки и другие расходы.

Но главный вопрос остаётся: сколько из этих обращений вообще необходимо?

Пример, в котором LLM не нужна

Возьмём обычную систему для редактирования программного кода.

Пользователь открывает проект, меняет исходный файл и запускает сборку.

Допустим, система отслеживает три факта:

  1. Есть ли несохранённые изменения.
  2. Когда исходники были изменены последний раз.
  3. Когда была выполнена последняя успешная сборка.

Теперь представим, что пользователь изменил код после последней сборки и пытается использовать ранее созданный файл.

Приложение может определить, что артефакт устарел относительно исходников.

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

Похожая ситуация возникает, если сборка завершилась ошибкой.

Вместо того чтобы сразу спрашивать LLM, что могло произойти, разумнее сначала показать фактическую диагностику инструмента сборки.

Программа уже располагает этой информацией.

Если ответ однозначно определяется имеющимися данными, генерация не добавляет новой информации.

Это не означает, что LLM бесполезна. Она может помочь интерпретировать сложную ошибку или предложить исправление кода. Но это следующий этап, а не обязательная часть каждой операции.

Как организовать подсказки без генерации

Для известных ситуаций можно использовать набор правил, который получает состояние приложения и возвращает рекомендацию.

Например, помощник последовательно проверяет несколько условий.

Первое условие — есть несохранённые изменения. Если пользователь изменил файл, но не сохранил его, приложение предлагает сохранить изменения.

Второе условие — последняя сборка завершилась ошибкой. Вместо запроса к языковой модели приложение показывает фактическую диагностику сборки.

Третье условие — исходники изменились после последней успешной сборки. Система предлагает собрать проект заново, поскольку имеющийся артефакт может не соответствовать текущей редакции.

Если ни одно из этих условий не выполняется, помощник сообщает, что известных проблем не обнаружено.

Такую последовательность можно реализовать обычными условными операторами, без обращения к языковой модели.

В реальной системе недостаточно просто сравнить время изменения файлов. Надёжнее хранить версии исходников или идентификаторы содержимого, на основе которых выполнялась сборка.

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

Однако сам принцип остаётся тем же: программа проверяет известные условия и выдаёт объяснимую рекомендацию.

При одинаковых состояниях и одинаковых правилах результат будет воспроизводимым.

Это упрощает тестирование. Для каждого условия можно заранее определить ожидаемое поведение и проверить его автоматически.

Как избежать неправильных подсказок

Детерминированный подход не гарантирует корректности сам по себе.

Например, если система хранит только время последнего сохранения, она может ошибочно решить, что ранее собранный файл соответствует текущему коду.

Такое возможно, если сборка выполнялась для другой версии исходников или состояние проекта изменилось во время выполнения операции.

Поэтому полезно фиксировать связь между исходниками и артефактом.

Допустим, текущая версия исходников — 42, а последняя успешная сборка выполнена для версии 41.

Это означает, что имеющийся артефакт не соответствует последней редакции проекта.

Система может обнаружить это без обращения к языковой модели.

Но если требуется объяснить, почему изменённый алгоритм работает неправильно, это уже другая задача.

Где LLM действительно полезна

У программных правил есть естественное ограничение: они могут обрабатывать только предусмотренные ситуации.

Если приложение знает, что файл не сохранён, достаточно обычной проверки.

Но если пользователь просит проанализировать неизвестный алгоритм, объяснить сложный участок кода или предложить архитектурное решение, заранее подготовленных условий может не хватить.

Здесь генеративная модель действительно способна добавить ценность.

Поэтому удобнее разделять задачи на три категории.

Первая — точные операции. Проверка статусов, сравнение версий, контроль обязательных полей, отображение диагностических сообщений. Их обычно следует реализовывать программно.

Вторая — задачи с ограниченной неопределённостью. Например, классификация сообщения или выбор следующего действия из небольшого набора вариантов. Здесь стоит сравнивать обычные алгоритмы, компактные модели и LLM по стоимости и качеству.

Третья — открытые задачи. Анализ произвольного текста, генерация программного кода, сложные объяснения и исследование неизвестных ситуаций. Это естественная область применения языковых моделей.

Такое разделение не означает, что все задачи третьей категории обязательно нужно решать через облачный API. Некоторые из них можно выполнять локально, если позволяют оборудование и качество модели.

Почему локальная модель тоже не решает всех проблем

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

Для этого существуют такие технологии, как WebGPU, WebLLM и Transformers.js.

Но появляются другие ограничения: загрузка модели, расход памяти, требования к оборудованию и различия производительности.

Пользователь со слабым компьютером может получить совсем другой опыт работы, чем обладатель современной видеокарты.

Кроме того, отсутствие оплаты токенов не означает отсутствия затрат. Остаются разработка, интеграция, тестирование и поддержка.

Поэтому локальную генерацию разумно рассматривать как отдельный вариант, а не универсальное решение.

Экономия токенов — не единственная метрика

Предположим, что использование обычного правила позволяет исключить тысячу запросов по семь центов.

Экономия составит $70.

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

Поэтому сравнивать стоит не только стоимость вызовов LLM.

Более полезная метрика — стоимость успешно выполненной операции с учётом разработки, инфраструктуры, проверки результата и исправления ошибок.

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

Для LLM добавляются токены, внешние API, дополнительные проверки, повторные обращения и возможные ошибки генерации.

В некоторых случаях простое обращение к LLM действительно будет экономически оправданнее собственной системы правил.

В других — обычное условие «если — то» окажется и дешевле, и надёжнее.

Как выбирать подход

Практический порядок может быть таким:

  1. Определить, какой результат нужен пользователю.
  2. Проверить, есть ли уже необходимые данные в приложении.
  3. Выделить условия, для которых существует однозначный алгоритм.
  4. Оценить сложность поддержки обычной программной логики.
  5. Использовать LLM там, где она действительно добавляет новые возможности.
  6. Измерять не только стоимость токенов, но и стоимость успешного результата.

Главное — не превращать языковую модель в обязательного посредника между пользователем и каждой функцией системы.

Нейросеть полезна там, где нужна генерация или интерпретация. Там, где ответ уже известен программе, часто достаточно обычного кода.

А как вы проводите эту границу в своих проектах? В каких случаях предпочитаете писать детерминированные правила, а в каких — обращаться к LLM, даже если задачу теоретически можно решить без неё?

11