О проекте
Команда: Skiter
Кейс HackAlem.ai: Спецтрек — Astana Innovations
Стадия: Доведённый продукт
Задача кейса: «Аким на 5 часов»: городской симулятор, распределяющий бюджет по 5 направлениям и 5 районам
Суть
Городской симулятор для Астаны: игрок выбирает ровно 5 мер из 14 в пределах 100 бюджетных единиц и видит результат по городу и районам. Есть место плана среди всех допустимых вариантов, стресс-тесты, AI-доклад, AI-советник и рейтинг команд.
Как устроено
Датасет city_dataset.json задаёт правила. Валидатор проверяет бюджет, совместимость мер и лимит в две меры на направление. Симулятор считает эффекты на горизонте 8 кварталов с долей (8−лаг)/8, итог Score = 0.7·D_avg + 0.3·min район − N_crit. Все 694 395 допустимых планов перебраны заранее и закэшированы в NumPy, отсюда ранг плана и лучшая замена одной меры. Семь стресс-сценариев оплачиваются из резерва. LLM (gpt-6-sol через Responses API) пишет доклад, где числа допускаются только через подстановки вида {{score}}. Советник вызывает инструменты validate и simulate до 6 раз, итоговый план сервер пересчитывает сам.
Ключевые решения
- exhaustive plan-space enumeration
- NumPy cache
- stress scenarios
- fact-placeholder guardrail
- tool calling validate/simulate
- reference scoring parity tests
Метрики
эталон 19/19 passed; демо-план 56.54 против базы 52.56, 566-е место из 694 395 (лучше 99.92% планов)
Особенности
Полный перебор пространства решений даёт честный ранг любого плана. Защита от галлюцинаций: LLM не может написать число вне разрешённых подстановок фактов. Официальный балл всегда считает код, а не модель. Интерактивная карта районов построена по официальным GIS-границам.
Стек
Python · FastAPI · Pydantic · NumPy · SQLite · React 18 · TypeScript · Vite · SVG map · Docker Compose · pytest
Модели
gpt-6-sol (OpenAI Responses API)
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-c4d4b101-skiter.
README
README.mdUrban AI
AI-симулятор управления городом: пять решений, ограниченный бюджет и измеримые последствия для жителей.
1. Проблема и аудитория
Как распределить городской бюджет, если одновременно нужны школы, транспорт, безопасные улицы и надёжные коммунальные сети? Улучшение одного района может оставить другой без поддержки, а сильный план в обычных условиях — оказаться уязвимым к аварии или бурану.
«Urban AI» позволяет проверить такие решения в учебной модели Астаны. Проект рассчитан на участников хакатона, студентов и команды, изучающие городское управление. Пользователь получает 100 условных бюджетных единиц, выбирает ровно пять мер и видит результат для города и каждого района.
2. Что реализовано
- Короткий обзор и отдельные страницы: город, мой план, результат, риски, стресс-тест, советник и рейтинг. План сохраняется при переходах между разделами.
- Город в цифрах: интерактивная карта пяти районов, сравнение районных баллов, тепловая карта десяти показателей, характеристики и натуральные единицы измерения.
- Конструктор плана: 14 мер в пяти направлениях; учёт стоимости, сроков и совместимости. Нельзя повторять меры, превышать бюджет или выбирать более двух мер одного направления. Сервер повторно проверяет ограничения.
- Результат в контексте: общий балл, изменения по районам, критические показатели, место среди 694 395 допустимых планов и лучшая замена одной меры.
- Риски и устойчивость: доля реализуемого эффекта, риски исполнения и семь независимых стресс-сценариев. Дополнительные реакции оплачиваются из резерва.
- AI-доклад: объяснение результата, влияния на город, вклада мер и рисков для руководства.
- AI-советник: проверка альтернатив через инструменты симулятора, сравнение стоимости и устойчивости, применение предложенного плана.
- Рейтинг команд: сравнение по основному баллу или устойчивости. Для каждой команды хранится последняя отправка.
- Работа без ИИ: если ключ не задан или сервис недоступен, остаются расчётный доклад и проверенная ближайшая альтернатива. Пользователь получает понятное уведомление.
3. Как работает решение
- В разделе «Город» пользователь изучает исходные показатели, карту и особенности районов.
- В «Мой план» указывает команду, выбирает пять мер и районы для локальных решений. Стоимость и предварительный результат пересчитываются автоматически.
- Нажимает «Отправить сценарий». Сервер проверяет правила, рассчитывает результат и сохраняет его в рейтинге.
- В «Результате» сравнивает показатели до и после, положение среди допустимых планов и оставшиеся проблемы.
- В «Стресс-тесте» проверяет устойчивость к событиям и при наличии резерва выбирает реакции.
- В «Советнике» получает доклад или проверенную альтернативу. Предложение можно применить, изучить и отправить как новый сценарий.
Во время подготовки ответа отображается индикатор загрузки. Технические сведения о провайдере и расходе токенов не показываются в пользовательском интерфейсе.

Карта в интерфейсе помогает выбрать район и открыть его показатели.
4. Технологии
| Компонент | Технологии |
|---|---|
| Интерфейс | TypeScript, React 18, Vite, CSS, SVG-карта |
| Сервер | Python 3.11+, FastAPI, Uvicorn, Pydantic |
| Расчёты | Python, NumPy для кэша пространства решений |
| Хранение рейтинга | SQLite |
| AI-интеграция | HTTPX; OpenAI Responses API для gpt-6-sol, OpenAI-совместимый Chat Completions API для других настроенных моделей |
Модель в .env.example | gpt-6-sol; модель и адрес провайдера настраиваются через окружение |
| Проверки | pytest, независимый эталон расчёта, TypeScript-проверка при сборке |
| Запуск | Docker Compose либо локальные Python и Node.js |
gpt-6-sol вызывается с уровнем рассуждения medium. Для работы с этой моделью необходимы действующий ключ и доступ к ней в API-аккаунте. Модель объясняет результаты и предлагает варианты; официальные баллы рассчитывает код симулятора.
5. Архитектура
flowchart LR
User[Пользователь] --> UI[React: план, карта, графики]
UI --> API[FastAPI]
Data[JSON: правила и данные города] --> Engine[Валидатор и симулятор]
API --> Engine
Engine --> Space[Кэш оценок допустимых планов]
Engine --> Events[Независимые стресс-сценарии]
API --> AI[Доклад и советник]
AI --> LLM[Настроенная AI-модель]
AI --> Engine
API --> DB[(SQLite: рейтинг)]
Расчёт балла
Горизонт модели — восемь кварталов. Эффекты мер учитываются с долей (8 − лаг) / 8; дополнительные эффекты совместимых мер добавляются по правилам датасета. Значения показателей ограничены диапазоном 0–100. Районный балл — взвешенная сумма десяти показателей.
D_avg = сумма (доля населения района × балл района)
N_crit = число показателей районов строго ниже 40
Score = 0.7 × D_avg + 0.3 × минимальный районный балл − N_crit
Так формула учитывает и общий уровень города, и положение слабейшего района. Неиспользованный бюджет не увеличивает основной балл. Он доступен для реакций на события.
Проверка ответов ИИ
Сервер передаёт модели каталог, профили районов и рассчитанные факты. В докладе модель должна ссылаться на числовые факты через подстановки, например {{score}}. Неизвестные ссылки и числа, написанные вне разрешённых подстановок, отклоняются; после одной повторной попытки используется расчётный текст.
Советник получает исходный план и проверенную ближайшую альтернативу. Ему доступны до шести вызовов инструментов validate и simulate. Итоговый план сервер рассчитывает повторно. Проверка чисел не является гарантией правильности каждого качественного вывода модели.
Структура репозитория
frontend/src/ страницы, карта, графики и формы
backend/app/main.py HTTP API
backend/app/engine/ правила, оценка планов, события и перебор
backend/app/ai/ провайдер, факты, промпты, доклад и советник
backend/app/storage.py рейтинг в SQLite
backend/tests/ автоматические проверки
spec/ датасет, эталон и контрольные сценарии
6. Установка и запуск
Получение проекта
Нужны Git и доступ к репозиторию:
git clone https://github.com/BAITC-Hacks/hack-c4d4b101-skiter.git
cd hack-c4d4b101-skiter
git switch main
Настройка ИИ — необязательно
В свежем клоне создайте локальный файл настроек:
cp .env.example .env
В .env заполните LLM_API_KEY. Адрес и модель задаются в LLM_BASE_URL и LLM_MODEL. Для OpenAI адрес — https://api.openai.com/v1. Не публикуйте ключ и не добавляйте его в .env.example. Файл .env исключён из Git и Docker-образа; Compose передаёт настройки серверу через окружение.
Без ключа приложение запускается и работает в расчётном режиме. В macOS скрытые файлы, включая .env, можно показать сочетанием Cmd + Shift + .
Вариант A: Docker Compose
Установите и запустите Docker с поддержкой Compose. Из корня проекта:
docker compose up --build
Откройте приложение на localhost:8501. При первом запуске построение кэша оценок может занять дополнительное время. Данные рейтинга сохраняются в именованном Docker-томе.
Остановка:
docker compose down
Вариант B: локально
Нужны Python 3.11+ и Node.js 20+. Команды ниже — для macOS/Linux, из корня проекта:
python3 -m venv .venv
.venv/bin/pip install -r backend/requirements.txt
npm ci --prefix frontend
В первом терминале запустите сервер:
cd backend
../.venv/bin/uvicorn app.main:app --host 127.0.0.1 --port 8000
Во втором терминале, из корня проекта, запустите интерфейс:
npm run dev --prefix frontend -- --host 127.0.0.1 --port 8501
Откройте приложение на 127.0.0.1:8501. Оба процесса должны оставаться запущенными.
Сборка интерфейса:
npm run build --prefix frontend
7. Сценарий проверки для жюри
- Запустите приложение и откройте «Город». Исходный балл — 52.56.
- В «Мой план» задайте название команды, например «Жюри», и выберите:
| Мера | Район | Стоимость |
|---|---|---|
| M7 — Школа + детсад | Нура | 24 |
| M8 — Центр семейного здоровья / поликлиника | Нура | 20 |
| M10 — Освещение и камеры | Нура | 12 |
| M12 — Единая цифровая платформа обращений | Весь город | 14 |
| M5 — Перевод частного сектора на чистое топливо | Сарыарка | 25 |
- Проверьте: стоимость 95, резерв 5, предварительный балл 56.54.
- Отправьте сценарий. Ожидаются 0 критических показателей, 566-е место среди 694 395 планов, результат лучше 99.92% допустимых планов, разрыв до лучшего — 0.69.
- Откройте «Стресс-тест». Без дополнительных реакций средний балл — 55.21, худший — 53.58. Основной результат остаётся 56.54.
- Выберите реакцию на сбой городских ИТ-систем стоимостью 5 и проведите стресс-тест. Балл этого сценария улучшится с 56.01 до 56.33. Реакция на аварию теплосетей стоимостью 10 недоступна при резерве 5.
- В «Советнике» запросите доклад и улучшение плана. Числа должны соответствовать расчёту; текст ИИ может меняться. Без доступа к ИИ приложение покажет расчётный вариант с пояснением.
- Вернитесь в «Мой план»: выбранные решения сохранятся. Посмотрите команду в «Рейтинге».
Автоматические проверки
Из корня проекта после установки зависимостей:
.venv/bin/pytest -q
.venv/bin/python spec/reference_scoring.py
npm run build --prefix frontend
Эталон должен вывести 19/19 passed. Проверки охватывают контрольные сценарии, бюджет и несовместимости, совпадение с эталоном на случайных допустимых планах, пространство решений, стресс-сценарии и защиту числовых ответов ИИ. Провайдер в автоматических AI-проверках подменяется; они не требуют ключа и не расходуют токены.
8. Данные и интеграции
- Синтетический датасет:
spec/city_dataset.json— единственный источник правил, показателей, мер, совместимости и событий. Включает пять районов, десять показателей, 14 мер и семь событий. Это учебные данные, а не актуальная городская статистика; персональных данных нет. - Натуральные единицы: расчётные баллы дополнены понятными величинами из датасета: время поездки, обеспеченность услугами, состояние сетей и другие показатели.
- Карта: локальный SVG на основе выгрузки слоя районов ГИС Е-Саулет. Он адаптирован к модели из пяти районов; обращение к ГИС при работе приложения не требуется. Источник геометрии указан в разделе ниже.
- AI-провайдер: OpenAI либо настроенный совместимый сервис. Ему передаются выбранный план и контекст синтетической модели; ключ хранится на сервере. Сетевой доступ требуется для AI-ответов.
- SQLite: хранит последнюю отправку каждой команды. Контрольные ответы
spec/test_cases.jsonиспользуются только проверками, приложение не подставляет их вместо расчёта.
Источник карты: слой районов ГИС Е-Саулет, выгрузка от 23 сентября 2026 года. Исходная геометрия содержит шесть полигонов; Сарайшық объединён с Алматы для соответствия пятирайонной учебной модели. Карта не предназначена для юридического определения административных границ.
9. Соответствие задаче хакатона
| Что оценивает жюри | Где посмотреть |
|---|---|
| Работоспособность основного сценария | «Мой план» → «Результат»; контрольный пример выше |
| Обоснованность решений | Районные показатели, критические значения, стоимость и сроки |
| Применение ИИ | Доклад и советник с инструментами проверки кандидатов |
| Наглядность | Карта, тепловая карта, сравнение районов и стресс-графики |
| Воспроизводимость | Общий датасет, детерминированный расчёт, эталон и автоматические проверки |
| Устойчивость решения | Работа без AI-ключа и отдельная оценка городских событий |
10. Ограничения текущей версии
- Это учебная статическая модель. Она не предназначена для принятия реальных бюджетных решений и не прогнозирует экономику или поведение жителей.
- Сценарии событий независимы и не имеют вероятностей. Их средний балл — сравнительная характеристика устойчивости, а не математическое ожидание прогноза.
- Советник ограничен шестью вызовами инструментов и не гарантирует глобально оптимальный план. Качественные выводы ИИ требуют осмысленного прочтения.
- Нет регистрации, ролей, защиты названий команд и ограничения частоты запросов. SQLite и текущая конфигурация запуска рассчитаны на локальную демонстрацию; для публичного сервиса нужны контроль доступа, лимиты AI-запросов, HTTPS и производственная схема размещения.
- План сохраняется между разделами открытой вкладки, но сбрасывается при полной перезагрузке страницы. В рейтинге остаются отправленные результаты.
- Задержка и доступность AI-ответов зависят от провайдера, модели и настроек аккаунта. Расчётная часть работает независимо от него.
11. Демонстрационная версия
Публичная deployed-ссылка в репозитории пока не указана. После запуска по инструкции доступна локальная демонстрация.
Авторы коммитов
История коммитов
- 2026-09-23 17:54Rename project and website to Urban AIAmir Saulebekov
- 2026-09-23 17:43Prepare final user experience, AI advisor, and jury READMEAmir Saulebekov
- 2026-09-23 16:35Merge testing into main and keep the district map on the beta simulator.Tagir Zamaletdinov
- 2026-09-23 16:26Delete Датасет районов.docxJayyngerBala
- 2026-09-23 16:25Add the Astana district map from official GIS boundaries.Tagir Zamaletdinov
- 2026-09-23 15:58Use GPT-6 Sol reasoning through Responses APIAmir Saulebekov
- 2026-09-23 15:55Keep API key only in local env fileAmir Saulebekov
- 2026-09-23 15:55Restore main frontend style and guard plan choicesAmir Saulebekov
Все коммиты (12)
- 2026-09-23 15:39Update .env.exampleAmir Saulebekov
- 2026-09-23 15:23Add expanded city simulator on betaAmir Saulebekov
- 2026-09-23 14:49Delete Датасет районов.docxJayyngerBala
- 2026-09-23 14:43Add the city-management simulator with engine-owned scoring.Tagir Zamaletdinov
Структура репозитория (60 файлов)
.dockerignore .env.example .gitignore AGENTS.md CODEX_GUIDE.md README.md backend/Dockerfile backend/app/__init__.py backend/app/ai/__init__.py backend/app/ai/advisor.py backend/app/ai/explainer.py backend/app/ai/facts.py backend/app/ai/llm.py backend/app/ai/prompts.py backend/app/cache/space_097b7c4ccb64.npy backend/app/config.py backend/app/engine/__init__.py backend/app/engine/dataset.py backend/app/engine/events.py backend/app/engine/simulator.py backend/app/engine/space.py backend/app/engine/units.py backend/app/engine/validator.py backend/app/main.py backend/app/storage.py backend/requirements.txt backend/tests/conftest.py backend/tests/test_ai.py backend/tests/test_events.py backend/tests/test_golden.py backend/tests/test_no_hardcoding.py backend/tests/test_parity.py backend/tests/test_rules.py backend/tests/test_space.py docker-compose.yml frontend/Dockerfile frontend/index.html frontend/package-lock.json frontend/package.json frontend/public/maps/astana-districts-interactive.svg frontend/public/maps/astana-districts-neutral.png frontend/src/App.tsx frontend/src/assets/astana-districts.svg frontend/src/components/CityVisuals.tsx frontend/src/components/DistrictDetailsPanel.tsx frontend/src/components/DistrictMap.tsx frontend/src/components/DistrictTooltip.tsx frontend/src/lib/districtMap.ts frontend/src/main.tsx frontend/src/styles.css frontend/src/types.ts frontend/src/vite-env.d.ts frontend/tsconfig.json frontend/vite.config.ts pytest.ini scripts/precompute_space.py spec/city_dataset.json spec/reference_scoring.py spec/test_cases.json spec/Датасет_районов_расширенный.docx
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.