О проекте
Команда: STU students
Кейс HackAlem.ai: Спецтрек — Astana Innovations
Стадия: Доведённый продукт
Задача кейса: «Аким на 5 часов»: городской симулятор, распределяющий бюджет по 5 направлениям и 5 районам
Суть
Симулятор «Аким на 5 часов»: пользователь собирает портфель из пяти мер по 5 районам Астаны в пределах бюджета, получает Quality of Life Score, сравнивает сценарии и спрашивает AI-советника (Supervisor-агента).
Как устроено
data/city_data.json содержит 5 районов, 10 показателей и 14 мер. Python-ядро (validator, simulator, scoring) проверяет бюджет и конфликты, применяет лаги, эффекты и синергии, затем считает районные баллы и общий Score. Оптимизатор перебирает допустимые планы с отсечениями по четырём целям: max_score, balanced, focus_district, budget_efficiency. Supervisor-агент через function calling выбирает один из пяти детерминированных инструментов (inspect/validate/simulate/compare/search) и объясняет результат. Grounding-модуль пропускает только числа, которые ссылаются на поля результата инструмента.
Ключевые решения
- deterministic city simulator
- exhaustive search with pruning
- function calling / tool calling
- numeric grounding check
- Supervisor agent
Особенности
Защита от выдуманных чисел: LLM ставит ссылки на поля результата инструмента, сервер проверяет их и только потом подставляет значения. Помимо этого есть GIS-карта Астаны из офлайн-тайлов OSM (mbtiles), стресс-тест кризисов, рейтинг команд и генерация «Доклада Акиму».
Стек
Python 3.12 · FastAPI · Pydantic 2 · Uvicorn · React 19 · TypeScript · Vite 6 · Tailwind CSS 4 · Recharts · Playwright · pytest · MBTiles (OSM Astana)
Модели
gpt-5.6 (OpenAI-compatible Chat Completions)
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-37187286-stu-students.
README
README.mdАким на 5 часов · AI Urban Strategy Copilot
Интерактивный симулятор городских управленческих решений для кейса HackAlem «Аким на 5 часов».
Проект помогает собрать портфель из пяти городских мероприятий в рамках ограниченного бюджета, проверить ограничения, рассчитать последствия для районов и итоговый Astana Quality of Life Score, сравнить сценарии и получить объяснение от AI-советника.
Важно: используемые в проекте показатели и сценарии являются синтетическими данными учебного кейса. Это не официальная статистика Астаны и не реальный прогноз развития города.
1. Что решает проект
При управлении городом решения в транспорте, экологии, социальной сфере, безопасности и городских сервисах конкурируют за общий бюджет и влияют друг на друга.
Пользователю нужно одновременно учитывать:
- бюджет;
- состояние разных районов;
- ограничения и несовместимость мероприятий;
- лаг до получения эффекта;
- синергии между решениями;
- влияние на отдельные показатели;
- итоговый баланс города.
AI Urban Strategy Copilot объединяет детерминированную модель города и AI-агента: Python выполняет все расчёты, а LLM понимает запрос пользователя, выбирает нужный инструмент и объясняет уже рассчитанный результат.
Целевая аудитория решения в рамках кейса:
- городской управленец;
- аналитик;
- участник стратегической сессии;
- жюри или пользователь симулятора, сравнивающий альтернативные городские стратегии.
2. Что реализовано
Симуляция города
- модель пяти районов Астаны;
- десять показателей качества городской среды;
- 14 доступных мероприятий;
- единый бюджет;
- выбор ровно пяти различных решений;
- районные и общегородские меры;
- лаги реализации;
- положительные и отрицательные эффекты;
- синергии между мероприятиями;
- несовместимости мероприятий;
- ограничение итоговых показателей диапазоном 0–100;
- расчёт районных оценок и итогового Quality of Life Score;
- учёт критических показателей ниже порога.
Конструктор решений
Пользователь может вручную собрать портфель мероприятий и назначить районы для локальных мер.
Backend автоматически проверяет:
- количество решений;
- бюджет;
- повторяющиеся мероприятия;
- корректность районов;
- лимит мероприятий одного направления;
- глобальные и локальные конфликты.
Невалидный сценарий не получает итоговый Score.
Аналитика результатов
После расчёта интерфейс показывает:
- Score до и после решений;
- изменение Score;
- использование бюджета;
- оценки районов;
- изменение отдельных индикаторов;
- критические показатели;
- активированные синергии;
- вклад выбранных мероприятий;
- визуализации и радарные графики.
Оптимизатор сценариев
Реализован детерминированный поиск допустимых планов по четырём целям:
| Цель | Что оптимизируется |
|---|---|
max_score | максимальный итоговый Score |
balanced | состояние слабейшего района и баланс между районами |
focus_district | результат выбранного района |
budget_efficiency | прирост Score относительно затрат |
Оптимизатор перебирает допустимые сочетания и размещения мероприятий, применяет отсечения и повторно проверяет найденные решения основным валидатором и симулятором.
Сравнение сценариев
Два рассчитанных плана можно сравнить по:
- Score;
- бюджету;
- районам;
- показателям;
- критическим значениям.
AI-советник
В проекте используется один Supervisor Agent.
Пользователь может написать запрос естественным языком, например:
- «Что сейчас самое слабое в городе?»;
- «Проверь мой план»;
- «Почему мой сценарий получил такой Score?»;
- «Найди лучший сценарий до бюджета 90»;
- «Как лучше улучшить Нуру?»;
- «Предложи более сбалансированный вариант»;
- «Найди более сбалансированный вариант и сравни его с моим текущим планом».
Supervisor может последовательно использовать несколько инструментов и затем сформировать объяснение.
Доступные tools:
inspect_city_state— исходное состояние города и правила;validate_scenario— проверка плана;simulate_scenario— расчёт сценария;compare_scenarios— сравнение двух сценариев;search_scenarios— поиск допустимых стратегий.
Защита от выдуманных чисел
LLM не используется для вычисления Score, бюджета или эффектов.
Все точные числовые значения берутся из deterministic tools. Внутри ответа модель ссылается на поля результата инструмента, а сервер проверяет эти ссылки и только после этого подставляет значения.
Если модель пытается вернуть неподтверждённое число, ответ не проходит grounding-проверку.
Дополнительные интерфейсные модули
В текущем frontend также реализованы:
- обзор города и интерактивная карта-схема;
- радарная визуализация направлений;
- экран стресс-теста кризисных сценариев;
- локальный рейтинг стратегий команд;
- генерация презентационного «Доклада Акиму» из рассчитанного сценария.
Рейтинг сохраняется в localStorage браузера. Стресс-тест кризисов реализован как отдельная клиентская демонстрационная модель и не является частью основного детерминированного городского симулятора.
3. Как работает решение
Основной пользовательский сценарий:
1. Frontend получает исходное состояние города
↓
2. Пользователь выбирает 5 мероприятий
↓
3. FastAPI передаёт план валидатору
↓
4. Validator проверяет бюджет и ограничения
↓
5. Simulator применяет лаги, эффекты и синергии
↓
6. Scoring рассчитывает показатели районов и общий Score
↓
7. Frontend показывает результат и визуализации
↓
8. При необходимости пользователь:
• сравнивает сценарии
• запускает поиск оптимального сценария
• задаёт вопрос AI-советнику
↓
9. Supervisor выбирает нужный deterministic tool
↓
10. Tool возвращает проверенный JSON
↓
11. LLM объясняет результат
↓
12. Grounding проверяет происхождение числовых утверждений
Таким образом, архитектура разделяет две ответственности:
- Python-код отвечает за факты и вычисления;
- LLM отвечает за понимание намерения пользователя, выбор tools и объяснение результата.
4. Технологии
Backend и расчётное ядро
- Python 3.12;
- FastAPI;
- Pydantic 2;
- Uvicorn;
- HTTPX;
- python-dotenv;
- pytest.
Frontend
- React 19;
- TypeScript;
- Vite 6;
- Tailwind CSS 4;
- Recharts;
- Lucide React;
- Playwright для end-to-end тестов.
AI
Проект использует Chat Completions-совместимый LLM API с:
- function calling;
- JSON output;
- tool calling.
В .env.example в качестве модели указан:
gpt-5.6
По умолчанию используется OpenAI-compatible endpoint:
https://api.openai.com/v1
Провайдер задаётся через переменные окружения, поэтому расчётная часть проекта не зависит от наличия LLM и продолжает работать без API-ключа.
5. Архитектура проекта
frontend/
React + TypeScript UI
│
│ HTTP /api/*
▼
backend/
FastAPI
│
├──────────────► validator
│
├──────────────► simulator
│
├──────────────► optimizer
│
├──────────────► comparison
│
│
└──────────────► AI Supervisor
│
▼
deterministic tools
│
▼
grounding
Основные директории:
ai/
agent.py # Supervisor и LLM transport
system_prompt.md # правила поведения агента
tools.py # пять инструментов агента
grounding.py # проверка ссылок на tool evidence
validator.py # проверка сценария
simulator.py # эффекты, лаги и синергии
scoring.py # расчёт районов и общего Score
optimizer.py # полный поиск допустимых сценариев
comparison.py # сравнение двух сценариев
data.py # загрузка данных
backend/
main.py # FastAPI endpoints и раздача frontend
schemas.py # Pydantic-модели расчётного ядра
agent_schemas.py # схемы AI-запросов и ответов
frontend/
src/ # React-интерфейс
e2e/ # Playwright сценарии
data/
city_data.json # структурированные данные учебного кейса
rules/
... # исходные правила кейса
scripts/
demo.py # воспроизводимые примеры без LLM
eval_agent.py # opt-in проверка реального AI Supervisor
tests/
... # unit/integration тесты
6. API
FastAPI предоставляет следующие основные endpoints:
| Метод | Endpoint | Назначение |
|---|---|---|
| GET | /api/health | состояние backend и наличие AI-конфигурации |
| GET | /api/context | данные города, меры, ограничения, baseline |
| POST | /api/validate | проверка выбранного плана |
| POST | /api/simulate | полный расчёт сценария |
| POST | /api/search | поиск оптимальных сценариев |
| POST | /api/compare | сравнение двух планов |
| POST | /api/chat | запрос к AI Supervisor |
| POST | /api/analyze | AI-объяснение уже проверенного расчёта |
Swagger/OpenAPI после запуска:
http://127.0.0.1:8000/docs
7. Установка и запуск
Требования
- Python 3.12;
- Node.js 22.13+;
- npm.
Windows PowerShell
Из корня репозитория:
py -3.12 -m venv .venv
.venv/Scripts/python.exe -m pip install -r requirements.lock.txt
npm.cmd --prefix frontend ci
npm.cmd --prefix frontend run build
.venv/Scripts/python.exe -m uvicorn backend.main:app --host 127.0.0.1 --port 8000
После запуска откройте:
http://127.0.0.1:8000
FastAPI раздаёт собранный frontend/dist.
Linux / macOS
Эквивалентный запуск:
python3.12 -m venv .venv
.venv/bin/python -m pip install -r requirements.lock.txt
npm --prefix frontend ci
npm --prefix frontend run build
.venv/bin/python -m uvicorn backend.main:app --host 127.0.0.1 --port 8000
Режим frontend-разработки
Backend должен быть запущен на порту 8000.
Во втором терминале:
npm.cmd --prefix frontend run dev
Frontend будет доступен по адресу:
http://127.0.0.1:5173
Vite проксирует запросы /api на backend.
8. Подключение AI
Детерминированная симуляция, поиск и сравнение работают без LLM.
Для AI-советника создайте корневой файл .env на основе .env.example:
LLM_API_KEY=<your-api-key>
LLM_MODEL=gpt-5.6
LLM_BASE_URL=https://api.openai.com/v1
После изменения .env полностью перезапустите backend.
Проверка конфигурации:
Invoke-RestMethod http://127.0.0.1:8000/api/health
Ожидаемый формат:
{
"status": "ok",
"ai_configured": true
}
ai_configured: trueозначает, что backend видит необходимые переменные окружения. Реальный вызов модели проверяется через/api/chatили черезscripts/eval_agent.py.
API-ключ не должен добавляться в Git. Файл .env исключён через .gitignore.
9. Как проверить решение
Вариант A — через интерфейс
- Запустите приложение.
- Откройте «Конструктор решений».
- Используйте демонстрационный портфель или выберите пять мероприятий самостоятельно.
- Запустите расчёт.
- Проверьте:
- соблюдение бюджета;
- итоговый Score;
- изменения районов;
- критические показатели;
- синергии.
- Измените одно из решений и рассчитайте новый сценарий.
- Используйте сравнение результатов.
- Откройте AI-советник и выполните, например:
Найди лучший сценарий до бюджета 90
или:
Как лучше улучшить Нуру?
При настроенном LLM Supervisor должен вызвать search_scenarios, а найденные значения должны поступить из deterministic optimizer.
Для проверки multi-tool сценария:
Найди более сбалансированный вариант и сравни его с моим текущим планом
Supervisor может последовательно выполнить поиск и сравнение.
Вариант B — воспроизводимый demo без LLM
.venv/Scripts/python.exe -m scripts.demo
Скрипт воспроизводит:
- валидный демонстрационный план;
- невалидный сценарий;
- поиск лучшего плана в ограниченном бюджете;
- поиск с фокусом на Нуру;
- сравнение двух сценариев.
Вариант C — тесты
Backend:
.venv/Scripts/python.exe -m pytest -q
Frontend build:
npm.cmd --prefix frontend run build
Browser E2E:
cd frontend
npx.cmd playwright install chromium
npm.cmd run test:e2e
Проверка реального AI routing
При настроенных LLM_API_KEY и LLM_MODEL:
.venv/Scripts/python.exe -m scripts.eval_agent
Live evaluator проверяет наблюдаемые свойства агента:
- доступность ответа;
- выбранные tools;
- аргументы tool calls;
- наличие evidence;
- прохождение grounding.
Он не оценивает качество текста субъективной метрикой.
10. Данные и интеграции
Данные
Основной набор данных находится в:
data/city_data.json
Он содержит:
- пять районов;
- доли населения;
- десять индикаторов;
- веса индикаторов;
- 14 мероприятий;
- стоимость и лаг каждого мероприятия;
- эффекты;
- синергии;
- несовместимости;
- демонстрационный план.
Данные являются частью учебного кейса и хранятся непосредственно в репозитории.
Внешние интеграции
Основной runtime не использует:
- базу данных;
- внешнюю GIS-платформу;
- официальные городские API;
- внешние сервисы статистики.
Единственная необязательная внешняя интеграция расчётного приложения — Chat Completions-совместимый LLM API для AI-советника.
Если LLM недоступна, остаются работоспособными:
- валидация;
- симуляция;
- поиск;
- сравнение;
- визуализация результатов.
11. Правила расчёта
Основные ограничения модели:
- бюджет — 100 единиц;
- пользовательский сценарий содержит ровно пять различных мероприятий;
- ровно по одному мероприятию каждого из пяти направлений;
- районная мера требует назначения района;
- общегородская мера не требует района;
- часть комбинаций мероприятий несовместима;
- эффект меры учитывает лаг на горизонте восьми кварталов;
- синергии применяются отдельно;
- показатели после всех изменений ограничиваются диапазоном 0–100.
Реализованный эффект мероприятия:
effect_share = (8 - lag) / 8
realized_effect = effect × effect_share
Районная оценка:
D_d = Σ(weight × indicator)
Средняя городская оценка:
D_avg = Σ(population_share × D_d)
Итоговый Score:
Score = 0.7 × D_avg + 0.3 × min(D_d) - N_crit
N_crit — количество пар «район × показатель» со значением строго ниже 40.
12. Ограничения текущей версии
Подтверждённые ограничения проекта:
- данные синтетические и не являются реальной статистикой Астаны;
- результат модели нельзя трактовать как реальный прогноз городской политики;
- AI-зависимая часть требует отдельного LLM API key;
- LLM не выполняет расчёты и не является источником числовых значений;
- оптимизатор работает на фиксированном наборе данных и правил;
- сервер не хранит пользовательские сессии;
- отдельной базы данных нет;
- рейтинг команд хранится только локально в браузере через
localStorage; - встроенные кризисные сценарии являются демонстрационной frontend-моделью и не изменяют состояние основного optimizer/simulator;
- полноценная оптимизация нового городского состояния после кризиса в расчётном ядре не реализована;
- внешние реальные городские данные и GIS API не подключены.
13. Deployed-версия
В текущем репозитории не обнаружена подтверждённая ссылка или конфигурация публичного deployment.
Проект воспроизводимо запускается локально:
http://127.0.0.1:8000
Если появится публичная deployed-версия, ссылку можно добавить в этот раздел.
Ключевая идея проекта
LLM не должна придумывать городские показатели.
В AI Urban Strategy Copilot:
LLM понимает задачу
↓
выбирает tool
↓
Python рассчитывает результат
↓
LLM объясняет только проверенные данные
↓
grounding контролирует числовые утверждения
Это позволяет совместить удобство естественного языка с воспроизводимыми и проверяемыми расчётами.
Авторы коммитов
История коммитов
- 2026-09-23 17:58Merge pull request #5 from BAITC-Hacks/frontendAkhmedyanov Salamat
- 2026-09-23 17:56fix: require one decision per city directionSalamat
- 2026-09-23 17:40feat: add mobile header styles, test script, and visual assetsSalamat
- 2026-09-23 17:26feat: add frontend styles, components, and interactive header test suiteSalamat
- 2026-09-23 17:15fix(map): expand map to 100% width with horizontal district stripSalamat
- 2026-09-23 17:13feat: add map-wide.png image to frontendSalamat
- 2026-09-23 17:13chore: remove fileSalamat
- 2026-09-23 17:11chore: remove temporary debug test scriptsSalamat
Все коммиты (26)
- 2026-09-23 17:08feat: add frontend UI styles, environment types, and overview componentSalamat
- 2026-09-23 16:58feat: initialize full-stack application with backend, frontend UI, and map tilesSalamat
- 2026-09-23 16:38fix(vite): allow port fallback when 5173 is occupiedSalamat
- 2026-09-23 16:35docs: rewrite README for hackathon jurySladok
- 2026-09-23 16:28Merge pull request #4 from BAITC-Hacks/ai-agentSladok
- 2026-09-23 16:25feat: improve AI supervisor orchestrationАлександр Юрышев
- 2026-09-23 16:21feat(map): ultra-detailed GIS map of Astana with zoom/pan, waterways, bridges, landmarks, and fullscreen viewSalamat
- 2026-09-23 16:19feat(frontend): Situational Center 2.0 with GIS heatmaps, 5-axis Radar, Crisis stress-test, Team Leaderboard, Pitch Deck and Control Plan integrationSalamat
- 2026-09-23 16:12chore: add .env to gitignoreSalamat
- 2026-09-23 15:29Merge pull request #3 from BAITC-Hacks/salamat-treeSladok
- 2026-09-23 15:28feat: finalize AI supervisor integrationАлександр Юрышев
- 2026-09-23 14:45Merge pull request #2 from BAITC-Hacks/salamat-treeSladok
- 2026-09-23 14:44feat: polish frontend and update READMEАлександр Юрышев
- 2026-09-23 14:38Add canonical district dataset rules sourceCorv23
- 2026-09-23 14:34feat: complete working urban strategy copilot MVPАлександр Юрышев
- 2026-09-23 14:19Merge pull request #1 from BAITC-Hacks/salamat-treeAkhmedyanov Salamat
- 2026-09-23 14:17feat: add city simulator architectureАлександр Юрышев
- 2026-09-23 14:10FIRST commitSalamat
Структура репозитория (86 файлов)
.env.example .gitignore README.md ai/__init__.py ai/agent.py ai/comparison.py ai/data.py ai/grounding.py ai/optimizer.py ai/scoring.py ai/simulator.py ai/system_prompt.md ai/tools.py ai/validator.py backend/__init__.py backend/agent_schemas.py backend/main.py backend/schemas.py backend/tiles.py data/city_data.json examples/requests.http frontend/.gitkeep frontend/arcgis-jsapi-view.png frontend/arcgis-webscene-view.png frontend/e2e/strategy.spec.ts frontend/header-fixed-1440.png frontend/header-mobile-375.png frontend/header-mobile-menu-open.png frontend/header-mobile-profile-open.png frontend/header-nav-dropdown.png frontend/header-profile-open.png frontend/header-sidebar-collapsed.png frontend/index.html frontend/map-panel-view.png frontend/new-map-boundaries.png frontend/new-map-nura-selected.png frontend/new-map-saryarka-selected.png frontend/package-lock.json frontend/package.json frontend/playwright.config.ts frontend/public/favicon.svg frontend/public/test-arcgis.html frontend/src/Advisor.tsx frontend/src/App.tsx frontend/src/Builder.tsx frontend/src/Crisis.tsx frontend/src/Leaderboard.tsx frontend/src/Overview.tsx frontend/src/PitchDeck.tsx frontend/src/Results.tsx frontend/src/api.ts frontend/src/components.tsx frontend/src/main.tsx frontend/src/mapData.ts frontend/src/styles.css frontend/src/types.ts frontend/src/vite-env.d.ts frontend/test-arcgis.mjs frontend/test-header-1440.png frontend/test-header-768.png frontend/test-header-interactions.mjs frontend/test-map-boundaries.mjs frontend/test-mobile-header.mjs frontend/test-pitemx.mjs frontend/tsconfig.json frontend/vite.config.ts idea.md instruct.md item.pitemx osm-2020-02-10-v3.11_kazakhstan_astana.mbtiles pyproject.toml requirements.lock.txt requirements.txt rules/Аким на 5 часов датасет.md scripts/demo.py scripts/eval_agent.py slides.txt tests/test_agent.py tests/test_api.py tests/test_eval_agent.py tests/test_llm_config.py tests/test_optimizer.py tests/test_simulator.py tests/test_tiles.py tests/test_tools.py tests/test_validator.py
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.