Adaptive Campaign Portfolio Agent
Агент тарифных кампаний Beeline. Ранжирует гипотезы по истории смен тарифов, проверяет их адаптивными SMS-пилотами и оптимизатором собирает портфель…
О проекте
Команда: Aid Soccer
Кейс HackAlem.ai: Телеком — Beeline
Стадия: Доведённый продукт
Задача кейса: Агент, который решает, каким абонентам какой тариф предложить (чистый прирост ARPU)
Суть
Агент тарифных кампаний Beeline. Ранжирует гипотезы по истории смен тарифов, проверяет их адаптивными SMS-пилотами и оптимизатором собирает портфель до 10 кампаний под бюджет и лимит контактов.
Как устроено
candidate_engine ранжирует до 40 гипотез по истории со shrinkage и учётом разнообразия ячеек. pilot_policy запускает до 10 разведочных пилотов по 80 контактов и до 5 подтверждений по 200. portfolio_optimizer одновременно выбирает канал (push/SMS/digital_ads), тариф и пропуск ячейки по mean/SE/safe lift; call исключён из-за насыщения конверсии. LLM-советник (OpenAI) видит только агрегаты гипотез и может предложить до двух пилотов. По умолчанию его ответ воспроизводится офлайн из artifacts/llm_policy.json по хешу контекста.
Ключевые решения
- historical shrinkage ranking
- adaptive pilots
- portfolio optimization under budget/reach
- safe lift (mean − SE)
- LLM replay by context hash
Метрики
Mock evaluator, seeds 0–9: средний net gain 2,898,763.77 против −480,836 у starter; положительных прогонов 10/10; seed 42 — 3,206,241.49; 147 тестов прошли
Особенности
Команда честно пишет, что LLM рост прибыли не дал: 11 живых запросов выбрали те же гипотезы, что и численный план. Детерминированный replay LLM-ответа по хешу контекста делает submission воспроизводимым. Опция adaptive_confirmation_n выключена по умолчанию, потому что ухудшила минимум.
Стек
Python · pandas · NumPy · pytest
Модели
OpenAI
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-dd3ffc75-aid-soccer.
README
README.mdAdaptive Campaign Portfolio Agent
Решение синтетического кейса Beeline для AI-хакатона. История переходов ранжирует
гипотезы, SMS-пилоты измеряют эффект на текущей аудитории, а оптимизатор выбирает
до 10 кампаний с учётом неопределённости, бюджета и охвата. Итоговая версия
объединена в main. Все команды выполняются из корня репозитория.
Обычный Agent() работает без сети и ключа: применяет сохранённую LLM-рекомендацию
при точном совпадении входного контекста, иначе использует численную политику.
Явный live-режим OpenAI доступен отдельно. Веса модели не обучались.
Быстрый запуск на новой машине
Нужны Git и Python 3.12. Проверенное окружение: Python 3.12.3, pandas 3.0.3, NumPy 2.4.4, pytest 9.0.2. Зависимости закреплены в requirements-файлах.
git clone --branch main https://github.com/BAITC-Hacks/hack-dd3ffc75-aid-soccer.git
cd hack-dd3ffc75-aid-soccer
python3.12 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -r requirements-dev.txt -r requirements-llm.txt
python -m pytest tests -q
python local_eval.py
python local_eval.py --runs 10
python -m tools.benchmark --runs 10 --compare-starter --trace-seed 42
python make_submission.py
python -m reporting --input reports/decision_trace.json --output reports/demo.html
Для работы обычного агента достаточно requirements.txt. Для полного набора
тестов, включая SDK через mock HTTP transport, команда выше также устанавливает
зависимости разработки и LLM. Тесты не вызывают внешний API. API-ключ для
официального evaluator и генерации submission не требуется.
Публичные CSV и неизменённые скрипты организаторов включены в репозиторий.
Папка beeline_case_participants с пробелом в конце содержит предыдущий
прототип; запускайте корневые скрипты, не эту копию. task/ для запуска не нужен.
Проверенные результаты
147 тестов прошли, в том числе в чистом экспорте без .env и task/.
В отдельной проверке чистого экспорта submission воспроизвёлся при отключённых
сети и импорте необязательных OpenAI SDK / dotenv.
Публичный mock evaluator, одинаковые seed 0–9 для нашего агента и starter:
| Метрика net gain, у.е. | Итоговый агент | Исходный agent_template |
|---|---|---|
| Среднее | 2,898,763.77 | -480,836.18 |
| Медиана | 3,103,097.10 | -357,947.80 |
| Минимум | 1,567,730.55 | -1,019,431.06 |
| Положительных прогонов | 10/10 | 0/10 |
Побед по одинаковым seed: 10/10. Starter оценивался без изменений: на seed 3
он вернул ноль финальных кампаний; его фактический результат только от пилотов
включён в сравнение и отмечен meets_final_count_requirement=false.
Во всех десяти прогонах итогового агента: 15 пилотов, 3–6 финальных кампаний, нет отброшенных кампаний и усечения по остаткам бюджета/охвата. Максимальные расходы — 96,542 / 100 000, контакты — 8,201 / 15 000. Максимальное измеренное время полного прогона — 0.599 с на проверенной машине; это офлайн-замер, не оценка задержки live API. Лимит задания — 600 секунд.
Seed 42: net gain 3,206,241.49, 15 пилотов + 4 финальные кампании, расходы 74 256, контакты 4 848. Число 19 в официальном отчёте включает пилоты; лимит 10 относится к финальному списку. После всего плана остаётся 25 744 бюджета; остаток, напечатанный evaluator после пилотов, отличается.
Доказательства: официальные 10 seed, seed 42, тесты, benchmark JSON, проверки чистого экспорта и submission, релизный отчёт, демо HTML. Числа относятся к публичной mock-среде и не предсказывают результат судейства.
LLM: фактическое поведение и live-проверка
llm_advisor.py передаёт модели до 40 агрегированных гипотез, параметры тарифов,
каналов и доступные ресурсы. Строки клиентов, их ID, скрытые эффекты, seed и
результаты evaluator в запрос не включаются. Модель может предложить до двух
существующих гипотез для пилотов; она не заменяет измеренные эффекты и проверки
лимитов. Если гипотезы уже выбраны, порядок пилотов сохраняется.
| Режим | Поведение |
|---|---|
Обычный Agent() | При наличии artifacts/llm_policy.json — офлайн-replay; при несовпадении контекста — численная политика. Без файла — off. |
Agent({"llm_mode": "off"}) | Численная политика без применения LLM-рекомендаций. |
Agent({"llm_mode": "assist"}) | До одного live-запроса на act; валидные рекомендации могут изменить выбор пилотов. |
Agent({"llm_mode": "shadow"}) | Запрос и запись рекомендации без влияния на выбор пилотов. |
Подстановка OPENAI_API_KEY сама по себе не включает live-режим обычного
Agent(). Автоматический переход к API на изменённых данных в текущей версии
не реализован. В live-режиме ключ читается из переменной окружения
OPENAI_API_KEY, как требует ТЗ. Только явно запущенный CLI дополнительно
загружает локальный .env; сам Agent() этого не делает.
Для локальной live-проверки после установки зависимостей:
# Создать шаблон только при отсутствии локального .env.
test -f .env || cp .env.example .env
chmod 600 .env
nano .env
# В редакторе заполнить OPENAI_API_KEY и сохранить файл.
python -m tools.llm_eval --check-config
python -m tools.llm_eval --mode assist --runs 1 --seed 42 \
--output-dir "reports/llm_runs/live-check-$(date +%Y%m%d-%H%M%S)"
Ожидается api_key_configured: true, затем llm_status=ok и API requests: 1.
Ключ не выводится и не должен попадать в Git. На судействе для явно включённого
live-режима достаточно переменной окружения; файл .env не нужен.
Таймауты, ошибки API, отсутствующий ключ и невалидные ответы переводят агента на численную политику. CLI возвращает ненулевой код при неудачной live-проверке, даже если запасная политика завершилась успешно. Сохранённый ответ привязан к хешам публичного контекста и инструкций; устаревшие рекомендации отвергаются.
В релизной проверке выполнено 11 успешных реальных API-запросов, включая 10 сравнительных live-прогонов. Модель каждый раз выбрала гипотезы, уже входившие в численный план, поэтому результаты совпали с baseline. Рост прибыли от LLM на этом наборе не подтверждён. Ответы и расход токенов.
Есть сбор примеров и экспорт проверенной разметки для будущего обучения. Веса модели пока не обучались; сохранённая рекомендация не является обученной моделью. Настройка, обновление рекомендации для новых данных и подготовка обучающих примеров: LLM_INTEGRATION.md.
Архитектура и опциональные требования
Agent.act(env)
-> generate_candidates(profile, history, tariffs)
-> LLM-рекомендация: replay / явно включённый live / off
-> run_adaptive_pilots(env, candidates)
-> build_campaigns(env, observations)
-> список финальных кампаний + last_trace
candidate_engine.py: устойчивое историческое ранжирование со shrinkage, разнообразием ячеек и каталожными альтернативами; до 40 гипотез по умолчанию.llm_advisor.py: ограниченные рекомендации, валидация ответа, чтение сохранённой политики и безопасное поведение при ошибках API.pilot_policy.py: до 10 разведочных SMS-пилотов по 80 контактов и до 5 адаптивно выбираемых подтверждений по 200. Оценки используют фактически возвращённые размеры выборок; отрицательные наблюдения сохраняются.portfolio_optimizer.py: совместный выбор push/SMS/digital_ads, тарифа и пропуска ячейки при ограничениях бюджета и охвата. Не более одной финальной кампании на ячейку; до 5000 клиентов в порядке числового ID на кампанию.agent.py: координация модулей, сброс trace на каждом запуске, контроль лимитов.tools/benchmark.pyиreporting.py: внешняя проверка и визуализация trace. Рендер отчёта не проводит новые пилоты и не меняет кампании.
Неопределённость учитывается через mean/SE/safe lift в нормализованных единицах; экономика применяет коэффициент канала один раз. Call исключён из-за насыщения конверсии. Выбор и число подтверждений зависят от измерений и ресурсов.
Дополнительный режим adaptive_confirmation_n=True подбирает также размер
подтверждений по текущей неопределённости. В десяти прогонах его медиана составила
3,002,247.39, минимум — 1,305,074.91, положительных — 10/10. Он ухудшил
минимум относительно основной политики, поэтому по умолчанию выключен.
Submission и состав сдачи
submission.csv генерируется неизменённым make_submission.py с seed 42.
Публичные sanitize_campaigns и validate_strategy приняли все четыре кампании.
Два запуска дали одинаковые байты; CSV соответствует сохранённому decision trace.
python make_submission.py
cp submission.csv /tmp/beeline-submission-first.csv
python make_submission.py
cmp submission.csv /tmp/beeline-submission-first.csv \
&& echo "OK: submission воспроизводится"
sha256sum submission.csv
Проверенный SHA-256:
3cba2865d369ad86c93e110476a4436c42f25c3583cbb9265382844e8e848e5e
CSV не редактируется вручную. После изменения кода, данных или сохранённой политики его нужно сгенерировать и проверить заново.
В сдаваемую версию включены:
agent.py,candidate_engine.py,pilot_policy.py,portfolio_optimizer.py,llm_advisor.pyиartifacts/llm_policy.json— модули и политика агента.submission.csv,requirements.txt,README.md.- Для live-режима и проверки:
requirements-llm.txt,requirements-dev.txt,tools/,tests/,reporting.py,docs/иreports/. - Публичные CSV,
data/и неизменённые скрипты организаторов для локального воспроизведения. Сохраните структуру путей при передаче проекта.
.env, виртуальное окружение, кеши Python и локальные исходники в task/
не нужны для сдачи. API-ключ передавать в составе проекта нельзя.
Ограничения и целостность
Исторический before/after lift среди сменивших тариф не доказывает причинный
эффект кампании. positive_rate не является конверсией, а prior_score —
прогнозом прибыли. История и текущая аудитория в предоставленных данных не
пересекаются по ID. На новой аудитории решения определяются её данными и пилотами.
После адаптивного отбора интервалы неопределённости являются эвристическими. Поиск ограниченной ширины не гарантирует глобальный оптимум. Точные ID пилотов недоступны агенту; оценки финального портфеля не изображают точную дедупликацию с пилотами. Фактический net gain считает официальный evaluator.
Когда нет положительной консервативной оценки, аварийная push-кампания явно помечается как рискованная: бесплатный контакт тоже может уменьшить выручку. Mock-эффекты отличаются от скрытой среды; результаты не являются прогнозом реального бизнеса или гарантией места на судействе.
Контрольные суммы подтверждают неизменность 15 файлов организаторов и данных. Дополнительные материалы: контракт, анализ данных, архитектура, демо.
Авторы коммитов
История коммитов
- 2026-09-23 17:57Finalize submission READMExretsam
- 2026-09-23 17:35Finish verified LLM advice, deterministic replay, and adaptive sizing optionxretsam
- 2026-09-23 17:17Prepare optional LLM exploration and reviewed training-data workflowxretsam
- 2026-09-23 16:40Integrate final campaign agent and verify official release artifactsxretsam
- 2026-09-23 16:33Add tariff campaign optimization agentaitzhxn
- 2026-09-23 16:33Implement contract-compliant historical prior candidate enginexretsam
- 2026-09-23 16:33Implement bounded campaign portfolio optimizeraitzhxn
- 2026-09-23 16:33Add analyst report and portfolio documentationaitzhxn
Все коммиты (15)
- 2026-09-23 16:26Implement contract-compliant historical prior candidate enginexretsam
- 2026-09-23 16:05Add analyst report and portfolio documentationaitzhxn
- 2026-09-23 16:03Implement bounded campaign portfolio optimizeraitzhxn
- 2026-09-23 16:00Fix pilot resource accounting and preserve failure diagnosticsayanamantay
- 2026-09-23 15:49Implement adaptive SMS pilots and tested integration handoffayanamantay
- 2026-09-23 15:43Add tariff campaign optimization agentaitzhxn
- 2026-09-23 14:49Add pilot-guided Beeline campaign agent and team architecturexretsam
Структура репозитория (104 файлов)
.env.example .gitignore PARTICIPANT_GUIDE.md PARTICIPANT_GUIDE.pdf PROMTS/00_START_HERE.md PROMTS/01_STUDENT_PRIOR.md PROMTS/03_STUDENT_PORTFOLIO.md PROMTS/04_FINAL_INTEGRATION.md PROMTS/SHARED_CONTRACT.md README.md agent.py agent_template.py artifacts/llm_policy.json beeline_case_participants /ANALYSIS.md beeline_case_participants /PARTICIPANT_GUIDE.md beeline_case_participants /PARTICIPANT_GUIDE.pdf beeline_case_participants /agent.py beeline_case_participants /agent_template.py beeline_case_participants /candidate_engine.py beeline_case_participants /customer_profile.csv beeline_case_participants /data/arpu_monthly.csv beeline_case_participants /data/change_tariff.csv beeline_case_participants /data/dict_tariff.csv beeline_case_participants /data/traffic.csv beeline_case_participants /environment.py beeline_case_participants /feature_dictionary.csv beeline_case_participants /local_eval.py beeline_case_participants /make_submission.py beeline_case_participants /mock_environment.py beeline_case_participants /scoring_core.py beeline_case_participants /submission.csv beeline_case_participants /tariff_dictionary.csv beeline_case_participants /test_candidate_engine.py candidate_engine.py customer_profile.csv data/arpu_monthly.csv data/change_tariff.csv data/dict_tariff.csv data/traffic.csv docs/ARCHITECTURE.md docs/DATA_FINDINGS.md docs/DEMO.md docs/LLM_INTEGRATION.md environment.py feature_dictionary.csv llm_advisor.py local_eval.py make_submission.py mock_environment.py pilot_policy.py portfolio_optimizer.py reporting.py reports/FINAL_RELEASE.md reports/LLM_RELEASE.md reports/benchmark.csv reports/benchmark.json reports/benchmark.md reports/benchmark_integration_checklist.md reports/benchmark_run.txt reports/clean_checkout_tests.txt reports/clean_checkout_verification.json reports/data_audit.json reports/decision_trace.json reports/demo.html reports/llm_clean_export_submission.txt reports/llm_clean_export_tests.txt reports/llm_final_10_seeds.txt reports/llm_final_benchmark.log reports/llm_final_seed42.txt reports/llm_final_submission_first.txt reports/llm_final_submission_second.txt reports/llm_final_tests.txt reports/llm_final_verification.json reports/llm_live_evidence.json reports/llm_preparation_10_seeds.txt reports/llm_preparation_tests.txt reports/llm_preparation_verification.json reports/local_eval_10_seeds.txt reports/local_eval_seed42.txt reports/organizer_integrity.json reports/submission_generation.txt reports/submission_regeneration.txt reports/submission_verification.json reports/tests.txt requirements-dev.txt requirements-llm.txt requirements.txt scoring_core.py submission.csv tariff_dictionary.csv tests/test_agent_integration.py tests/test_candidate_engine.py tests/test_llm_advisor.py tests/test_llm_cli.py tests/test_llm_replay.py tests/test_pilot_policy.py tests/test_portfolio_optimizer.py tests/test_reporting.py tests/test_training_data.py tools/benchmark.py tools/export_training_data.py tools/freeze_llm_policy.py tools/llm_eval.py tools/profile_data.py
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.