Финансы · банк

Агент проверки гипотез: десятки тысяч сочетаний на стандартных данных хранилища

Сила агента — пересечения: 20 типов данных из той же базы дают 21 679 сочетаний, команде аналитиков их не перебрать.

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

Агент знает схему хранилища, сам пишет SQL и проверяет гипотезу за минуты. Точки роста он находит в поведении каждого клиента — в итогах по сегментам их не видно.

Посмотреть в работе
  • 8 рабочих днейхватило пилоту, чтобы найти точки роста бизнесаклассический цикл одной гипотезы — недели
  • ≈70%найденных точек роста скрыто в деталях поведения клиентовклассический процесс их пропустил бы
  • 400+ часовработы аналитика освободилось за те же 8 днейаналитик — уже не исполнитель выгрузок, а куратор агента
  • 7⁠–⁠10 в деньпроверенных гипотез вместо 2⁠–⁠3 итераций в неделю
  • 21 679сочетаний из 20 типов данных перебирает агентаналитик за итерацию смотрит ~10 разрезов — оценка по пилоту

Чем агент отличается от дашборда и аналитика

Дашборд покажет готовое, аналитик — через дни, агент — за минуты

Выберите вопрос — ответят все три.

Дашборд

Мониторинг бизнеса

сразу

Падение видно, состав — нет

Покажет, что доход и число клиентов снизились. Не покажет, какая часть потерь — от ушедших, а какая — от тех, кто остался и платит меньше.

Финансовый аналитик

Выгрузки и расчёты под запрос

3–5 дней

Разбор по каждому клиенту

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

AI-агент

Проверка гипотез вместе с продуктологом

1–10 минут

Состав падения, сверенный с итогом

Делит клиентов на ушедших, новых и оставшихся с меньшим доходом и считает вклад групп и продуктов. Видно, что делать первым: возвращать ушедших или растить доход оставшихся.

Сроки — оценка по работе продуктовых команд и пилоту аналогичного агента.

Кому агент меняет работу и что получает банк

Узкое место одно — выигрывают трое

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

Продуктолог

проверяет гипотезы

Заказывает выгрузку и ждёт дни. Успевает 2⁠–⁠3 итерации гипотезы в неделю.

Спрашивает агента обычными словами или берёт готовый шаблон вопроса.

7⁠–⁠10 проверенных гипотез и около 36 инсайтов в день.

Продукт выходит на рынок с проверенными гипотезами, а не с догадками.

Финансовый аналитик

исполнитель выгрузок → куратор агента

Тратит до 60⁠–⁠70% времени на рутинные выгрузки. Один аналитик на команду.

Курирует агента: берёт сложные расчёты, проверяет выводы, пополняет его знания о данных.

1⁠–⁠2 аналитика на 5⁠–⁠10 команд: новые команды — без найма.

Фонд оплаты труда не растёт с числом команд. Аналитики заняты сложными расчётами, а не выгрузками.

Сеть продаж

продаёт на местах

Получает отчёты сверху; сравнить своё отделение с лучшими нечем.

Отделение само смотрит свой профиль и сравнивает с лучшими.

Отделения перенимают практики лучших.

Растут проникновение продуктов и кросс-продажи.

Цифры — из пилота аналогичного агента; сколько команд закрывает один аналитик — расчёт по ним.

Как агент это делает и почему его ответам можно верить

Агент сам пишет запрос — и проверяет себя до ответа

Продуктолог ставит задачу — без очереди к аналитику

Сначала агент читает свои правила и схему базы

Агент сверяет задачу с данными и строит гипотезы

Агент выгружает сам — только чтение и откат

По пути агент находит новые гипотезы — решает продуктолог

Продуктолог ставит задачу: «где вырастить доход от эквайринга?». Агент сначала читает свои правила (read only: SELECT, WITH, EXPLAIN; months: closed only; client income: income_month; missing data: name it, do not guess) и схему витрины mart.client_month: region — регион, industry — отрасль, status — активный клиент, acquiring_active_flag — эквайринг, income_month — доход клиента, month — закрытый месяц. Сверяет задачу с данными: «эквайринг» — acquiring_active_flag; «доход» — income_month; «где» — region × industry; «доход от эквайринга» — нет, в витрине такого поля нет: считаем доход клиентов с эквайрингом. Строит гипотезы: 1) слабые регионы отстают от портфеля; 2) в каких отраслях эквайринг берут реже; 3) похожие клиенты уже с эквайрингом; 1 и 2 проверит один запрос, 3 — следом. Пишет SQL; защита пропускает только select, with, explain, а delete отклоняет: Write/admin SQL is blocked. База выполняет запрос только на чтение и откатывает его: rows 14 · 2,8 s · ROLLBACK. Ответ: клиентов с эквайрингом — Регион 1, 20%; в среднем по портфелю — 47%; разрыв — +260 млн ₽/мес, пример расчёта для крупного банка. По пути агент заметил: платежи тают у части клиентов — риск оттока? — копать; новые когорты держатся лучше — дело в тарифе? — отложить; второго продукта нет — кросс-продажа? — копать. Решает продуктолог: копать сейчас или отложить.

Реконструкция сессии, цифры условные; разрыв в деньгах — пример расчёта для крупного банка. Правила агента и запрос — реконструкция по приёмам боевого кода; поля витрины и строки защиты — код автора · обезличено.

Не сошлось — агент сам ищет причину

Средний доход сегмента вышел нулём: segment — малый бизнес, открыт в этом году; clients — 124 000; avg_revenue — 0. Агент не отвечает «Данные не сошлись», а проверяет три гипотезы: период — причина, совпадения — следствие, единицы — снята. Причина: август загружен на 12% от обычного объёма. Вывод: август не закрыт — считаем по последнему полному.

Данные синтетические; запросы — код автора · обезличено.

Та же база — 20 типов данных, десятки тысяч сочетаний

База остаётся той же: новых таблиц нет. Агент пересекает 20 типов данных — платежи: входящие платежи, исходящие платежи, контрагенты, обороты по картам, эквайринг; продукты: счёт и тариф, кредиты, депозиты и остатки, зарплатный проект, бизнес-карты; клиент: отрасль, регион, размер бизнеса, возраст компании, каналы обслуживания; динамика: сезонность, когорта прихода, доход с клиента, обращения и отзывы, отток и возврат. По 2 типа — 190 сочетаний, По 3 типа — 1 140 сочетаний, По 4 типа — 4 845 сочетаний, По 5 типов — 15 504 сочетаний; всего 21 679. Потом агент пропускает сочетания через фильтры, по одному на находку: похожие клиенты — отрасль, регион, размер бизнеса, обороты по картам; сезонный провал — сезонность, обороты по картам, входящие платежи; платежи тают — входящие платежи, исходящие платежи, отток и возврат; карты без эквайринга — бизнес-карты, эквайринг, обороты по картам. Аналитик смотрит ~10 разрезов за итерацию, агент — 20–30+ разрезов на гипотезу.

Типы данных — примеры; сочетания — по 2⁠–⁠5 из 20 типов; разрезы за итерацию и на гипотезу — пилот аналогичного агента.

Без доказательств агент не выдаёт гипотезу за тезис

Вопрос: Где проникновение эквайринга ниже среднего по портфелю и сколько это стоит? База отдаёт доказательства: penetration_by_region: Регион 1 — 20% · Регион 2 — 63%; portfolio_norm: в среднем 47%; income_with_product: 8 150 ₽ на клиента; client_reviews: statement timeout, необязательный источник. Coverage score — 100 из 100. «В Регионе 1 проникновение вдвое ниже среднего по портфелю» — тезис; «Разрыв стоит денег каждый месяц» — тезис; «Часть клиентов не подключает эквайринг из-за комиссии» — гипотеза, запрос данных: отзывы клиентов об эквайринге за полгода.

Данные в карточках синтетические; шлюз доказательств — код автора · обезличено.

Каждое уточнение — новый круг очереди. У агента — минуты

Агент готовит презентацию за день — запуск на 1⁠–⁠6 недель раньше

После запуска агент отделит эффект акции от других

Продуктологу нужен анализ данных. Классическая цепочка: продуктолог — финансовый аналитик — финансовый департамент. Выгрузка занимает 0,5⁠–⁠3 дня, очередь до недели; каждое уточнение возвращает вопрос аналитику: ещё 4 ч — 1 неделя. После 4 уточнений цепочка занимает 2,5–28 раб. дн., агент — 5–50 мин. Дальше защита идеи: неделя на презентацию и неделя на согласование; презентацию с данными, графиками и текстами агент собирает за 1 день. Time to market до запуска: 12,5–38 раб. дн. без агента, ≈6 раб. дн. с агентом. Через 3–6 месяцев после запуска эффекты нескольких акций на одной базе клиентов смешаны; агент отделяет эффект каждой по тому, как менялось поведение клиентов: разбор без агента — 4 ч — 8 раб. дн., с агентом — 1–10 мин.

Оценка по цепочке: выгрузка 0,5⁠–⁠3 дня и очередь до недели, уточнение — от 4 часов до недели, защита идеи — две недели, разбор эффекта — одна выгрузка через цепочку; с агентом цикл 1⁠–⁠10 минут, презентация — день, согласование — прежняя неделя.

Код этого раздела
Text
prompts/data-rules.mdреконструкция по приёмам боевого кода
# Data rules the analyst agent reads before a task (reconstruction on top of the production prompts) read only: SELECT, WITH, EXPLAINmonths: closed onlyactive client: status = 'active'client income: income_monthgroups under :min_clients: hiddenmissing data: name it, do not guessevery figure: the query it came from

Что агент уже нашёл в данных

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

Суммы и число клиентов в карточках — пример расчёта для крупного банка: реальные цифры закрыты NDA. Три находки — из пилота аналогичного агента: за 8 рабочих дней 306 запросов дали 61 гипотезу и 329 инсайтов. Персональный кэшбэк — из практики автора. Ниже четыре находки; другие точки роста пилот нашёл в активации клиентов, продажах по городам и новых срезах клиентской базы.

«Около 70% находок пилота скрыты в деталях поведения клиентов классический процесс их пропустил бы: они видны только на пересечении нестандартных срезов, аномалий и разных источников.»

Итог разбора · Автор решения: постановка задачи, устройство агента, метрики для пилота, дорожная карта.

Нажмите на находку — ниже появится ход агента к ней, под ним запрос.

Находка 1 из 4 · пример расчёта для крупного банка

Разрыв проникновения между регионами

В сильном регионе ключевой продукт у 63% клиентов сегмента, в слабом — у 20%. В пересчёте на крупный банк подтянуть слабые регионы до среднего по портфелю — это плюс 260 млн рублей в месяц.

Ход агента: каждый ответ рождает новый вопросв пилоте на одну гипотезу — 20–30+ разрезов данных · ход — реконструкция

  1. Где ключевой продукт берут реже, чем в среднем по портфелю?

    регион × отрасльв слабом регионе — 20%, в сильном — 63%

  2. новый вопрос

    Разрыв во всём регионе или в отдельных отраслях?

    тот же срез по отраслямв отдельных отраслях, остальные на уровне портфеля

  3. новый вопрос

    Кто в этих отраслях уже активно пользуется банком?

    оборот по картамчасть клиентов каждый месяц платит картами банка

  4. пересечение 2 × 3

    Кого подключать первым?

    слабые отрасли × оборот по картамклиентов с оборотом по картам, но без продукта

  5. новый вопрос

    Почему они не подключают продукт?

    отзывы клиентовкомиссия — гипотеза, агент просит данные

Находка+260 млн ₽/меспример расчёта для крупного банка

Запрос, который дал находку
Разрыв проникновенияSQL
queries/penetration-gap.sqlреконструкция по приёмам боевого кода
WITH base AS (  SELECT region, industry,         COUNT(*) AS clients,         AVG(acquiring_active_flag::numeric) AS penetration,         AVG(income_month) FILTER (WHERE acquiring_active_flag = 1) AS income_with_product  FROM mart.client_month  WHERE month = :month AND status = 'active'  GROUP BY region, industry  HAVING COUNT(*) >= :min_clients),portfolio AS (  SELECT industry, AVG(acquiring_active_flag::numeric) AS portfolio_penetration  FROM mart.client_month  WHERE month = :month AND status = 'active'  GROUP BY industry)SELECT b.region, b.industry, b.clients,       ROUND(100 * b.penetration, 1) AS penetration_pct,       ROUND(100 * p.portfolio_penetration, 1) AS portfolio_pct,       ROUND((p.portfolio_penetration - b.penetration) * b.clients * b.income_with_product) AS monthly_gapFROM base bJOIN portfolio p USING (industry)WHERE b.penetration < p.portfolio_penetrationORDER BY monthly_gap DESC;

Метод

Тот же бюджет удержания — в 8 раз больше уходящих: у агента до них доходят 80 предложений из 100, по дашборду — 10

Агент разбирает каждого клиента: сводит данные хранилища с тем, что говорили ушедшие клиенты с похожим поведением и набором продуктов, и называет вероятную причину ухода. Банк тратит на удержание меньше или на те же деньги удерживает больше клиентов.

Кто выбирает, кому отправить предложение

Что видит агент

  • данные хранилища: оборот, платежи, остатки, продукты
  • голос ушедших: что они говорили в звонках и отзывах
  • похожие клиенты: поведение и набор продуктов
Клетка — 10 клиентов. Горят клетки, получившие предложение: красные собирались уйти, жёлтые — нет, им предложение ушло впустую. Тусклые красные уйдут без предложения. Точность 10%, 30% и 80% — практика автора; клетки и причины — синтетические данные.
Получили предложение1 000 клиентов
Собирались уйти800предложение дошло
Впустую200уходить не собирались

Агент выбирает клиентов по одному: из 1 000 получивших предложение уйти собирались 800, и для каждого известна вероятная причина. Тот же бюджет доходит до уходящих в 8 раз чаще, чем акция по дашборду.

Почему уходят — по словам ушедших клиентов с похожим поведением

  • дорого обслуживание35%
  • у другого банка выгоднее ставка25%
  • нет нужного продукта20%
  • долго решают проблемы20%

Чтобы предложение дошло до 100 уходящих клиентов, по дашборду нужно 1 000 предложений, по отчёту аналитика — 333, агенту — 125. Экономию можно оставить банку или вложить в более сильное предложение тем, кто уходит.

С чего агент начинает: сигналы угасания по каждому клиенту
Балл риска оттокаSQL
queries/churn-risk.sqlреконструкция по приёмам боевого кода
WITH signals AS (  SELECT client_id,         (turnover_3m < 0.5 * turnover_prev_3m)::int AS turnover_fell,         (days_since_last_payment > 45)::int AS went_quiet,         (balance_avg_3m < 0.7 * balance_avg_prev_3m)::int AS balance_fell,         (products_closed_3m > 0)::int AS closed_product  FROM mart.client_month  WHERE month = :month AND status = 'active'),scored AS (  SELECT client_id,         turnover_fell + went_quiet + balance_fell + closed_product AS risk_score  FROM signals)SELECT client_id, risk_scoreFROM scoredWHERE risk_score >= 3ORDER BY risk_score DESC;

Во что это складывается для банка

Продуктолог с агентом проверяет 7⁠–⁠10 гипотез в день

Показатели из презентации, без пересчёта на команду и месяц.

Источник цифр — внешний пилот аналогичного агента. За 8 рабочих дней: 11 сессий, 306 запросов, 61 гипотеза, 329 инсайтов, 277 аналитических обращений; освободилось 400+ часов работы аналитика.

Медианный цикл проверки гипотезы. Было — недели.

~10 мин

Обращения к данным без очереди. За 11 сессий пилота.

277 обращений

Производительность за день. Гипотезы и инсайты — отдельные показатели.

Гипотез в день на одного продуктолога
7⁠–⁠10
Инсайтов и точек роста в день
~36

Что нужно для запуска и где стоят замки

Пилот за 1⁠–⁠2 месяца — в закрытом контуре банка

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

Что нужно

  1. только чтение

    Данные и контур

    Агент работает с обезличенным срезом хранилища внутри закрытого контура банка. Каждый запрос проходит защиту: только SELECT, WITH и EXPLAIN, только чтение, таймаут и откат. Менять код, настройки и базу агент не может — это делает агент-исполнитель по заявке, после проверки.

    Ошибка агента не доходит ни до данных, ни до решения

    Пример рабочей доски спринта: люди, компании и числа вымышлены
    Код контура: защита, доказательства, правило агента
    Bash
    scripts/db-query.shкод автора · обезличено
    #!/usr/bin/env bashset -euo pipefail STACK_DIR="ops/analytics-db"ENV_FILE="$STACK_DIR/.env"COMPOSE=(docker compose --env-file "$ENV_FILE" -f "$STACK_DIR/docker-compose.yml") set -asource "$ENV_FILE"  # credentials stay on the server, never in the reposet +a if [[ $# -gt 0 ]]; then  SQL="$*"else  SQL="$(cat)"fi SQL_TRIMMED="$(printf '%s' "$SQL" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"SQL_LOWER="$(printf '%s' "$SQL_TRIMMED" | tr '[:upper:]' '[:lower:]')" if [[ -z "$SQL_TRIMMED" ]]; then  echo "Empty SQL" >&2  exit 2fi if [[ ! "$SQL_LOWER" =~ ^(select|with|explain)[[:space:]] ]]; then  echo "Only SELECT/WITH/EXPLAIN queries are allowed" >&2  exit 2fi if [[ "$SQL_LOWER" =~ (^|[^a-z])(insert|update|delete|drop|alter|create|truncate|grant|revoke|copy|vacuum|analyze|call|do)([^a-z]|$) ]]; then  echo "Write/admin SQL is blocked" >&2  exit 2fi "${COMPOSE[@]}" exec -T -e PGPASSWORD \  postgres psql -v ON_ERROR_STOP=1 -U "$READONLY_USER" -d "$ANALYTICS_DB" -P pager=off \    -c "BEGIN READ ONLY; SET LOCAL statement_timeout = '15s'; SET LOCAL lock_timeout = '2s'; ${SQL_TRIMMED}; ROLLBACK;"

Этапы

только чтение

Данные и контур

Агент работает с обезличенным срезом хранилища внутри закрытого контура банка. Каждый запрос проходит защиту: только SELECT, WITH и EXPLAIN, только чтение, таймаут и откат. Менять код, настройки и базу агент не может — это делает агент-исполнитель по заявке, после проверки.

Ошибка агента не доходит ни до данных, ни до решения

Пример рабочей доски спринта: люди, компании и числа вымышлены
Код контура: защита, доказательства, правило агента
Bash
scripts/db-query.shкод автора · обезличено
#!/usr/bin/env bashset -euo pipefail STACK_DIR="ops/analytics-db"ENV_FILE="$STACK_DIR/.env"COMPOSE=(docker compose --env-file "$ENV_FILE" -f "$STACK_DIR/docker-compose.yml") set -asource "$ENV_FILE"  # credentials stay on the server, never in the reposet +a if [[ $# -gt 0 ]]; then  SQL="$*"else  SQL="$(cat)"fi SQL_TRIMMED="$(printf '%s' "$SQL" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"SQL_LOWER="$(printf '%s' "$SQL_TRIMMED" | tr '[:upper:]' '[:lower:]')" if [[ -z "$SQL_TRIMMED" ]]; then  echo "Empty SQL" >&2  exit 2fi if [[ ! "$SQL_LOWER" =~ ^(select|with|explain)[[:space:]] ]]; then  echo "Only SELECT/WITH/EXPLAIN queries are allowed" >&2  exit 2fi if [[ "$SQL_LOWER" =~ (^|[^a-z])(insert|update|delete|drop|alter|create|truncate|grant|revoke|copy|vacuum|analyze|call|do)([^a-z]|$) ]]; then  echo "Write/admin SQL is blocked" >&2  exit 2fi "${COMPOSE[@]}" exec -T -e PGPASSWORD \  postgres psql -v ON_ERROR_STOP=1 -U "$READONLY_USER" -d "$ANALYTICS_DB" -P pager=off \    -c "BEGIN READ ONLY; SET LOCAL statement_timeout = '15s'; SET LOCAL lock_timeout = '2s'; ${SQL_TRIMMED}; ROLLBACK;"

Пример рабочей доски спринта: люди, компании и числа вымышлены

Что замерить до и после пилота

Проверка гипотез, пересобранная вокруг агента

  1. от вопроса до ответа

    Вопрос

    Было

    Заявка аналитику и очередь до недели

    С агентом

    Задача агенту — ответ за минуты

    В пилоте меряем: срок проверки гипотезы

    Цифры: пилот аналогичного агента

от вопроса до ответа

Вопрос

Было

Заявка аналитику и очередь до недели

С агентом

Задача агенту — ответ за минуты

В пилоте меряем: срок проверки гипотезы

Цифры: пилот аналогичного агента

Пилот идёт 1⁠–⁠2 месяца на одном продуктовом направлении, агент работает с обезличенным срезом хранилища. До и после пилота замеряют срок проверки гипотезы, число проверенных гипотез и время аналитика на команду.

  • код автора · обезличенокод, который работает в агентах автора; имена систем, пути и доступы заменены.
  • перенесено из боевого кода · проверено тестамибоевой код, перенесённый на TypeScript: защита отвечает на 28 тестовых запросов так же, как боевой скрипт, а подсчёт доказательств работает в шаге «Доказательства» выше.
  • реконструкция по приёмам боевого кодазапросы, написанные для страницы теми же приёмами.