О проекте
Команда: ENRIQUE
Кейс HackAlem.ai: Телеком — Beeline
Стадия: Рабочий MVP
Задача кейса: Агент, который решает, каким абонентам какой тариф предложить (чистый прирост ARPU)
Суть
Статистический агент для кейса Beeline: выбирает сегменты абонентов, целевые тарифы и каналы коммуникации, проверяет гипотезы SMS-пилотами и формирует до 10 кампаний, максимизируя чистый прирост ARPU.
Как устроено
Аудитория группируется по текущему тарифу и ARPU-сегменту (LOW/MID/HIGH); история смен тарифов служит слабым приором для выбора целевого тарифа. Затем две волны SMS-пилотов (до 12 по 100 клиентов, потом до 4 по 200), результаты объединяются с приором с учётом размера выборки и неопределённости. Жадный последовательный отбор сравнивает push, SMS, рекламу и звонок по осторожному чистому эффекту и после каждой кампании пересчитывает остаток бюджета и лимит контактов; поверх Agent.act(env) есть Streamlit-демо.
Ключевые решения
- сегментация тариф×ARPU
- двухэтапные пилоты
- байесовское объединение приора и пилотов
- жадный отбор кампаний с лимитами
- сравнение каналов по осторожной оценке
Метрики
seed 42: чистый результат +3 465 618 у.е. (контакты 99 998 у.е.), 16 пилотов, 8 кампаний; seed 0–9: 10/10 положительных, медиана +3 533 049 у.е.
Особенности
Схема exploration→exploitation: широкие дешёвые пилоты, затем повторная проверка спорных гипотез перед тратой бюджета. В README подробно разобран пример расчёта на одной кампании и учёт того, что один абонент считается только по лучшей кампании. Команда честно предупреждает, что результат получен на мок-модели и не переносится на скрытую модель жюри.
Стек
Python · pandas · numpy · Streamlit
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-fb0999ac-enrique.
README
README.mdEnrique-agent
Задача
Агент выбирает сегменты клиентов, целевые тарифы и каналы связи для кампаний по смене тарифа. Он проверяет гипотезы на пилотах и формирует план, который должен увеличить ARPU за вычетом расходов на коммуникацию.
Данные и тарифы в кейсе синтетические. Результаты локальной проверки не являются прогнозом результата на судействе: там используется другая модель эффектов.
Гипотеза и её проверка
Мы предполагаем, что для группы с определённым текущим тарифом и уровнем ARPU другой тариф может увеличить выручку. Исторические переходы помогают выбрать, какую идею проверить первой. Они относятся к другой аудитории и не доказывают, что конкретный человек согласится на предложение. Проверка гипотезы — пилот на текущих абонентах.
flowchart LR
A["Текущий тариф и ARPU-сегмент"] --> C["Гипотеза: кому предложить какой тариф"]
B["История смен тарифов"] --> C
C --> D["SMS-пилот на текущей аудитории"]
D --> E["Наблюдаемый эффект с шумом"]
E --> F["Оценить прибыль и надёжность"]
F --> G["Включить в план или отклонить"]
Например, переход tariff_4 → tariff_8 выглядит осмысленным кандидатом: пакет интернета увеличивается с 4 до 8 ГБ, пакет минут — с 40 до 80. Это объясняет, почему предложение стоит проверить, но не гарантирует переход. Текущая версия агента формирует кандидатов по тарифу, ARPU-сегменту и истории; потребление интернета и звонков пока не участвует в выборе.
Как работает агент
Основная реализация находится в archive/agent.py и соответствует интерфейсу Agent.act(env).
- Группирует аудиторию по текущему тарифу и ARPU-сегменту (
LOW,MID,HIGH). Для каждой группы считает охват и среднийpredicted_arpu. - Использует историю смен тарифов из
archive/data/change_tariff.csvкак слабую подсказку для выбора гипотез. Историческая выборка отличается от целевой. - Проводит первый этап проверки: до 12 SMS-пилотов по 100 клиентов для широкого отбора гипотез. Затем повторно проверяет до 4 наиболее перспективных или неоднозначных гипотез SMS-пилотами по 200 клиентов. Пилоты расходуют общий бюджет и лимит контактов.
- Совмещает историческую оценку с шумными результатами пилотов с учётом их размера и неопределённости. Для каждого канала сравнивает ожидаемый и осторожный чистый эффект при фактически доступном бюджете и охвате; повторные контакты не считает новым охватом.
- Последовательно выбирает до 10 финальных кампаний и после каждого выбора пересчитывает доступные бюджет, контакты и варианты каналов.
flowchart TD
A["Группы по текущему тарифу и ARPU"] --> B["История: предварительный рейтинг переходов"]
B --> C["Выбор одного целевого тарифа на группу"]
C --> D["Этап 1: до 12 SMS-пилотов по 100 клиентов"]
D --> E["Этап 2: до 4 повторных SMS-пилотов по 200 клиентов"]
E --> F["Оценка эффекта и неопределённости"]
F --> G["Сравнение push, SMS, рекламы и звонка при оставшихся лимитах"]
G --> H{"Есть положительный чистый эффект?"}
H -- "Да" --> I["Выбрать кампанию и пересчитать остатки"]
I --> G
I --> J["Финальный план: до 10 кампаний"]
H -- "Нет" --> K["Остановить отбор"]
Чистый результат скорера равен сумме прироста ARPU по уникальным клиентам за вычетом стоимости всех контактов, включая пилоты и повторные контакты. Пилот даёт шумный результат для группы, а не вероятность перехода каждого отдельного абонента.
Это статистический агент с последовательным выбором гипотез; отдельная нейросеть или внешний LLM не используются. Эффект и итоговый балл рассчитываются предоставленной средой и скорером.
Откуда берётся чистый результат
Скорер считает модельный прирост ARPU, а не фактически полученные платежи. В локальной мок-модели для каждого затронутого абонента расчёт такой:
Эффект клиента = predicted_arpu
× среднее относительное изменение ARPU при переходе
× min(1, доля исторических переходов × множитель канала)
Чистый результат = сумма лучших эффектов по уникальным абонентам
− стоимость всех контактов, включая пилоты
Например, на seed=42 одна финальная кампания предлагает группе tariff_4 / MID перейти на tariff_8 через digital_ads. Она охватывает 1 227 человек со средним predicted_arpu около 4 760 у.е. Для этой пары тарифов мок-модель использует среднее изменение ARPU 39,45%, долю исторических переходов 60,90% и множитель рекламы 0,85:
4 760 × 39,45% × 60,90% × 0,85 ≈ 972 у.е. на человека
972 × 1 227 ≈ 1 192 642 у.е. валового прироста кампании
1 192 642 − (1 227 × 22) ≈ 1 165 648 у.е. после её расходов
Последняя строка показывает эффект кампании отдельно от остальных. При сложении всех кампаний и пилотов валовый прирост до устранения повторов составляет примерно 4 294 715 у.е. Из него скорер убирает около 729 100 у.е. повторно посчитанного эффекта: один абонент учитывается только по лучшей для него кампании. После вычета 99 998 у.е. затрат на все контакты получается 3 465 618 у.е. чистого прироста (точное вычисление выполняется до округления показанных чисел).
Доля исторических переходов в мок-модели не является измеренной вероятностью согласия на рекламу. Именно поэтому высокий локальный результат нельзя переносить на реальных клиентов или скрытую модель судейства.
Состав проекта
archive/agent.py— агент, который запускается и сдаётся.archive/agent_template.py— исходный демонстрационный шаблон.archive/environment.py,archive/mock_environment.py— интерфейс пилотов и локальная имитация среды.archive/scoring_core.py— проверка кампаний, применение лимитов и расчёт чистого результата.archive/local_eval.py— локальная оценка агента.archive/make_submission.py— генераторsubmission.csvс фиксированным seed.archive/customer_profile.csv— профиль целевой аудитории.archive/data/— история тарифов, месячный ARPU, трафик и машинный справочник тарифов.archive/tariff_dictionary.csv,archive/feature_dictionary.csv— справочники для чтения человеком.archive/PARTICIPANT_GUIDE.mdи.pdf— полное задание и правила кейса.
Запуск и воспроизведение
Нужен Python и библиотеки pandas, numpy. Все команды выполняются из папки archive/, так как скрипты используют относительные пути:
cd archive
python -m pip install pandas numpy
python local_eval.py
python local_eval.py --runs 10
python make_submission.py
local_eval.py без аргументов запускает seed 42. Режим --runs 10 запускает seed 0–9 и показывает устойчивость на разных случайных результатах пилотов. make_submission.py создаёт submission.csv; повторный запуск с тем же кодом и seed воспроизводит тот же план.
Результаты локальных прогонов
Проверено на мок-модели кейса с текущим archive/agent.py:
- seed 42: статус PASS, чистый результат +3 465 618 у.е. (+2,301% к baseline); валовый прирост 3 565 616 у.е., стоимость контактов 99 998 у.е.
- На seed 42 проведено 16 пилотов (12 по 100 и 4 по 200 клиентов) и сформировано 8 финальных кампаний. Всего скорер учёл 8 321 контакт с 6 747 уникальными абонентами. Число «24 кампании» в отчёте скорера включает 16 пилотов и 8 финальных кампаний; ограничение в 10 относится к финальному плану.
- Финальный план seed 42 использует 2 кампании
digital_ads, 1call, 1smsи 4push. Их сегменты, тарифы и каналы записаны вarchive/submission.csv. - seed 0–9: положительный результат в 10 из 10 прогонов; медиана +3 533 049 у.е., диапазон +2 586 971…+3 683 688 у.е. Меньшее значение на seed 6 показывает чувствительность выбора дорогого канала к шуму пилотов.
Это результаты локальной мок-модели, а не прогноз прибыли или балла на судействе.
Ограничения и дальнейшая работа
- Скрытые эффекты на судействе отличаются от мок-модели; локальный результат проверяет механику и поведение агента, но не будущий балл.
- Текущие кампании сегментируют по текущему тарифу и ARPU. Признаки потребления интернета и звонков доступны в профиле, но пока не входят в фильтры финального плана.
- Пилот возвращает агрегированную шумную оценку, а не индивидуальные результаты, поэтому доверительная оценка приближённая; полноценный bootstrap по клиентам недоступен.
- Исторические переходы — не рандомизированные отклики на маркетинговое предложение, поэтому используются только для приоритизации пилотов.
- Следующие улучшения: сравнить стратегии на одинаковых seed, добавить сегментацию по потреблению и проверить устойчивость распределения бюджета между дорогими каналами при неудачных пилотах.
Перед сдачей сверьте ограничения и формат артефактов с archive/PARTICIPANT_GUIDE.md.
Графическое демо
Установите зависимости из корня репозитория и запустите интерфейс:
python -m pip install -r requirements.txt
streamlit run app.py
Интерфейс запускает Agent.act(env) на локальной мок-среде и показывает пилоты, итоговый план, затраты и чистый результат. Мок-модель нужна для проверки механики и отличается от скрытой модели судейства.
Авторы коммитов
История коммитов
- 2026-09-23 17:03Update agent README with current results and scoring exampleNurdaulet Miron
- 2026-09-23 16:10Document agent hypothesis and decision flowNurdaulet Miron
- 2026-09-23 12:24Create ARSEN folderNurdaulet Miron
- 2026-09-23 11:54Create agenttetriagen
- 2026-09-23 11:53Create app.pytetriagen
- 2026-09-23 11:34Improve campaign allocation and confirm pilot hypothesestetriagen
- 2026-09-23 10:03Document Beeline campaign agenttetriagen
- 2026-09-23 09:31Improve tariff campaign agenttetriagen
Все коммиты (18)
- 2026-09-23 09:00Update agent guidance for Beeline casetetriagen
- 2026-09-23 08:53Add Beeline case package under archivetetriagen
- 2026-09-23 07:49Add project agent guidelinestetriagen
- 2026-09-23 07:44Remove ARSEN foldertetriagen
- 2026-09-23 17:21Update Enrique-agent dashboard and remove CSV exportnedepzhatsyn
- 2026-09-23 15:31Document how to run the demo UInedepzhatsyn
- 2026-09-23 15:30Add Streamlit dependencies for demo UInedepzhatsyn
- 2026-09-23 15:29Build Streamlit demo UI for Enrique-agentnedepzhatsyn
- 2026-09-23 15:12Rename README agent to Enrique-agentnedepzhatsyn
- 2026-09-23 15:08Name agent Enrique-agentnedepzhatsyn
Структура репозитория (21 файлов)
AGENTS.md README.md app.py archive/PARTICIPANT_GUIDE.md archive/PARTICIPANT_GUIDE.pdf archive/agent.py archive/agent_template.py archive/customer_profile.csv archive/data/arpu_monthly.csv archive/data/change_tariff.csv archive/data/dict_tariff.csv archive/data/traffic.csv archive/environment.py archive/feature_dictionary.csv archive/local_eval.py archive/make_submission.py archive/mock_environment.py archive/scoring_core.py archive/submission.csv archive/tariff_dictionary.csv requirements.txt
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.