О проекте
Команда: Nur_Sultan_teamAI
Кейс HackAlem.ai: Энергетика — Самрук-Казына
Стадия: Доведённый продукт
Задача кейса: AI-агент, прогнозирующий выработку ветровой электростанции по погодным данным
Суть
Агентная система почасового прогноза мощности двух ветровых турбин на 48 часов по SCADA и архивным прогнозам погоды NOAA GFS, с квантилями 10/50/90, API и Streamlit-интерфейсом.
Как устроено
XLSX SCADA агрегируются в часы, берутся только полные часы из шести 10-минутных значений. Из архива NOAA GFS по HTTP Range скачиваются только поля U/V ветра на 100 м и температуры на 2 м, причём выбирается прогон, уже опубликованный к моменту выпуска прогноза (задержка 8 ч), чтобы избежать утечки. Сравниваются 5 моделей с помесячной валидацией 2025 года и holdout января 2026, выбрана CatBoost, строятся квантили и 48-часовой replay февраля. LangGraph-супервизор на LLM может только выбрать разрешённое действие (аудит, карточка модели, расчёт, завершение) и не трогает числа. Есть SQLite-очередь с worker, FastAPI и Streamlit/Plotly.
Ключевые решения
- CatBoost
- квантильная регрессия
- LangGraph
- помесячная валидация
- holdout
- GRIB2 Range-загрузка
- защита от утечки по времени
- SHA-256 manifests
Метрики
Macro RMSE 2025: 0.3021 (baseline среднего 0.3486); январь 2026 RMSE: T1 0.2821, T2 0.2810; покрытие интервала 10–90% ≈67%; 55 тестов
Особенности
Строгая защита от утечки по времени: для каждого выпуска берётся только прогон GFS, который был опубликован к этому моменту, а все GRIB-источники фиксируются с byte range, ETag и SHA-256. LLM ограничен выбором разрешённых действий и не генерирует числа. Недотянутое покрытие квантилей (67% вместо 80%) команда не скрывает, а показывает в UI.
Стек
Python · uv · pandas · CatBoost · scikit-learn · ecCodes · LangGraph · FastAPI · Streamlit · Plotly · SQLite · GitHub Actions
Модели
gpt-5.4-mini-2026-03-17 · nvidia/nemotron-nano-3-30b-a3b
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-5d19020d-nur-sultan-teamai.
README
README.mdWIND AGENT
Agentic AI-система команды Nur_Sultan_teamAI для воспроизводимого почасового прогноза нормализованной активной мощности двух ветровых турбин на 24–48 часов.
Проект решает задачу HackAlemAI: использует исторический SCADA и архивные прогнозы погоды, доступные на момент выпуска прогноза. Текущие пользователи — команда и жюри.
Версия является рабочим MVP. Временная зона SCADA и положение метки внутри 10-минутного интервала пока не подтверждены организаторами. Поэтому результаты помечены
provisional, а strict-export заблокирован.
Что реализовано
- импорт двух XLSX и почасовая агрегация только из полных часов с шестью 10-минутными значениями;
- обработка пропусков без замены их на нулевую мощность;
- архивная погода NOAA GFS без регистрации: Range-загрузка только
U/Vветра на 100 м и температуры на 2 м; - контроль временной доступности, единиц, высоты полей, контрольных сумм и источников;
- CatBoost и базовые модели, помесячная валидация 2025 года и отдельный holdout января 2026;
- прогнозы 10/50/90-квантилей и ежедневный 48-часовой replay февраля 2026 одной фиксированной моделью;
- LangGraph-супервизор с разрешёнными действиями, лимитом решений и безопасным локальным fallback;
- SQLite-очередь, worker, агентские traces, FastAPI, Streamlit UI и CSV-выгрузки;
- 55 автоматических тестов, Ruff и GitHub Actions.
Проверенные результаты
Данные результаты получены фактическим запуском root-версии с предоставленными XLSX и архивом GFS. Это не метрики февраля: фактическая мощность за февраль не предоставлена.
| Проверка | Результат |
|---|---|
| Выбранная модель | catboost_small |
| Помесячная macro RMSE, 2025 | 0.3021 |
| Базовая модель среднего, macro RMSE | 0.3486 |
| Январь 2026, RMSE турбины 1 | 0.2821 |
| Январь 2026, RMSE турбины 2 | 0.2810 |
| Daily origins в replay | 29 |
| Строк 48-часового прогноза | 2 784 |
| Строк, относящихся к февралю | 2 688 |
| Тесты | 55 passed |
Мощность измеряется в нормированном диапазоне исходных данных 0…1, не в МВт:
номинальная мощность турбин не предоставлена.
Как работает
XLSX SCADA ─► проверка и почасовая агрегация ──┐
├─► CatBoost ─► 48-часовой прогноз ─► API / UI / CSV
архив NOAA GFS ─► GRIB Range ─► погодные признаки ─┘ │
LangGraph ─► проверки и trace
Для выбранного origin система выбирает более ранний запуск GFS с консервативным запасом времени публикации, извлекает нужные погодные поля, строит прогноз и сохраняет неизменяемый артефакт с manifest и SHA-256. LLM может только выбрать одно из действий: прочитать аудит, карточку модели, запустить численный расчёт либо завершить задачу. LLM не создаёт и не исправляет численные прогнозы.
Технологии
| Область | Инструменты |
|---|---|
| Язык и среда | Python 3.11, uv |
| Данные | pandas, NumPy, openpyxl, PyArrow, SQLite |
| ML | CatBoost, scikit-learn |
| Погода | NOAA GFS, AWS S3, GRIB2, ecCodes |
| Agentic AI | LangGraph, OpenAI Responses API, NVIDIA-compatible API |
| Backend и UI | FastAPI, Uvicorn, Streamlit, Plotly |
| Проверки | pytest, Ruff, GitHub Actions |
OpenAI-модель по умолчанию: gpt-5.4-mini-2026-03-17. NVIDIA-модель по умолчанию:
nvidia/nemotron-nano-3-30b-a3b. Без API-ключей численный конвейер и локальный
сценарий агента продолжают работать.
Архитектура
| Путь | Ответственность |
|---|---|
wind_agent/ingest.py | XLSX, временной контракт, аудит качества |
wind_agent/weather.py | GFS, Range GRIB, погодные признаки |
wind_agent/models.py | модели, карточки, проверка артефактов |
wind_agent/evaluation.py | валидация и holdout |
wind_agent/forecast.py | прогноз, replay, manifests и CSV |
wind_agent/agent.py | ограниченный LangGraph-супервизор |
wind_agent/jobs.py | очередь и worker |
wind_agent/api.py | локальный HTTP API |
ui/app.py | русскоязычный операционный интерфейс |
config/project.json | площадки, временной контракт и GFS-параметры |
scripts/ | установка и жизненный цикл Windows-сервисов |
tests/ | unit, integration и acceptance-проверки |
demo/ | ранний автономный пример на synthetic fixtures, не основной результат |
Кэш, модели, прогнозы и журналы находятся вне Git по умолчанию:
%USERPROFILE%\Documents\Codex\wind-agent-runtime.
Установка и запуск
Требуются Windows 10/11, интернет при первой установке и исходные XLSX в соседней папке
given с turbine 1 и turbine 2 в именах файлов.
git clone https://github.com/BAITC-Hacks/hack-5d19020d-nur-sultan-teamai.git
cd hack-5d19020d-nur-sultan-teamai
.\scripts\setup.ps1
Если нужен облачный LLM-диспетчер, создайте локальный .env:
Copy-Item .env.example .env
notepad .env
OPENAI_API_KEY=
NVIDIA_API_KEY=
NVIDIA_BASE_URL=https://integrate.api.nvidia.com/v1
NVIDIA_MODEL=nvidia/nemotron-nano-3-30b-a3b
WIND_LLM_BUDGET_USD=2.00
Укажите API-ключ, а не URL для активации кредита. .env намеренно исключён из Git.
Полный MVP-конвейер с возможностью продолжения:
.\scripts\run.ps1 run-all --profile mvp
Он импортирует XLSX, загружает 114 архивных выпусков погоды, проверяет пять моделей, обучает финальную и строит 29 ежедневных выпусков за тестовый период.
.\scripts\start.ps1 -OpenBrowser
- UI: http://127.0.0.1:8501
- API: http://127.0.0.1:8000/docs
- health: http://127.0.0.1:8000/health
Остановка: .\scripts\stop.ps1.
Как проверить решение
- Выполните
setup.ps1иrun-all --profile mvp. - Запустите
start.ps1 -OpenBrowser. - Во вкладке «Проверка точности» изучите сравнение моделей и holdout января 2026.
- Во вкладке «Прогноз» выберите выпуск и турбину, проверьте 48-часовой график, источник GFS, cutoff модели, квантили и скачайте CSV.
- В левой панели выберите дату, локальный диспетчер и нажмите «Рассчитать 48 часов».
- Во вкладке «Агент и задачи» проверьте очередь и trace решений.
- Запустите локальную проверку:
.\scripts\run.ps1 release-check
Данные и интеграции
Исходные XLSX содержат статистическое время, скорость ветра, нормализованную активную мощность и температуру с марта 2023 по 31 января 2026 года. Координаты из задания:
| Турбина | Широта | Долгота |
|---|---|---|
| 1 | 43.645150 | 78.535604 |
| 2 | 43.643198 | 78.538828 |
Открытый источник погоды — noaa-gfs-bdp-pds. Для GRIB-объектов сохраняются URL,
byte range, Last-Modified, ETag и SHA-256.
Ограничения
- Для MVP принято
Asia/Almaty, метка — начало 10-минутного интервала; это ждёт подтверждения организаторов. - Задержка публикации GFS принята равной 8 часам и дополнена серверными метками, но не подтверждена организаторами.
- Сетка GFS 1° грубо описывает локальный рельеф; высота ступицы и паспорт турбин неизвестны.
- Фактической мощности за февраль нет, поэтому февральские метрики не вычисляются.
- Январское покрытие интервала 10–90% около 67%, а не номинальные 80%; это явно показано в UI.
- MVP использует выборку origins для обучения и валидации;
weather --profile fullтребует больше времени и места. - TimesFM и двухэтапная OOF-коррекция из расширенного плана в MVP не входят.
- Dockerfile есть, но на машине разработки проверен нативный Windows-запуск, Docker daemon был недоступен.
Deployed-версия
Публичной deployed-версии пока нет. Проект проверенно запускается локально. Сырые данные, прогнозы, модели и секреты не публикуются в GitHub.
Документы
- PRODUCT.md — продуктовые ограничения;
- docs/final/WIND_AGENT_MASTER_FINAL_RU.md — расширенный план;
- docs/final/WIND_AGENT_FINAL_REVIEW_RU.md — обзор плана;
- docs/brainstorm/ — ранние материалы, не действующие инструкции.
Безопасность
- Write-endpoints требуют локальный bearer token.
- Файлы сохраняются атомарно с SHA-256, а пути артефактов проверяются.
- LLM видит ограниченный JSON-контекст и не имеет shell-доступа.
.env, кэш погоды, runtime, модели, прогнозы и логи не попадают в Git.
Авторы коммитов
История коммитов
- 2026-09-23 18:10feat(release): document and harden root MVP7292024
- 2026-09-23 17:58Final solution EEE7292024
- 2026-09-23 17:53docs: expand root README with demo/ folder map7292024
- 2026-09-23 17:50fix: robust local .env loading and wind_agent hardening7292024
- 2026-09-23 17:46fix: track demo fixtures for offline MVP runs7292024
- 2026-09-23 17:44feat: add wind-demo MVP and project tooling7292024
- 2026-09-23 17:17feat(core): establish leakage-safe wind agent foundationNZALMATY
- 2026-09-23 16:43docs: add final wind-agent planning package7292024
Все коммиты (11)
- 2026-09-23 15:40docs: add brainstorm notes from GPT, Gemini, Claude7292024
- 2026-09-23 14:06docs: add trial team instructions and env example7292024
- 2026-09-23 12:13kotak e 17292024
Структура репозитория (245 файлов)
.agents/skills/gh-address-comments/LICENSE.txt .agents/skills/gh-address-comments/SKILL.md .agents/skills/gh-address-comments/agents/openai.yaml .agents/skills/gh-address-comments/assets/github-small.svg .agents/skills/gh-address-comments/assets/github.png .agents/skills/gh-address-comments/scripts/fetch_comments.py .agents/skills/gh-fix-ci/LICENSE.txt .agents/skills/gh-fix-ci/SKILL.md .agents/skills/gh-fix-ci/agents/openai.yaml .agents/skills/gh-fix-ci/assets/github-small.svg .agents/skills/gh-fix-ci/assets/github.png .agents/skills/gh-fix-ci/scripts/inspect_pr_checks.py .agents/skills/git-commit-writer/SKILL.md .agents/skills/pr-description-writer/SKILL.md .cursor/hooks.json .cursor/mcp.json .cursor/skills/impeccable/SKILL.md .cursor/skills/impeccable/reference/adapt.md .cursor/skills/impeccable/reference/adapt.native.md .cursor/skills/impeccable/reference/android.md .cursor/skills/impeccable/reference/animate.md .cursor/skills/impeccable/reference/audit.md .cursor/skills/impeccable/reference/audit.native.md .cursor/skills/impeccable/reference/bolder.md .cursor/skills/impeccable/reference/clarify.md .cursor/skills/impeccable/reference/colorize.md .cursor/skills/impeccable/reference/craft-floor.md .cursor/skills/impeccable/reference/craft.md .cursor/skills/impeccable/reference/critique.md .cursor/skills/impeccable/reference/degraded/asset-producer.md .cursor/skills/impeccable/reference/degraded/documenter.md .cursor/skills/impeccable/reference/degraded/finish-reviewer.md .cursor/skills/impeccable/reference/degraded/manual-edit-applier.md .cursor/skills/impeccable/reference/delight.md .cursor/skills/impeccable/reference/distill.md .cursor/skills/impeccable/reference/doctor.md .cursor/skills/impeccable/reference/document.md .cursor/skills/impeccable/reference/extract.md .cursor/skills/impeccable/reference/harden.md .cursor/skills/impeccable/reference/hooks.md .cursor/skills/impeccable/reference/init.md .cursor/skills/impeccable/reference/ios.md .cursor/skills/impeccable/reference/layout.md .cursor/skills/impeccable/reference/live-setup.md .cursor/skills/impeccable/reference/live.md .cursor/skills/impeccable/reference/new-work.md .cursor/skills/impeccable/reference/onboard.md .cursor/skills/impeccable/reference/operate.md .cursor/skills/impeccable/reference/optimize.md .cursor/skills/impeccable/reference/overdrive.md .cursor/skills/impeccable/reference/polish.md .cursor/skills/impeccable/reference/quieter.md .cursor/skills/impeccable/reference/routing.md .cursor/skills/impeccable/reference/shape.md .cursor/skills/impeccable/reference/typeset.md .cursor/skills/impeccable/reference/visualize.md .cursor/skills/impeccable/scripts/command-metadata.json .cursor/skills/impeccable/scripts/concept-seed.mjs .cursor/skills/impeccable/scripts/context-signals.mjs .cursor/skills/impeccable/scripts/context.mjs .cursor/skills/impeccable/scripts/critique-storage.mjs .cursor/skills/impeccable/scripts/detect-csp.mjs .cursor/skills/impeccable/scripts/detect.mjs .cursor/skills/impeccable/scripts/detector/browser/injected/index.mjs .cursor/skills/impeccable/scripts/detector/cli/main.mjs .cursor/skills/impeccable/scripts/detector/design-system.mjs .cursor/skills/impeccable/scripts/detector/detect-antipatterns-browser.js .cursor/skills/impeccable/scripts/detector/detect-antipatterns.mjs .cursor/skills/impeccable/scripts/detector/engines/browser/detect-url.mjs .cursor/skills/impeccable/scripts/detector/engines/regex/detect-text.mjs .cursor/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs .cursor/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs .cursor/skills/impeccable/scripts/detector/engines/visual/screenshot-contrast.mjs .cursor/skills/impeccable/scripts/detector/findings.mjs .cursor/skills/impeccable/scripts/detector/node/file-system.mjs .cursor/skills/impeccable/scripts/detector/profile/profiler.mjs .cursor/skills/impeccable/scripts/detector/registry/antipatterns.mjs .cursor/skills/impeccable/scripts/detector/rules/checks.mjs .cursor/skills/impeccable/scripts/detector/shared/color.mjs .cursor/skills/impeccable/scripts/detector/shared/constants.mjs .cursor/skills/impeccable/scripts/detector/shared/fonts.mjs .cursor/skills/impeccable/scripts/detector/shared/inline-ignores.mjs .cursor/skills/impeccable/scripts/detector/shared/page.mjs .cursor/skills/impeccable/scripts/doctor.mjs .cursor/skills/impeccable/scripts/embed-prompt.mjs .cursor/skills/impeccable/scripts/generate-image.mjs .cursor/skills/impeccable/scripts/hook-admin.mjs .cursor/skills/impeccable/scripts/hook-before-edit.mjs .cursor/skills/impeccable/scripts/hook-lib.mjs .cursor/skills/impeccable/scripts/hook.mjs .cursor/skills/impeccable/scripts/lib/artifact-schema.mjs .cursor/skills/impeccable/scripts/lib/composition-catalog.mjs .cursor/skills/impeccable/scripts/lib/concept-catalog.mjs .cursor/skills/impeccable/scripts/lib/design-parser.mjs .cursor/skills/impeccable/scripts/lib/impeccable-config.mjs .cursor/skills/impeccable/scripts/lib/impeccable-paths.mjs .cursor/skills/impeccable/scripts/lib/is-generated.mjs .cursor/skills/impeccable/scripts/lib/open-system-browser.mjs .cursor/skills/impeccable/scripts/lib/provider.mjs .cursor/skills/impeccable/scripts/lib/roll-selection.mjs .cursor/skills/impeccable/scripts/lib/staleness-deep.mjs .cursor/skills/impeccable/scripts/lib/staleness-notice.mjs .cursor/skills/impeccable/scripts/lib/staleness.mjs .cursor/skills/impeccable/scripts/lib/surface-briefs.mjs .cursor/skills/impeccable/scripts/lib/target-args.mjs .cursor/skills/impeccable/scripts/lib/target-slug.mjs .cursor/skills/impeccable/scripts/lib/template-extensions.mjs .cursor/skills/impeccable/scripts/live-accept.mjs .cursor/skills/impeccable/scripts/live-browser-dom.js .cursor/skills/impeccable/scripts/live-browser-session.js .cursor/skills/impeccable/scripts/live-browser.js .cursor/skills/impeccable/scripts/live-commit-manual-edits.mjs .cursor/skills/impeccable/scripts/live-complete.mjs .cursor/skills/impeccable/scripts/live-copy-edit-agent.mjs .cursor/skills/impeccable/scripts/live-discard-manual-edits.mjs .cursor/skills/impeccable/scripts/live-inject.mjs .cursor/skills/impeccable/scripts/live-insert.mjs .cursor/skills/impeccable/scripts/live-manual-edit-evidence.mjs .cursor/skills/impeccable/scripts/live-poll.mjs .cursor/skills/impeccable/scripts/live-resume.mjs .cursor/skills/impeccable/scripts/live-server.mjs .cursor/skills/impeccable/scripts/live-status.mjs .cursor/skills/impeccable/scripts/live-target.mjs .cursor/skills/impeccable/scripts/live-wrap.mjs .cursor/skills/impeccable/scripts/live.mjs .cursor/skills/impeccable/scripts/live/accept-css.mjs .cursor/skills/impeccable/scripts/live/accept-verify.mjs .cursor/skills/impeccable/scripts/live/browser-script-parts.mjs .cursor/skills/impeccable/scripts/live/completion.mjs .cursor/skills/impeccable/scripts/live/event-validation.mjs .cursor/skills/impeccable/scripts/live/frameworks/astro.mjs .cursor/skills/impeccable/scripts/live/frameworks/detect-utils.mjs .cursor/skills/impeccable/scripts/live/frameworks/index.mjs .cursor/skills/impeccable/scripts/live/frameworks/journal.mjs .cursor/skills/impeccable/scripts/live/frameworks/nextjs.mjs .cursor/skills/impeccable/scripts/live/frameworks/nuxt.mjs .cursor/skills/impeccable/scripts/live/frameworks/script-src.mjs .cursor/skills/impeccable/scripts/live/frameworks/static-html.mjs .cursor/skills/impeccable/scripts/live/frameworks/sveltekit.mjs .cursor/skills/impeccable/scripts/live/frameworks/tag-strategy.mjs .cursor/skills/impeccable/scripts/live/frameworks/tanstack-start.mjs .cursor/skills/impeccable/scripts/live/frameworks/vite-generic.mjs .cursor/skills/impeccable/scripts/live/generation-preflight.mjs .cursor/skills/impeccable/scripts/live/insert-ui.mjs .cursor/skills/impeccable/scripts/live/instructions.mjs .cursor/skills/impeccable/scripts/live/manual-apply.mjs .cursor/skills/impeccable/scripts/live/manual-edit-routes.mjs .cursor/skills/impeccable/scripts/live/manual-edits-buffer.mjs .cursor/skills/impeccable/scripts/live/poll-lanes.mjs .cursor/skills/impeccable/scripts/live/roots.mjs .cursor/skills/impeccable/scripts/live/session-store.mjs .cursor/skills/impeccable/scripts/live/source-lock.mjs .cursor/skills/impeccable/scripts/live/source-search.mjs .cursor/skills/impeccable/scripts/live/svelte-ast.mjs .cursor/skills/impeccable/scripts/live/svelte-component.mjs .cursor/skills/impeccable/scripts/live/sveltekit-adapter.mjs .cursor/skills/impeccable/scripts/live/tanstack-adapter.mjs .cursor/skills/impeccable/scripts/live/ui-surfaces.mjs .cursor/skills/impeccable/scripts/live/vocabulary.mjs .cursor/skills/impeccable/scripts/modern-screenshot.umd.js .cursor/skills/impeccable/scripts/palette.mjs .cursor/skills/impeccable/scripts/pin.mjs .cursor/skills/impeccable/scripts/serve-question.mjs .cursor/skills/impeccable/scripts/surface-brief.mjs .cursorrules .dockerignore .env.example .github/workflows/ci.yml .gitignore .streamlit/config.toml AGENTS.md Dockerfile INSTRUCTIONS.md PRODUCT.md README.md config/project.json demo/.env.example demo/.gitignore demo/ASSUMPTIONS.md demo/README.md demo/configs/agent.yaml demo/configs/models.yaml demo/configs/sites.yaml demo/configs/time.yaml demo/data/fixtures/README.md demo/data/fixtures/scada_T1.csv demo/data/fixtures/scada_T2.csv demo/data/raw/README.md demo/pyproject.toml demo/scripts/demo_run.py demo/src/wind_demo/__init__.py demo/src/wind_demo/agent/__init__.py demo/src/wind_demo/agent/graph.py demo/src/wind_demo/agent/policy.py demo/src/wind_demo/agent/providers.py demo/src/wind_demo/agent/tools.py demo/src/wind_demo/api.py demo/src/wind_demo/cli.py demo/src/wind_demo/config.py demo/src/wind_demo/features.py demo/src/wind_demo/fixtures.py demo/src/wind_demo/forecast.py demo/src/wind_demo/ingest.py demo/src/wind_demo/schemas.py demo/src/wind_demo/storage.py demo/src/wind_demo/train.py demo/src/wind_demo/weather.py demo/tests/test_smoke.py demo/ui/app.py docs/brainstorm/claude.txt docs/brainstorm/gemini.txt docs/brainstorm/gpt.txt docs/brainstorm/my-question-1.txt docs/brainstorm/my-question-2.txt docs/final/WIND_AGENT_FINAL_REVIEW_RU.md docs/final/WIND_AGENT_MASTER_FINAL_RU.md docs/final/WIND_AGENT_START_HERE_RU.md docs/final/final.txt pyproject.toml scripts/run.ps1 scripts/setup.ps1 scripts/start.ps1 scripts/stop.ps1 tests/conftest.py tests/test_data_contract.py tests/test_weather_and_model.py tests/test_workflow.py ui/app.py uv.lock wind_agent/__init__.py wind_agent/__main__.py wind_agent/agent.py wind_agent/api.py wind_agent/cli.py wind_agent/config.py wind_agent/evaluation.py wind_agent/features.py wind_agent/forecast.py wind_agent/ingest.py wind_agent/jobs.py wind_agent/llm.py wind_agent/models.py wind_agent/release.py wind_agent/storage.py wind_agent/weather.py
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.