О проекте
Команда: TAZART
Кейс HackAlem.ai: Телеком — Beeline
Стадия: Рабочий MVP
Задача кейса: Агент, который решает, каким абонентам какой тариф предложить (чистый прирост ARPU)
Суть
Streamlit-панель маркетолога и официальный агент Agent.act(env): агент проводит пилоты и собирает портфель из 1–10 тарифных кампаний (сегмент × тариф × канал) для максимизации чистого эффекта ARPU в рамках бюджета и лимита контактов.
Как устроено
По CSV абонентов и тарифов строятся сегменты и гипотезы. Агент тратит часть бюджета на до 20 пилотов в мок-среде, оценивает зашумлённые отклики и оптимизирует портфель при ограничениях: 100 000 у.е., 15 000 контактов, не больше 5 000 на кампанию. plan_validator проверяет ограничения, результат выгружается в submission.csv. В веб-демо модель OpenAI через Responses API выбирает порядок вызова локальных аналитических инструментов и объясняет выбор; без ключа всё считается локально.
Ключевые решения
- пилотное тестирование гипотез
- constrained portfolio optimization
- plan validation
- OpenAI Responses API tool calling
- scenario comparison по бюджету
Особенности
Числовой агент полностью детерминирован и работает без LLM, а LLM только выбирает порядок вызова аналитических инструментов и пишет объяснение. Интерфейс показывает отклонённые варианты и причины выбора. Можно сравнить сценарии при разных бюджетах.
Стек
Python · Streamlit · pandas · numpy
Модели
OpenAI (Responses API)
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-899436f0-tazart.
README
README.mdBeeline Tariff Marketing Campaigns Case
Штаб тарифных кампаний · by TAZART
Продукт помогает маркетологу выбрать тарифные кампании для роста ARPU (средней выручки на абонента) с учётом затрат на контакты, бюджета и лимита охвата. На синтетических данных кейса Beeline локальный агент проверяет гипотезы пилотами и рассчитывает портфель, а OpenAI-агент в веб-демо запрашивает локальные аналитические инструменты и объясняет получившийся выбор. Интерфейс показывает, почему выбраны конкретные сегменты, тарифы и каналы, на что расходуется бюджет и какие варианты отклонены. Результат — план, проверенный по ограничениям кейса, и CSV для выгрузки; продукт не отправляет сообщения абонентам. Числа кейса не описывают реальных абонентов или бизнес Beeline.
Проверяющему: запуск с OpenAI и без ключа
В репозитории есть исходники и данные для запуска. API-ключ команды в репозиторий не входит. Для проверки OpenAI-режима на другом компьютере нужен собственный действующий OPENAI_API_KEY и доступ к интернету.
| Режим | Что настроить | Что работает |
|---|---|---|
| Локальный, без OpenAI | Установить Python 3.12 и зависимости по инструкции ниже. .env не нужен. | Сегменты, гипотезы, пилоты, расчёт кампаний и KPI, проверка ограничений, причины отбора, сравнение бюджетов и выгрузка CSV. |
| С OpenAI | После установки добавить ключ в .env или окружение и запустить приложение. | Всё перечисленное, а также реальный выбор порядка аналитических инструментов моделью и её объяснение и рекомендация в интерфейсе. |
Если ключ отсутствует или API недоступен, приложение продолжает локальный расчёт и показывает «AI-сервис временно недоступен — используется локальный режим расчёта». Это предусмотренный режим, а не ошибка запуска. В этом режиме обращения к OpenAI не выполняются при отсутствии ключа; при недоступности сервиса расчёт продолжается после неудачной попытки подключения.
Порядок первого запуска: установить зависимости → при необходимости добавить ключ → запустить Streamlit → нажать «Сформировать оптимальный план». Официальный агент Agent.act(env) и подготовка submission.csv работают без OpenAI в обоих режимах.
Демо за 2–3 минуты
После установки и запуска приложения пройдите три шага:
- Откройте http://127.0.0.1:8501. Первый экран объясняет задачу, показывает ввод бюджета и исходный размер базы; показатели ниже рассчитаны по локальным CSV.
- Оставьте бюджет 100 000 у. е. и нажмите «Сформировать оптимальный план». Локальный агент проведёт пилоты и рассчитает кампании. Финальные KPI и карточки кампаний появятся в обоих режимах. При успешном подключении OpenAI появятся статус «AI-агент OpenAI: активен» и пояснения модели; без ключа — уведомление о локальном режиме.
- Проверьте блоки «Почему выбран именно этот план» и «Отклонённые варианты». Затем измените бюджет на 10 000 у. е., нажмите «Пересчитать план» и сравните два запуска в «Сценарном анализе». При текущих данных это меняет состав плана и его прогноз; на другом наборе данных изменение не гарантировано. Кнопка «Скачать текущий план» выгружает показанный сценарий.
Экран оформлен как рабочая панель маркетолога: крупный тёмный первый блок с жёлтыми акцентами и подписью by TAZART, схема База → Анализ → Гипотезы → Пилоты → Оптимизация → План, большие KPI и карточки кампаний. Под показателями указаны смысл и источник; результат объединяет прогноз, использование лимитов, причины выбора, отклонённые варианты и сравнение бюджетов. Иллюстрация сети аналитических действий в первом блоке показывает идею работы агента, а не дополнительные данные или результаты расчёта.
Появление KPI и результата, наведение на карточки и индикатор работы агента анимированы средствами CSS. При системной настройке уменьшения движения (prefers-reduced-motion) анимации отключаются. Интерфейс не использует видео или тяжёлые библиотеки анимации.
Прогноз на экране — оценка агента для финальных кампаний после затрат на них, без эффекта и затрат пилотов. Это не полученная выручка и не результат скрытого зачёта. Подробная проверка сценария и команды для официальной сдачи приведены ниже.
Официальный интерфейс — Agent.act(env) в agent.py: метод получает публичный объект среды, запускает пилоты и возвращает от 1 до 10 финальных кампаний. Каждая кампания задаёт сегмент абонентов, предлагаемый тариф и канал связи. Пилоты и финальные кампании расходуют общий бюджет до 100 000 у. е. и общий лимит 15 000 контактов. На одну финальную кампанию разрешено до 5 000 контактов, пилотов — до 20. Повторные обращения также расходуют лимит. Подключения к системам оператора нет. Официальный агент и все числовые расчёты работают локально и воспроизводимо; API-ключ нужен для AI-анализа и текста рекомендаций в веб-демо либо для отдельной проверки соединения.
Технологии и зависимости
Рабочая версия проверена на Python 3.12. Все прямые зависимости закреплены в requirements.txt:
| Пакет | Версия | Назначение |
|---|---|---|
numpy | 2.5.3 | Численные вычисления локальной среды и оценщика. |
pandas | 2.3.3 | Чтение CSV, сегментация и расчёт аудиторий. |
streamlit | 1.64.0 | Локальный веб-интерфейс. |
Исходные CSV из пакета участника должны лежать в корне проекта и в каталоге data/: customer_profile.csv, data/change_tariff.csv, data/dict_tariff.csv. Сохраняйте структуру каталогов: код читает файлы по относительным путям. Для установки пакетов через pip может потребоваться доступ к индексу пакетов. Веб-демо вызывает OpenAI Responses API через стандартную библиотеку Python, когда задан OPENAI_API_KEY; check_openai.py остаётся отдельной проверкой соединения без данных кейса.
Установка и запуск
Скачайте и распакуйте репозиторий целиком либо клонируйте его через Git. Откройте терминал в корне проекта, где находятся app.py и requirements.txt. Данные CSV уже включены; отдельно скачивать их не нужно.
1. Установите зависимости. На macOS/Linux:
python3 --version
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -r requirements.txt
python3 --version должен показать Python 3.12.x. Если python3 указывает на другую версию, создайте окружение командой python3.12 -m venv .venv.
В Windows PowerShell с установленным Python 3.12:
py -3.12 -m venv .venv
.\.venv\Scripts\python.exe -m pip install -r requirements.txt
2. Выберите режим. Для локального расчёта переходите к запуску. Для OpenAI создайте .env в корне проекта по шаблону .env.example и замените your_key_here своим ключом — подробная инструкция. Если .env уже существует, не перезаписывайте его. Ключ можно также задать через переменную окружения OPENAI_API_KEY.
3. Запустите приложение. На macOS/Linux в активированном окружении:
python -m streamlit run app.py --server.address 127.0.0.1 --server.port 8501
В Windows PowerShell:
.\.venv\Scripts\python.exe -m streamlit run app.py --server.address 127.0.0.1 --server.port 8501
4. Откройте http://127.0.0.1:8501 и нажмите «Сформировать оптимальный план». Сервер работает, пока запущена команда, и останавливается клавишами Ctrl+C. Если порт занят, замените номер порта и в команде, и в адресе браузера. После изменения ключа перезапустите сервер. Подтверждение успешного OpenAI-запуска — статус «AI-агент OpenAI: активен» после нажатия кнопки; одного наличия .env для этого недостаточно.
Проверка основного пользовательского сценария
- Откройте страницу «Штаб тарифных кампаний». Первый экран объясняет задачу, показывает размер текущей синтетической базы и даёт указать бюджет; ниже приведены показатели из локальных CSV.
- В блоке «Задайте бюджет и запустите агента» укажите сумму от 0 до 100 000 у. е. и нажмите «Сформировать оптимальный план». Сейчас поддержана цель «максимизация чистого финансового эффекта»; режимы без собственной логики расчёта не предлагаются. Для каждого запуска создаётся новая локальная мок-среда с выбранным бюджетом, и агент заново проводит пилоты.
- Просмотрите этапы работы: в AI-режиме OpenAI выбирает локальные аналитические действия; локальный агент формирует гипотезы, проводит пилоты, отбирает и проверяет план; затем «AI формирует и объясняет рекомендации». Пилотные наблюдения относятся только к текущему запуску. При успешном ответе Responses API статус показывает «AI-агент OpenAI: активен» и краткое объяснение. Если ключ отсутствует или API недоступен, появляется «AI-сервис временно недоступен — используется локальный режим расчёта»; локальный план и его проверка остаются доступны.
- В «Рекомендованном портфеле кампаний» проверьте число финальных кампаний (1–10), итоговый расход вместе с пилотами (не выше выбранного бюджета) и контакты (не больше 15 000). В карточках сегмент, тариф, канал, размер аудитории и стоимость должны соответствовать рассчитанному плану.
- Откройте «Почему выбран именно этот план» и «Отклонённые варианты». Объяснения должны ссылаться на вычисленные оценки или ограничения; если подходящих вариантов для показа нет, интерфейс должен сказать об этом прямо.
- Измените бюджет, нажмите «Пересчитать план» и в блоке «Сценарный анализ» сравните предыдущий и новый запуски: лимит, прогноз финальных кампаний, фактические расходы и контакты. Число кампаний и расходы могут измениться, но изменение состава плана не гарантируется. Сценарное сравнение не является результатом официального зачёта. Кнопка «Скачать текущий план» экспортирует показанный сценарий в CSV; для официальной сдачи отдельно запускайте
make_submission.py.
Как читать результат: наблюдение пилота — зашумлённый ответ локальной мок-среды; «прогноз эффекта финальных кампаний» — сумма оценок агента по выбранным кампаниям после их стоимости, но без вклада пилотов и поправки на пересечения с ними. Это не полученная выручка и не полный прогноз чистого результата всего запуска. local_eval.py выдаёт фактический результат публичной мок-модели по правилам скорера. В скрытом зачёте эффекты другие, поэтому ни прогноз агента, ни локальный мок-результат не являются обещанием будущего балла.
Реализованы все три слоя демонстрационного сценария: P0 — обзор, рабочее бюджетное ограничение, запуск настоящего агента, карточки плана и объяснения; P1 — этапы по событиям агента, отклонённые гипотезы и рассчитанные показатели; P2 — повторный запуск при новом бюджете и сравнение двух сценариев. OpenAI выбирает локальные аналитические действия и формулирует пояснение, но не задаёт числовые оценки и не изменяет рассчитанный портфель. Отправка сообщений и интеграция с системами Beeline не являются частью прототипа.
Проверка агента и подготовка файла сдачи
В новом терминале активируйте .venv и выполните из корня проекта:
python -m unittest discover -v
python local_eval.py
python local_eval.py --runs 10
python make_submission.py
Первый вызов запускает тесты правил финального плана, загрузки ключа, основного AI-сценария и локального режима при сбое. В тестах API заменён тестовыми ответами: реальный ключ и платные запросы не нужны. local_eval.py печатает пилоты, расходы и результат на мок-модели организаторов; его строка «Кампаний» считает пилоты вместе с финальными кампаниями, поэтому может быть больше 10. Серия из десяти запусков показывает чувствительность к шуму разных seed, а не будущий балл. make_submission.py создаёт submission.csv с фиксированным seed 42. Повторный запуск с тем же кодом и данными должен дать идентичный файл. Официальная точка входа на судействе остаётся Agent.act(env); в скрытой среде агент может принять другие решения. В Windows команды можно выполнять через .\.venv\Scripts\python.exe без активации окружения.
Архитектура и принцип работы
Веб-кнопка → OpenAI Responses API → выбор локальных аналитических инструментов
├→ анализ сегментов из синтетических CSV
├→ проверка гипотез и пилотов через Agent.act(env)
└→ расчёт кампаний и проверка ограничений
← обезличенные агрегаты ← локальный Python-код
→ краткое объяснение + рассчитанный локально план в интерфейсе
make_submission.py → Agent.act(env) → submission.csv для сдачи
Интерфейс запускает того же Agent.act(env), что и генератор сдачи; отдельного алгоритма расчёта для демонстрации нет. В ходе веб-запуска OpenAI Responses API выбирает и вызывает локальные инструменты анализа сегментов, проверки гипотез и расчёта кампаний. Эти инструменты используют уже существующий детерминированный Python-код. В API уходят только необходимые обезличенные агрегаты, без сырых строк абонентской базы, идентификаторов и ключей; полученный текст объясняет локально рассчитанный план. Ошибка API или отсутствие ключа переключает экран в локальный режим без изменения математики. Параметр бюджета в интерфейсе ограничен диапазоном 0–100 000 у. е. и задаёт лимит новой локальной среды до пилотов. При нулевом бюджете платные каналы недоступны, но бесплатный push может быть допустим. Для официального файла сдачи используется стандартный бюджет среды организаторов, без настройки из интерфейса.
Алгоритм работает так:
campaign_engine.pyочищает историю переходов: удаляет дубли, исключает исходный ARPU ниже 100 и ограничивает экстремальное относительное изменение. Она создаёт слабые prior для переходовcurrent_tariff × arpu_segment × target_tariff, дополняя отсутствующие сочетания тарифными характеристиками. Историческая доля переходов не трактуется как конверсия на предложение: таких данных нет.agent.pyвыбирает разнообразные гипотезы и запускает до 12 разведочных пилотов черезenv.run_pilot, обычно в бесплатном канале push. Для части пилотов он выбирает менее ценные подгруппы внутри базового сегмента: по правилам данного симулятора относительный эффект внутриcurrent_tariff × arpu_segmentодинаков, а возможный денежный ущерб от отрицательного пилота меньше.- По наблюдаемому эффекту пилотов агент обновляет среднее и неопределённость гипотезы с дисперсией шума
0.804² / n. При переносе результата между push, SMS и digital_ads корректно учитывается множитель канала в значении и дисперсии. До шести дополнительных SMS-пилотов подтверждают важные неопределённые гипотезы. - Отбор использует консервативную оценку эффекта и сравнивает каналы по приросту ARPU, стоимости контактов и доступному бюджету. Портфель строится из непересекающихся базовых сегментов. Звонки пока исключены: их цена 160 за контакт, а перенос эффекта с других каналов может ошибаться из-за насыщения конверсии.
plan_validator.pyпроверяет 1–10 кампаний, реальные размеры аудиторий, допустимые фильтры и тарифы, бюджет и охват после пилотов. Он отклоняет планы, которые официальный скорер молча обрезал бы. Если надёжно положительных кампаний нет, агент возвращает маленькую бесплатную push-кампанию с ограниченным возможным ущербом. При шести подряд отрицательных разведочных наблюдениях он прекращает дальнейшие пилоты, чтобы не расходовать оставшийся охват на слабые гипотезы.
Пилоты входят в общий результат и лимиты. Один клиент даёт эффект только по лучшему из полученных предложений, однако повторные контакты расходуют охват и бюджет. ID участников пилота агенту не раскрываются; прогнозы по пересечениям и итоговому уникальному охвату имеют неопределённость. Официальный risk_score нельзя отождествлять с вероятностью убытка из модели агента.
Файлы и данные
| Файл | Назначение |
|---|---|
agent.py | Официальный агент и журнал решений trace |
campaign_engine.py | Очистка истории и генерация гипотез |
plan_validator.py | Строгая проверка финального плана |
dashboard_service.py | Создаёт новую мок-среду с выбранным бюджетом, запускает настоящего агента, подготавливает расчёты и отдельно хранит оценки агента и результат мок-скорера |
openai_demo_agent.py | Вызывает OpenAI Responses API, предоставляет модели локальные аналитические инструменты с обезличенными агрегатами и возвращает текст рекомендаций; при сбое сохраняет локальный результат |
app.py | Русскоязычный экран «Штаб кампаний» на Streamlit |
assets/dashboard.css | Чёрно-бело-жёлтая тема, адаптивная компоновка и лёгкие анимации с учётом настройки уменьшения движения |
assets/strategy-network.svg | Локальная тематическая иллюстрация аналитической сети в первом блоке |
check_openai.py | Отдельный нейтральный тест доступности OpenAI API без данных кейса |
local_eval.py, make_submission.py, environment.py, scoring_core.py | Предоставленные организаторами интерфейс и локальная проверка |
customer_profile.csv, data/*.csv | Синтетические данные из пакета участника |
submission.csv | Воспроизводимый результат для сдачи |
Данные из ZIP участника находятся в корне и в data/. Не удаляйте их до окончания проверки: mock_environment.py, локальный оценщик и генератор submission читают эти относительные пути. Для отправки решения нужны код в командном GitHub, README и отдельная сдача на странице треков. Перед отправкой проверьте содержимое репозитория и воспроизводимость команды выше.
Параметры окружения и OpenAI API
| Параметр | Нужен для запуска? | Применение |
|---|---|---|
OPENAI_API_KEY | Для AI-режима веб-демо | Ключ OpenAI Responses API. Без него интерфейс автоматически показывает локальный режим; Agent.act(env), local_eval.py и make_submission.py работают без ключа. |
| Бюджет кампаний | Да, вводится в интерфейсе | Целое число 0–100 000 у. е.; задаёт лимит новой локальной среды до пилотов. Это не переменная окружения. |
| Начальное зерно случайности | Нет | Для веб-демонстрации и submission.csv используется фиксированное значение 42; local_eval.py --runs 10 запускает несколько seed. |
Единственная поддерживаемая бизнес-цель — максимизация финансового эффекта в пределах бюджета. Настройка меньшего бюджета в интерфейсе не меняет официальные правила сдачи и не записывается в submission.csv.
OpenAI нужен для выбора аналитических действий и понятного маркетологу объяснения уже рассчитанного плана. Все размеры аудиторий, пилотные оценки, расходы, финансовые показатели и ограничения вычисляет локальный Python-код. Ключ OpenAI создаётся в OpenAI Platform; код активации кредитов со страницы наград — не API-ключ. Подписка ChatGPT/Codex Pro также не заменяет ключ OpenAI API. NVIDIA API в текущем пользовательском сценарии не используется.
Если локального .env ещё нет, создайте его из шаблона в корне репозитория. Если он уже существует, не перезаписывайте его: проверьте в нём значение OPENAI_API_KEY.
cp .env.example .env
В новом .env замените заглушку на свой API-ключ. Строка в шаблоне выглядит так:
OPENAI_API_KEY=your_key_here
your_key_here — только заглушка: замените её в локальном .env, не в .env.example. Уже заданная переменная окружения OPENAI_API_KEY имеет приоритет: в этом случае .env не читается. Пустая переменная отключает AI-режим даже при наличии ключа в .env. После изменения ключа перезапустите Streamlit. .env исключён из Git, а .env.example разрешён; на macOS/Linux ограничьте доступ к ключу командой chmod 600 .env. Не добавляйте ключ в код, README, интерфейс и логи.
На сервере задайте OPENAI_API_KEY в разделе Secrets / Environment Variables панели хостинга и перезапустите приложение. .env на сервере не нужен. В Streamlit Community Cloud выберите app.py и Python 3.12, а в настройках Secrets добавьте запись верхнего уровня TOML OPENAI_API_KEY = "your_key_here", заменив заглушку своим ключом только в панели хостинга. Streamlit передаст её в окружение процесса; тот же код заработает без изменений. Посетителям опубликованного приложения вводить ключ не нужно; для самостоятельного запуска после clone владелец запуска должен задать свой ключ. См. настройку Streamlit Secrets и рекомендации OpenAI по серверным ключам.
Проверить только соединение можно отдельной командой из корня проекта:
python check_openai.py
Она отправляет один нейтральный текстовый запрос, не читает CSV и не передаёт данные кейса. Но для проверки основного сценария нужно запустить app.py, нажать «Сформировать оптимальный план» и убедиться, что появился статус «AI-агент OpenAI: активен». Блоки «Почему выбран этот план» и «Рекомендация» показывают текст фактического ответа OpenAI. В этом сценарии OpenAI Responses API получает результаты только локальных аналитических инструментов в виде обезличенных агрегатов; сырые строки абонентской базы не отправляются. Если ключ не задан или соединение не удалось, вместо этого виден статус «AI-сервис временно недоступен — используется локальный режим расчёта», при этом рассчитанный план остаётся доступен.
Официальный путь Agent.act(env) и файл сдачи не зависят от внешнего сервиса. Если даже отправка обезличенных агрегатов запрещена правилами вашего доступа к данным, не задавайте ключ для веб-демо и используйте локальный режим.
Держите командный GitHub закрытым для команды и организаторов. Не помещайте ключи в код, репозиторий, презентации, логи, чаты и скриншоты. Перед публикацией проверьте изменения на секреты и ограниченные данные. При утечке сообщите организаторам, отзовите ключ и создайте новый. После мероприятия удалите временные ключи и локальные копии предоставленных данных согласно инструкции организаторов.
Ограничения и следующие шаги
Это симулятор с синтетическими данными. История другой аудитории — только слабое начальное предположение; один пилот шумный, а 10 локальных seed меняют лишь шум мока. Нынешний портфель использует жадный поиск по стоимости бюджета и непересекающимся базовым сегментам, поэтому глобальный оптимум не гарантируется. Следующие улучшения: отдельная проверка звонков, стресс-тесты на сдвиге скрытых эффектов и более точный учёт ожидаемых пересечений пилотов.
Авторы коммитов
История коммитов
- 2026-09-23 17:53Clarify jury setup and OpenAI modes in READMEanuar_universe
- 2026-09-23 17:41Update README.mdanuaruniverse
- 2026-09-23 17:29Finalize portable OpenAI demo flow and deployment setupanuar_universe
- 2026-09-23 17:12Polish Demo Day dashboard and clarify business-facing copyanuar_universe
- 2026-09-23 16:50Integrate OpenAI agent into demo flow and polish dashboardanuar_universe
- 2026-09-23 16:06Improve campaign dashboard visual experienceanuar_universe
- 2026-09-23 15:43Build Beeline campaign optimizer MVPanuar_universe
- 2026-09-23 14:53Update README.mdanuaruniverse
Все коммиты (9)
- 2026-09-23 14:35Update README.mdanuaruniverse
Структура репозитория (33 файлов)
.env.example .gitignore PARTICIPANT_GUIDE.md PARTICIPANT_GUIDE.pdf README.md agent.py agent_template.py app.py assets/dashboard.css assets/strategy-network.svg campaign_engine.py check_openai.py config.py customer_profile.csv dashboard_service.py data/arpu_monthly.csv data/change_tariff.csv data/dict_tariff.csv data/traffic.csv environment.py feature_dictionary.csv local_eval.py make_submission.py mock_environment.py openai_demo_agent.py plan_validator.py requirements.txt scoring_core.py submission.csv tariff_dictionary.csv test_config.py test_openai_demo_agent.py test_plan_validator.py
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.