О проекте
Команда: AVM AI
Кейс HackAlem.ai: Спецтрек — Astana Innovations
Стадия: Доведённый продукт
Задача кейса: «Аким на 5 часов»: городской симулятор, распределяющий бюджет по 5 направлениям и 5 районам
Суть
Симулятор городского бюджета на FastAPI. Проверяет правила, считает Astana QoL Score, предлагает замены мер, сравнивает план с полным перебором всех допустимых планов и объясняет результат через LLM с проверкой фактов.
Как устроено
Пакет engine/ на Python включает модель данных, валидатор с кодами ошибок и scoring (лаг, синергии, клиппинг, веса показателей и долей населения). Советник ищет до трёх лучших замен одной меры. Полным перебором построен индекс top_sets.json: 694 395 допустимых планов, топ-100, квантили и Парето-граница. По нему считается ранг сценария. Объяснение LLM проверяется по JSON-схеме, ссылкам на факты и допустимым числам, при ошибке включается шаблонный разбор. Фронт на чистом JS раздаётся тем же FastAPI.
Ключевые решения
- полный перебор 694 395 планов
- Парето-граница стоимость/Score
- квантильный перцентиль
- замена одной меры
- валидация LLM-ответа по JSON-схеме и числам
- шаблонный fallback
- humanizer-стиль промптов
Метрики
Полный перебор: 694 395 допустимых планов, глобальный максимум Score 57.236735 при стоимости 98; лучшая замена в эталоне даёт 57.20556; ~60 тестов
Особенности
Команда полностью перебрала пространство решений и показывает, где план пользователя стоит относительно глобального оптимума и Парето-границы. Объяснения LLM проверяются на соответствие фактам и числам. В коммитах видно, как два агента-«консилиума» (Claude/Codex) выбирали трек. Патруль Go2 и дрон сделаны как визуальная демонстрация.
Стек
Python · FastAPI · Uvicorn · Pydantic · openai · HTTPX · pytest · HTML/CSS/JavaScript
Модели
gpt-4o-mini · OpenAI-совместимый API · Nano Banana Pro (генерация иллюстраций)
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-e4dfa205-avm-ai.
README
README.mdАким на 5 часов
AI-симулятор управления городом команды AVM AI. HackAlem AI, задача 12, спец-трек Astana Innovations. Условия задачи и данные организатора: техническое задание и дополнительный документ с датасетом, каталогом мер и формулой.
Пользователь получает бюджет 100 условных единиц и выбирает ровно пять мер из 14 по пяти направлениям: транспорт, экология, социальная инфраструктура, безопасность и городской сервис. Приложение проверяет ограничения, рассчитывает Astana Quality of Life Score, показывает изменения в пяти районах и предлагает улучшения заменой одной меры.
Модель учебная: показатели и эффекты заданы организатором, а не описывают реальный городской бюджет. Решение предназначено для обучения и обсуждения компромиссов городского управления.
Требования и зависимости
- Python 3.11+ с pip и модулем
venv; Windows, Linux или macOS. - Современный браузер с JavaScript. Фронтенд — HTML, CSS и JavaScript без сборки; Node.js, Docker и база данных не требуются.
- Интернет нужен для установки зависимостей и внешней AI-модели. Основной сценарий работает без ключей и аккаунтов.
Прямые зависимости зафиксированы в requirements.txt: FastAPI 0.115.0, Uvicorn 0.30.6, Pydantic 2.9.2, openai 1.51.0, python-dotenv 1.0.1, HTTPX 0.27.2, pytest 8.3.3. Полного lock-файла транзитивных зависимостей пока нет.
Установка и запуск
Получите репозиторий и выполняйте команды из его корня, где находится app.py.
Windows PowerShell:
python -m venv .venv
.\.venv\Scripts\python.exe -m pip install --no-cache-dir -r requirements.txt
.\.venv\Scripts\python.exe -m uvicorn app:app --host 127.0.0.1 --port 8000
Linux / macOS:
python3 -m venv .venv
./.venv/bin/python -m pip install --no-cache-dir -r requirements.txt
./.venv/bin/python -m uvicorn app:app --host 127.0.0.1 --port 8000
В Debian/Ubuntu при отсутствии venv установите системный пакет python3-venv. Активация виртуального окружения не требуется. После установки для каждого запуска достаточно последней команды.
- Приложение: http://127.0.0.1:8000/.
- Проверка сервера: http://127.0.0.1:8000/api/health.
- Интерактивная документация API: http://127.0.0.1:8000/docs.
- Остановка:
Ctrl+C.
Открывайте страницу через сервер, а не как файл static/index.html. Для режима без ключа не создавайте .env и не задавайте OPENAI_API_KEY в окружении. При наличии ключа приложение использует внешнюю модель.
Переменные окружения
Настройки перечислены в .env.example. Для живого AI скопируйте его в .env (Copy-Item .env.example .env в PowerShell, cp .env.example .env в Bash), заполните поля и перезапустите сервер. Переменные процесса имеют приоритет над .env; файл с ключами исключён из Git.
| Переменная | Назначение |
|---|---|
OPENAI_API_KEY | Ключ модели; без ключа объяснение строится из фактов расчёта |
OPENAI_MODEL | Имя модели, по умолчанию gpt-4o-mini |
LLM_TIMEOUT_S | Таймаут запроса, по умолчанию 15 секунд |
OPENAI_BASE_URL | Необязательный адрес OpenAI-совместимого API; модель и ключ должны соответствовать провайдеру |
Ключ можно ввести в настройках интерфейса. Он хранится в sessionStorage вкладки, передаётся серверу заголовком X-OpenAI-Key и имеет приоритет над серверным. Приложение не записывает его в файлы или журналы. «Убрать ключ» очищает значение в браузере. Совместимость всех функций с каждым сторонним провайдером отдельно не проверена.
Проверка основного сценария
- Откройте приложение и нажмите «Сброс», если восстановился прежний план. Бюджет — 100, Score без решений — 52.55768, критических показателей в Нуре — 2.
- Нажмите «Готовый сценарий». Набор: M7 Нура, M8 Нура, M10 Нура, M12 город, M5 Сарыарка. Стоимость — 95, Score — 56.54307, критических показателей — 0. Интерфейс округляет Score до двух знаков.
- Нажмите «Объяснить». Без ключа появится «автоматический разбор» с сильными сторонами, рисками и рекомендациями. С ключом приложение попробует получить ответ модели.
- Нажмите «Найти улучшение». Лучший вариант меняет M5 Сарыарка на M3 Нура: стоимость 100, Score 57.20556. «Применить» пересчитывает план.
- Удалите одну меру: результат неполного набора не рассчитывается. Каталог запрещает шестую меру, превышение бюджета, повторы и несовместимые решения.
- В Swagger вызовите
POST /api/evaluateс набором M3 Есиль, M13 Алматы, M5 Сарыарка, M7 Нура, M12 город. Стоимость 121: ожидаютсяvalid: false,score: nullи ошибкаbudget_exceeded.
План сохраняется в localStorage браузера. Для одинаковых стартовых условий используйте «Сброс».
Пример расчёта через PowerShell:
$city = Invoke-RestMethod http://127.0.0.1:8000/api/city
$body = @{ decisions = $city.example_scenario } | ConvertTo-Json -Depth 10
Invoke-RestMethod http://127.0.0.1:8000/api/evaluate -Method Post -ContentType 'application/json' -Body $body
Пример через Bash:
curl -sS http://127.0.0.1:8000/api/evaluate \
-H 'Content-Type: application/json' \
-d '{"decisions":[{"measure_id":"M7","district_id":"nura"},{"measure_id":"M8","district_id":"nura"},{"measure_id":"M10","district_id":"nura"},{"measure_id":"M12"},{"measure_id":"M5","district_id":"saryarka"}]}'
Тесты и терминальное демо
Windows PowerShell:
.\.venv\Scripts\python.exe -m pytest -q
.\.venv\Scripts\python.exe -m pip check
.\.venv\Scripts\python.exe scripts/demo.py
Linux / macOS:
./.venv/bin/python -m pytest -q
./.venv/bin/python -m pip check
./.venv/bin/python scripts/demo.py
Демо показывает расчёт, отклонение неверных наборов, улучшения, рейтинг и объяснение без запуска сервера. При наличии ключа в окружении или .env оно обращается к модели; без ключа работает локально.
Архитектура и структура
Браузер: static/ → HTTP JSON → FastAPI: app.py → engine/ → data/
↓
внешняя AI-модель (опционально)
| Файл или каталог | Назначение |
|---|---|
app.py | API и раздача интерфейса с одного сервера |
engine/model.py, validator.py, scoring.py | Загрузка данных, проверка решений, расчёт Score |
engine/advisor.py, ranking.py | Замены одной меры, полный перебор и ранжирование |
engine/facts.py, templates.py, explain.py | Факты, локальное объяснение и работа с моделью |
data/city.json | Данные, меры и правила из ТЗ |
data/top_sets.json | Готовый индекс: топ-100, квантили и Парето-граница |
static/ | Интерфейс, изображения и демонстрация патруля |
scripts/demo.py, scripts/rank_all.py | Терминальное демо и пересчёт индекса |
tests/ | Тесты расчёта, правил, советника, API и демо |
API: GET /api/health, /api/city, /api/top; POST /api/evaluate, /api/improvements, /api/explain, /api/chat, /api/ai/check. Схемы доступны в /docs.
Правила расчёта и роль AI
По подробным правилам ТЗ принимаются ровно пять разных мер, не более двух из одного направления. Для районной меры обязателен район; городская действует на все районы. Бюджет, направления и несовместимости проверяет сервер. Невалидный набор не получает Score.
Эффект каждой меры умножается на (8 − лаг) / 8; синергии добавляются без масштабирования. Значения показателей ограничиваются диапазоном 0–100. Далее:
D_района = сумма(вес показателя × новое значение)
D_города = сумма(доля населения × D_района)
Score = 0.7 × D_города + 0.3 × min(D_района) − N_crit
N_crit — число пар «район × показатель» со значением строго ниже 40. Все числа считает Python; модель получает готовые факты. Ответ объяснения проверяется по JSON-схеме, ссылкам на факты и допустимым числам. При ошибке или отсутствии ключа используется локальное объяснение template. Проверка не гарантирует смысловую точность каждой фразы. Свободный чат доступен только с ключом.
Поиск улучшений возвращает до трёх лучших замен одной меры. Полный перебор содержит 694 395 допустимых планов, лучший Score — 57.236735 за 98 единиц. Процентиль приближённый, по квантилям; Парето-граница показывает лучшие соотношения стоимости и Score. Индекс включён в проект, пересчитывать его для запуска не нужно.
Демонстрационные возможности и ограничения
Патруль Go2 и дрон — визуальная демонстрация со статичными сгенерированными изображениями и заранее заданными событиями. Реального видеопотока, распознавания, датчиков и отправки обращений службам нет; надписи LIVE и телеметрия относятся к демонстрации. Патруль и дрон не меняют бюджет или Score. Подключение реальных городских сигналов — направление дальнейшего развития.
Рейтинг сравнивает математические сценарии, а не зарегистрированные команды.
Сторонние материалы
- FastAPI — MIT; Uvicorn — BSD-3-Clause; Pydantic — MIT; openai-python — Apache-2.0; python-dotenv и HTTPX — BSD-3-Clause; pytest — MIT. Зависимости устанавливаются штатными пакетами с их лицензиями.
- Данные, каталог мероприятий, формула, синергии и ограничения предоставлены организатором в условиях трека 12 (ссылки в начале README) и перенесены в
data/city.jsonбез изменений. - Карта, иконки и изображения персонажей и камеры сгенерированы командой с помощью Nano Banana Pro. Это иллюстрации, а не съёмка реального патруля.
- Код разработан с использованием Claude Code и Codex. Правила стиля AI-ответов адаптированы из skill
humanizer, основанного на материале Wikipedia «Signs of AI writing»; источник отмечен вengine/explain.py. Co-Authored-By сохранён в истории коммитов.
Команда
- Алибек Абдеков — капитан, фронтенд.
- Канат Тәжіхан — бэкенд.
Авторы коммитов
История коммитов
- 2026-09-23 17:54ui: убрана пометка о демонстрации в окне камерыAlibek Abdekov
- 2026-09-23 17:53fix: кадр камеры соответствует событию ленты у собаки и дронаAlibek Abdekov
- 2026-09-23 17:52ui: кнопка «Правила» вместо «Как считается»Alibek Abdekov
- 2026-09-23 17:51docs: README упоминает дрон в блоке демонстрации патруляAlibek Abdekov
- 2026-09-23 17:51feat: сменяемые кадры камер робота-собаки и дрона, по пять на каждого (демо-данные)Alibek Abdekov
- 2026-09-23 17:49feat: отдельный кадр камеры дрона с высоты (демо-данные)Alibek Abdekov
- 2026-09-23 17:48feat: дрон в блоке патруля — экология, транспорт, ЖКХ (демо-данные)Alibek Abdekov
- 2026-09-23 17:42chore: убраны правила для агентов (AGENTS.md, CLAUDE.md) и упорядочен .gitignoreAlibek Abdekov
Все коммиты (69)
- 2026-09-23 17:42docs: тексты правил игры простым языкомAlibek Abdekov
- 2026-09-23 17:41docs: README без фразы о непригодности для реальных бюджетных решенийAlibek Abdekov
- 2026-09-23 17:38Merge branch 'main' of https://github.com/BAITC-Hacks/hack-e4dfa205-avm-aiAlibek Abdekov
- 2026-09-23 17:38chore: чистка репозитория перед сдачей — убраны рабочие документы процесса и планы агентов, README сокращён под эксперта, .env.example только OpenAI, AGENTS.md без инструментов команды; правки интерфеAlibek Abdekov
- 2026-09-23 17:38docs: дорожная карта после хакатона — ИИ-агенты города (дрон, транспорт, ЖКХ) как источник данных симулятораKanat06
- 2026-09-23 17:36fix: восстановлены изменения Каната, потерянные при слиянии 78a7ae9: валидатор и регрессионные тестыAlibek Abdekov
- 2026-09-23 17:33Merge origin/main: правки Каната по ревью и финальные проверки; в чате оставлен явный ответ об ошибке моделиAlibek Abdekov
- 2026-09-23 17:32fix: по ревью 23.09: лимит тела по чанкам, пустой ответ модели в чате, советник не смешивает сценарии и не открывается сам, ошибка поиска замен с повтором, прокрутка окон, шапка на телефоне, патруль пAlibek Abdekov
- 2026-09-23 17:32docs: финальный статус — чистый запуск 17:32 (65 тестов), итог в документе анализаKanat06
- 2026-09-23 17:31fix: по ревью Codex — пустой ответ модели даёт mode=error, ядро терпит нестроковый measure_id; отчёт Codex и статус находокKanat06
- 2026-09-23 17:29docs: README — финальный чистый запуск 17:29, 63 тестаKanat06
- 2026-09-23 17:28fix: closeModal сбрасывает advisorOpen — после Escape советник снова открывается; прогон интерфейса проходит полностьюKanat06
- 2026-09-23 17:26docs: результаты прогона интерфейса — Escape ломает открытие советника (advisorOpen), косметика шапкиKanat06
- 2026-09-23 17:24feat: новые таблички районов с единицами и шкалой, «до решений» вместо «база», без слова «лаг»; патруль Go2, аватар советника, README и ревьюAlibek Abdekov
- 2026-09-23 17:21feat: единицы «балла/баллов» у всех чисел оценки в интерфейсе, автоматическом разборе и промпте; правки стилей и разметкиAlibek Abdekov
- 2026-09-23 17:16Merge origin/main: Парето в индексе и README после слиянияAlibek Abdekov
- 2026-09-23 17:16fix: советник без меток фактов, нейтральная фраза про автоматический разбор, чат шлёт только role и contentAlibek Abdekov
- 2026-09-23 17:15docs: README после слияния (демо в терминале, OPENAI_BASE_URL, установка по ОС); тест demo не зависит от локального .envAlibek Abdekov
- 2026-09-23 17:14Merge remote-tracking branch 'origin/main'Kanat06
- 2026-09-23 17:14feat: Парето «стоимость → лучший Score» из полного перебора в индексе, /api/top и демоKanat06
- 2026-09-23 17:12Merge branch 'main' of https://github.com/BAITC-Hacks/hack-e4dfa205-avm-aiAlibek Abdekov
- 2026-09-23 17:12feat: живой стиль советника по правилам humanizer в промптах и банке ответов, доработки интерфейса, район без кодов показателейAlibek Abdekov
- 2026-09-23 17:10feat: демонстрация сценария в терминале (scripts/demo.py), OPENAI_BASE_URL для OpenAI-совместимых провайдеров, тестыKanat06
- 2026-09-23 17:01docs: концепт патруля Go2 — задача для фронтенда и раздел README о пути к реальным даннымKanat06
- 2026-09-23 16:56docs: README, чистый запуск зафиксированной версии проверен на Windows 11Alibek Abdekov
- 2026-09-23 16:53docs: README — 60 тестов и чистый запуск с фронтендом; статус фронтенда в планеKanat06
- 2026-09-23 16:50feat: интерфейс подключён к API (расчёт, объяснение, замены, ключ, диалог), раздача static, строгая сверка чисел AI, защита от M²Alibek Abdekov
- 2026-09-23 16:38docs: оценка опыта патрульного робота для раздела безопасности, два варианта без изменения формулыKanat06
- 2026-09-23 16:35docs: бриф для Codex — контекст, правила, зоны, ожидаемые предложенияKanat06
- 2026-09-23 16:33docs: анализ, концепция и план до сдачи; README: ссылка на SwaggerKanat06
- 2026-09-23 16:29feat: ключ OpenAI из интерфейса, топ планов, ранг сценария, диалог с советникомKanat06
- 2026-09-23 16:24feat: полный перебор планов, глобальный топ, банк ответов советникаKanat06
- 2026-09-23 16:22docs: план, часть 2 по ревью Codex: совместимость explain с app, кэш по ключу и провайдеру, схема чата, текстыAlibek Abdekov
- 2026-09-23 16:16fix: ядро устойчиво к null и не-объектам, повторы считаются до фильтрацииKanat06
- 2026-09-23 16:11docs: часть 2 плана бэкенда с понятными текстами советника, склонениями и ключом из интерфейсаAlibek Abdekov
- 2026-09-23 15:58Merge remote-tracking branch 'origin/main'Kanat06
- 2026-09-23 15:58docs: README, соответствие ТЗ, лицензии, проверка чистого запускаKanat06
- 2026-09-23 15:58docs: часть 2 плана бэкенда (перебор, банк ответов, ключ из интерфейса, диалог) и ревью задач 1–6Alibek Abdekov
- 2026-09-23 15:53feat: FastAPI сервер, маршруты city, evaluate, improvements, explain, лимит телаKanat06
- 2026-09-23 15:50feat: AI-объяснение с проверкой схемы, ссылок и чисел, резервKanat06
- 2026-09-23 15:43feat: факты для объяснения и резервное объяснение по правиламKanat06
- 2026-09-23 15:38feat: советник, улучшение заменой одной мерыKanat06
- 2026-09-23 15:36feat: формула Score, вклад мер, разложение прироста, контрольные тестыKanat06
- 2026-09-23 15:30feat: валидатор набора решений с кодами ошибок и индексамиKanat06
- 2026-09-23 15:26feat: модель данных с проверкой датасета, gitignore для кэша PythonKanat06
- 2026-09-23 15:24feat: данные задачи и зависимостиKanat06
- 2026-09-23 15:11docs: план реализации бэкенда для агента, спека и ревью Codex, gitignore для venvAlibek Abdekov
- 2026-09-23 14:46docs: согласованная спецификация симулятора, основа README, структура папок, переменные окруженияAlibek Abdekov
- 2026-09-23 14:41chore: убрать из отслеживания лишние материалы и устаревшие черновикиAlibek Abdekov
- 2026-09-23 14:29Merge remote-tracking branch 'origin/main'Alibek Abdekov
- 2026-09-23 14:29docs: выбрана задача 12 «Аким на 5 часов», условия ТЗ в AGENTS.md и docs/tracksAlibek Abdekov
- 2026-09-23 14:28docs: выбран трек «Аким на 5 часов» (Astana Innovations) — разбор задачи и черновая архитектураKanat06
- 2026-09-23 13:48Merge branch 'main' of https://github.com/BAITC-Hacks/hack-e4dfa205-avm-aiAlibek Abdekov
- 2026-09-23 13:48chore: консилиум убран из репозитория, правило коммитов в AGENTS.mdAlibek Abdekov
- 2026-09-23 13:46docs: разбор трека — прогноз выработки ВЭС (Самрук-Казына)Kanat06
- 2026-09-23 13:39docs: консилиум — слепой первый раунд, позиция Клода вынесена в отдельный файлAlibek Abdekov
- 2026-09-23 13:39docs: консилиум — сводная таблица по 12 задачам, анкеты ТЗ, позиция КлодаAlibek Abdekov
- 2026-09-23 13:36docs: общий файл консилиума двух агентов для выбора задачиAlibek Abdekov
- 2026-09-23 13:31docs: все 12 задач хакатона с полными ТЗ и ссылками на материалыAlibek Abdekov
- 2026-09-23 13:25setup: правила хакатона для агентов, .env.example, .gitignoreAlibek Abdekov
- 2026-09-23 12:09check: проверка доступа на запись перед хакатономAlibek Abdekov
Структура репозитория (61 файлов)
.env.example .gitignore README.md app.py data/city.json data/top_sets.json docs/roadmap-ai-city-agents.md engine/__init__.py engine/advisor.py engine/explain.py engine/facts.py engine/model.py engine/ranking.py engine/scoring.py engine/templates.py engine/validator.py pytest.ini requirements.txt scripts/demo.py scripts/rank_all.py static/app.css static/app.js static/img/advisor.png static/img/ic-brigade.png static/img/ic-buslane.png static/img/ic-cleanfuel.png static/img/ic-clinic.png static/img/ic-crossing.png static/img/ic-digital.png static/img/ic-greening.png static/img/ic-lights.png static/img/ic-lrt.png static/img/ic-park.png static/img/ic-pipes.png static/img/ic-safecity.png static/img/ic-school.png static/img/ic-sport.png static/img/map.jpg static/img/patrol-cam.jpg static/img/patrol-dog.png static/img/patrol-dog2.jpg static/img/patrol-dog3.jpg static/img/patrol-dog4.jpg static/img/patrol-dog5.jpg static/img/patrol-drone.png static/img/patrol-drone2.jpg static/img/patrol-drone3.jpg static/img/patrol-drone4.jpg static/img/patrol-drone5.jpg static/img/patrol-dronecam.jpg static/index.html static/patrol.js tests/test_advisor.py tests/test_api.py tests/test_bank.py tests/test_codex_regressions.py tests/test_demo.py tests/test_explain.py tests/test_facts.py tests/test_scoring.py tests/test_validator.py
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.