The Jerusalem PostNova site restricted to memorial events, not celebrations, KKL-JNF says ahead of third anniversaryPunchUS establishes office of religious affairsBollywood HungamaBigg Boss 20: Rhiti Tiwari evicted in surprise mid-week exit after captaincy task? Here’s what we know!Daily MaverickWhen VW sneezes, Nelson Mandela Bay catches a coldBBC BusinessTravelodge failed sex assault victim 'at every stage'الشرقاكتشاف آلية تمهد لتطوير علاج يعتمد على الفيروسات لمكافحة البكتيرياObservador DesportoModelo de IA supera os melhores de jogo de estratégiaDeadlineBAFTA Makes Plans For ‘I Swear’s John Davidson To Attend Scotland Awards After N-Word ScandalLa PresseSénat | Richard Martel n’a pas choisi d’affiliation, mais dit conserver ses valeursAntara NewsNew FM Arrmanatha Nasir vows to continue Prabowo's foreign policyynetבעלי הבית היקר ביותר באוסטרליה: בן של שורד אושוויץ ואשתו היו בטיסת האימהRMF24Kolejny kraj wejdzie do strefy euro? 80 proc. obywateli jest za
The Daily Newsstand · Free, Always
Thursday, October 1, 2026

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

Translate

В моем приложении для управления финансами была кнопка "Показать Кубышу" Она раскладывала накопления по целям: сколько положить в подушку, сколько в отпуск, сколько в машину. Работала через LLM. У части людей из за белых списков вместо ответа она показывала «работает только с VPN»

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

Что за кнопка

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

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

Что пошло не так

1. Доступность. Модель работает на внешнем сервисе. На мобильном интернете в России внешние сервисы доступны не всегда, и человек без VPN получал ошибку (в последствии проблему белых списков победил)

2. Один вопрос, разные ответы. Нажал кнопку дважды, получил две разные раскладки. В тексте это нормально, в деньгах подрывает доверие: какой из двух ответов правильный?

3. Ответ нельзя проверить тестом. Нельзя написать тест «модель разложила правильно» Можно только смотреть глазами или готовить Датасеты, но всех кейсов покрыть почти невозможно.

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

Это не задача для модели

Если убрать слова, задача оказывается оптимизацией с двумя режимами:

  • «Достичь целей быстрее»: отдать деньги целям по очереди, чтобы первые в очереди собрались как можно раньше

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

Очередь та же, что в календарном движке: сначала приоритет (критичная, важная, хотелка), потом ближайшая желаемая дата внутри приоритета. Если очередь будет своя, раскладка и даты снова разойдутся.

Минимальная сумма. Чем больше денег уже лежит в цели, тем раньше она собирается. Дата монотонно зависит от суммы, значит, минимум можно найти бинарным поиском. Точность до рубля не нужна, шаг 1 000 ₽:

/// Наименьшая сумма (шаг 1 000 ₽), при которой цель успевает к желаемой дате.static func minimalAmount(upTo cap: Double, index: Int, goals: [Goal], target: Date,                          forecast: ([Goal]) -> [UUID: Date]) -> Double {    func onTime(_ amount: Double) -> Bool {        var probe = goals        probe[index].currentAmount = amount        guard let date = forecast(probe)[probe[index].id] else { return amount >= probe[index].targetAmount }        return date <= target    }    guard !onTime(0) else { return 0 }      // успевает и без денег    guard onTime(cap) else { return cap }   // не успевает даже со всеми    var low = 0.0, high = cap    while high - low > 1_000 {        let mid = ((low + high) / 2 / 1_000).rounded() * 1_000        if mid <= low || mid >= high { break }        if onTime(mid) { high = mid } else { low = mid }    }    return high}

static func minimalAmount(upTo cap: Double, index: Int, goals: [Goal], target: Date,

forecast: ([Goal]) -> [UUID: Date]) -> Double {

func onTime(_ amount: Double) -> Bool {

var probe = goals

probe[index].currentAmount = amount

guard let date = forecast(probe)[probe[index].id] else { return amount >= probe[index].targetAmount }

return date <= target

}

guard !onTime(0) else { return 0 } // успевает и без денег

guard onTime(cap) else { return cap } // не успевает даже со всеми

var low = 0.0, high = cap

while high - low > 1_000 {

let mid = ((low + high) / 2 / 1_000).rounded() * 1_000

if mid <= low || mid >= high { break }

if onTime(mid) { high = mid } else { low = mid }

}

return high

}

Один источник дат. forecast передается снаружи, и это та же функция, которая считает даты на карточках целей. Поэтому дата после раскладки совпадает с датой, которую человек увидит на соседнем экране. Чтобы никто не посчитал даты в обход, есть тест-сторож: он падает, если где-то появляется второй расчет прогноза.

Что получилось

  • работает предсказуемо, без сети, в том числе на мобильном интернете без VPN

  • отвечает мгновенно

  • один и тот же вход дает один и тот же ответ

  • покрыт тестами: цель без даты, посильная дата, непосильная, очередь, премия.

Где модель осталась

Там, где нужен текст, а не число: инсайт дня, итоги недели, совет, что сделать дальше. Правила такие:

Задача

Кто делает

Сумма на день, даты целей, раскладка денег

код

Хватит ли до получки, на сколько дней

код

Объяснить цифру простыми словами

модель

Совет на завтра, тон, разрешение порадовать себя

модель

Нет сети

запасной текст-шаблон

Пять правил, к которым я пришел

  1. Цифры считает код. Модель получает их уже посчитанными и не придумывает новые.

  2. Один источник для каждой цифры. Если модель называет дату, это дата из движка, а не ее собственная.

  3. У каждого текста модели есть запасной шаблон на случай, если сети нет.

  4. Если результат можно проверить тестом, это задача для кода.

  5. Если ошибка в цифре стоит человеку спокойствия, модель туда не пускаем.

Расскажите где в ваших продуктах/проектах ИИ оказался лишним? А где после его внедрения реально получилось улучшить результаты?

View the original on Хабр →

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.