TL;DR. Собрал воркфлоу на языковой модели, который раз в сутки обходит 34 страницы условий у 12 российских банков, сравнивает их со вчерашним снимком и публикует сводку изменений с ссылкой на источник в каждой строке, а при изменении цены пишет разбор с расчётом. Модель вызывается в четырёх точках и ни в одной не решает, что делать дальше. Цитаты, числа и статистика проверяются кодом. Каждый выпуск оценивается по 14 бинарным проверкам, метрики публичные. Стоит от 3 центов до 70 в день. Ниже устройство, проверки, evals и что он нашёл за первую неделю.

Я работаю в розничных кредитных рисках банка. С языковыми моделями познакомился пару недель назад, начал собирать себе инструменты, и один из них за это время дорос до публичного продукта: Telegram-канал и сайт, где каждое утро в 09:00 выходит сводка изменений условий кредитных карт, рассрочки, кредитов наличными и автокредитов, а когда есть повод, короткий разбор одного изменения.

Что делает

Раз в сутки радар обходит 34 страницы условий и тарифных документов, сравнивает их с вчерашним снимком и превращает разницу в текст. Отдельно читает новости регулятора и четырёх деловых изданий, ключевую ставку с cbr.ru и котировки банков на Мосбирже. Итог одного дня: сводка из трёх-четырёх разделов, где у каждой строки есть ссылка на источник, и, не чаще трёх раз в неделю, разбор на четыре абзаца с одним графиком.

Так выглядит сводка за 12 сентября, как есть:

Условия у банков • Сбербанк убрал со страницы кредитной карты условие о ставке 9,8 %, новое значение не указано. • МТС-Банк, кредитная карта: страница условий переписана (21 правка). Что изменилось: льготный период: указано до 111 дней и до 51 дня; минимальный платёж: значение 10 % со страницы убрано; лимит: теперь указано до 1 млн ₽. • Сбербанк, кредитная карта: со страницы условий убрали строку Правила акции «Выдача собственных денежных средств».

Новости Новых новостей по розничному кредиту за сутки нет.

А так разбор 11 сентября, в двух фразах: Газпромбанк записал устройство льготного периода в название тарифа, «приветственный до 120 дней, далее до 60», а на странице по-прежнему крупно стоит «до 120». При ставке 59,99 % те же 100 000 ₽ долга на 120 дней в первом цикле бесплатны, во втором стоят около 9,9 тыс. ₽. Число дней на сайте перестало быть ценой продукта, цену задаёт второй цикл.

Разбор 11 сентября: что раскрыто в условиях кредитных карт
Разбор 11 сентября: что раскрыто в условиях кредитных карт

Почему воркфлоу, а не агент

В терминологии Anthropic агент сам выбирает следующий шаг, воркфлоу идёт по маршруту, заданному кодом. Я выбрал второе, и это главное архитектурное решение проекта. Модель вызывается в четырёх точках, и ни в одной она не решает, что делать дальше.

Схема ежедневного выпуска
Схема ежедневного выпуска
  1. Редактура сводки. Строки сводки собирает код из диффа страниц: банк, продукт, параметр, было, стало. Модель получает эти строки и переписывает их по-человечески. Она не может добавить число, которого нет во входе, и это проверяется после.

  2. Черновик разбора. Только если сработал триггер: ценовой параметр (ставка, ПСК, льготный период, платёж) изменился с одним числом на другое. Переписанная страница без изменения цены поводом не считается.

  3. Три проверяющих. Черновик читают три роли: факты, методология, риски. Каждой отдаётся ровно тот же материал, что видел автор, иначе они честно объявляют выдумкой то, что есть в источнике. Замечания уровня «важно» и выше уходят в одну доработку.

  4. Лёгкие ворота перед публикацией: короткий вызов, который отвечает, можно ли это выпускать.

Всё остальное детерминировано: обход, диффы, фильтр шума, графики, публикация, статистика по графику. Последнее важно: коэффициенты корреляции, R², p-value и ρ Спирмена считает код и дописывает под текст. Модели запрещено писать r и p самой, потому что она их придумывает.

Что проверяется кодом, а не верой

Первые выпуски научили быстро. Модель уверенно склеивала два изменения в одну фразу, обрывала цитаты посреди слова, называла cookie-баннер «значимым изменением условий» и один раз написала «конкуренты» так, что стало понятно, из какого банка автор. Каждая такая ошибка превратилась в проверку.

Цитаты дословно. Каждая цитата из разбора ищется как подстрока в сохранённом тексте источника после нормализации пробелов и регистра. Не нашлась, удаляется. В упрощённом виде это одна функция:

def quote_in(fact: str, ctx_norm: str) -> bool:
    """fact — цитата из ответа модели; ctx_norm — нормализованный текст всех источников дня."""
    f = " ".join(fact.split()).lower().strip("«»\"' .")
    return len(f) >= 12 and f in ctx_norm

res["facts"] = [f for f in res.get("facts", []) if quote_in(f, ctx_norm)]

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

Ссылка в каждой строке. Банк в строке условий ведёт на страницу условий, новость на статью, ставка на таблицу ЦБ, акции на карточку бумаги. Строка без ссылки не проходит самопроверку.

Шум не считается изменением. Даты, счётчики, хэши заменяются заглушками до диффа. Cookie-баннеры, чат-боты, «оцените страницу», промо приложений отфильтрованы списком фраз.

Обрывы. Обрезка только по границе слова, с многоточием. Переписанная страница (больше восьми правок) сворачивается в одну строку: «страница условий переписана, 21 правка. Что изменилось: льготный период: до 111 и до 51 дня; лимит: до 1 млн ₽».

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

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

Окно на «стоп». Перед публикацией разбора черновик уходит мне в личку через второго бота, 15 минут на команду «стоп». Сводка выходит в любом случае.

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

Я не верю в «вроде нормально». Рубрика бинарная: девять проверок для сводки, пять для разбора, каждая 0 или 1. Шесть из четырнадцати проверяет код (ссылки, числа, обрывы, запрещённые слова), остальные судья-модель с коротким промптом, где заранее написано, что считается одним событием, а что склейкой. Снимок дня со всеми входами и выходами пишется при каждом выпуске, так что любой день можно прогнать заново.

#

Проверка

Кто

d1

самопроверка сводки пуста: ссылки есть, нет запрещённых слов, нет обрывов цитат

код

d3

каждая строка закончена, не обрывается посреди слова

код

d4

каждая строка по банку со ссылкой

код

d5

все числа в строке есть в старом или новом значении изменения

код

d7

одно событие на строку, не склейка двух

судья

d8

понятно, что изменилось: было, стало, появилось, убрано

судья

d9

читается как факт, не как реклама с витрины

судья

e1

заголовок разбора это вывод, а не тема

судья

e2

гипотезы помечены как гипотезы

судья

e4

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

код и судья

Первый прогон на сохранённых текстах дал 67 из 100. Нашлось: строки без ссылок, слово-паразит «По сути» из моего же запрещённого списка, и то, что судья счёл строку переписанной страницы «склейкой», пока я не объяснил ему в рубрике, что это одно событие. После двух правок два дня прошли на 100. Это не оценка качества, выборка из двух дней ничего не значит, это проверка, что контур работает. Опубликованные тексты держатся около 89: ноль по пункту «читается как факт» на строке про МТС-Банк, которую редактура оставила слишком витринной. Стоимость проверки около 0,006 $ за выпуск. Метрики выкладываются на сайт автоматически.

Инженерные мелочи, без которых не работало

  • Сертификаты Минцифры. Сбер, Альфа, ВТБ и Совкомбанк отдают сертификаты УЦ, которого нет в системном доверии. Корневой сертификат лежит в каталоге проекта и подключается только процессу радара. Браузеру передаётся точечно, через отпечаток ключа, а не отключением проверки.

  • Рендер только по необходимости. Обычный GET дешёвый. Headless-браузер включается, если пришла JS-заглушка: у Сбера это 6 КБ каркаса без единой цифры по продукту.

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

  • Хеджированный запрос к модели. Если соединение висит 8 секунд, пускается дубль, берётся первый ответ.

  • Превью ссылок в Telegram ненадёжно. Bot API не даёт проверить, собралось ли превью. Единственная схема, которая рендерится всегда: sendPhoto с подписью до 1024 знаков, полный текст ответом на фото.

  • Бюджетный страж. Расход пишется в журнал по каждому вызову. При превышении дневного лимита генерация переключается на модель дешевле, при превышении месячного выпуск пропускается с сообщением мне. Реальные цифры: день со сводкой около 0,03 $, день с разбором на старшей модели около 0,7 $.

Сайт как побочный продукт того же воркфлоу

Telegram не индексируется, а изменения условий это ровно то, что люди ищут: «льготный период Газпромбанк 2026». Поэтому после публикации сводки тот же текст без единого дополнительного вызова модели раскладывается в статическую страницу выпуска: дата, лид, разбор с графиком, сводка по разделам, ссылки, разметка NewsArticle. Модуль в 350 строк держит архив, JSON-ленту для главной страницы, RSS и sitemap выпусков, заливает всё по FTP и пингует IndexNow. Состояние в одном JSON, любую страницу можно пересобрать.

Страница выпусков на сайте
Страница выпусков на сайте

Хостинг за один день дважды переставал отвечать по 443 при живом 80. Поэтому рядом с радаром живёт монитор: раз в пять минут проверяет сайт с другого сервера, при сбое перепроверяет трижды и уходит в экспоненциальный бэкофф до часа, а мне шлёт одно сообщение при падении и одно при восстановлении. Журнал сбоев это и есть текст тикета в поддержку.

Что не так и что дальше

Главная слабость радара в том, что единица наблюдения пока строка текста, а не параметр продукта. Диффы построчно дают обрывки абзацев и три формулировки одного и того же. Правильная единица: таблица параметров по банку и продукту, где новость это изменение ячейки. Тарифный модуль уже умеет это для тарифных документов, лендинги пока нет. Это следующая ступень, она сделает разбор короче и дешевле, а половину проверок ненужной.

Второе: для читателя-руководителя ценность не в ежедневных обрывках, а в трёх вещах: решение регулятора в день события, цена денег по рынку одной картинкой раз в неделю, и редкий разбор, когда кто-то реально сдвинул цену. Ежедневная сводка нужна, но её пустота это тоже норма, и радар так и пишет: «Изменений условий за сутки нет».

Что это дало

За неделю: двухступенчатый грейс у Газпромбанка, который на витрине не виден; снижение нижней границы ПСК в автокредите Альфы на 1 п.п. после рекордного августа по выдачам; отсутствие статистически значимой связи между сервисным рейтингом и стоимостью риска на семи банках, которое я бы иначе продолжал считать очевидной. И привычка: когда числа проверяет код, а не автор, спорить с текстом становится проще, потому что видно, откуда взялась каждая цифра.

Все выпуски, схема воркфлоу и метрики evals: ageev.dev/credit-radar.