Nowcasting-agentti-energiahuoltovarmuuteen

Nowcast-agentti huoltovarmuudelle — tekninen briiffi

Versio: 1.0, 15.5.2026 Tarkoitus: Konteksti Claude Codelle MVP-kehityksen aloittamiseen. Cinian ennakointi-tarjooman pilotti, joka yhdistää kvantitatiivisen nowcasting-mallin agenttiseen tilannekuvaan.


1. Tuote lyhyesti

Nowcasting-agentti energiahuoltovarmuuden seurantaan. Tuottaa reaaliaikaisen numeerisen estimaatin Suomen sähköhuoltovarmuusmittarista (julkaisuviive ~kvartaali) korkeampifrekvenssisistä avoimista indikaattoreista, päivittää estimaattia uutta dataa saapuessa, ja tuottaa LLM-kerroksen kautta luettavan selityksen siitä mistä muutos johtuu — mukaan lukien geopoliittiset ajurit kuten Hormuzin salmen tilanne ja LNG-markkinan reaktiot.

Differentiaattori suhteessa Wahlbergin Vantaa-demoon: kvalitatiivisen tilannekuvan päälle numeerinen, validoitavissa oleva malli, jonka tarkkuus voidaan todentaa jälkikäteen oikeaa virallista lukua vastaan.

Asiakkaat: Huoltovarmuuskeskus (HVK), TEM, suuret kaupungit (Helsinki, Vantaa, Espoo, Tampere), energiayhtiöt, Traficom. Pilotti todennäköisesti HVK tai Vantaa (Wahlbergin tiimin jatkumo).


2. Tieteellinen pohja

Kolme toisiaan tukevaa pilaria:

  1. Hopp (2021), UNCTAD Research Paper No. 62: LSTM-nowcasting voittaa Dynamic Factor Modelin (DFM) kolmessa kohdesarjassa eri datavintageilla. Tuottanut nowcast_lstm Python-kirjaston (PyPI), joka käyttää PyTorchia ja madaltaa implementointikynnystä. Käytämme tätä metodologisena runkona.
  2. Energialähtöinen LSTM-kirjallisuus: Lyhyen aikavälin sähkönkulutuksen ennustaminen LSTM:llä on vakiintunut tutkimusala (esim. Kong et al. 2019 IEEE Trans. Smart Grid). Antaa sektorispesifin validoinnin.
  3. Geopoliittinen riski-indeksi: Caldara & Iacoviello (Federal Reserve, 2018→) GPR-indeksi on standardimuuttuja makrotaloudessa ja korreloi öljyn/LNG:n hinnan kanssa. Antaa kausaaliketjulle vertaisarvioidun pohjan.

Tärkeä rajaus: Malli ei “ennusta Hormuzin sulkemista” — se mittaa miten markkinoiden hinnoittelema riski kehittyy ja päivittää huoltovarmuusestimaattien epävarmuusvälejä. Tämä erottaa tuotteen spekulatiivisesta “AI-ennustaa-sodan” -hypestä.


3. Tekninen arkkitehtuuri

[Data Layer]              [Model Layer]            [Agent Layer]            [UI Layer]
─────────────             ─────────────            ─────────────            ─────────────
Tilastokeskus API   ──┐
Eurostat API        ──┤
Fingrid API         ──┼─→ Data Collector  ──→  nowcast_lstm  ──→  Nowcast Agent   ──┐
Nord Pool           ──┤   Agent (orchestr.)     (10 networks,     (runs model,       │
ENTSO-E             ──┤   X13 seasonal adj.,    mean of outputs,  produces estimate  │
TTF/Brent (Eikon)   ──┤   stationarity,          MAE/RMSE vs       + confidence)     │
AIS Hormuz (avoin)  ──┤   ARMA gap-filling)     ARMA benchmark)                      ├─→ Dashboard
GPR Index           ──┤                                              ↓                │   (Streamlit
Caldara-Iacoviello  ──┤                                                              │   tai HTML)
Polymarket          ──┘                                          Explainer Agent     │
                                                                 (LLM: sensitivity   │
                                                                 analysis + skenaario│
                                                                 -peilaus + tekstinen│
                                                                 selitys)        ────┘

Komponentit:


4. Kohdesarja ja data

Ensisijainen kohdesarja (target variable)

Vaihtoehto A (suositus aloitukseen): Suomen sähkön nettotuonti / sähköomavaraisuusaste, neljännesvuosittain, Tilastokeskuksen energiatase, viive ~3 kk. Pitkä historia (>15 v), selkeä kausivaihtelu, hyvät korreloivat indikaattorit.

Vaihtoehto B (yksinkertaisempi): Suomen kuukausittainen sähkön kokonaiskulutus, Tilastokeskus tai Energiavirasto, viive ~6 viikkoa. Helpompi mallintaa, mutta vähemmän “huoltovarmuus”-kytköstä.

Vaihtoehto C (vaativampi mutta vaikuttavin): Kriittisten tavararyhmien tuontivolyymit (polttoaineet, lääkkeet, lannoitteet), Tulli, viive ~6 viikkoa.

Aloitetaan A:lla. Jos data ei aukea helposti, fallback B.

Input features (15–30 sarjaa)

Kotimainen energia:

Eurooppa-konteksti:

Globaali/geopoliittinen:

Kausitasaus: Kaikki Hopp:n ohjeen mukaan X13-ARIMA-SEATS, kasvuasteiksi muunnettuina. statsmodels.tsa.x13 toimii.


5. Skenaariokerros

Asiakkaan kanssa määritellään kolme skenaariota; tämä on osa konsultointia, ei automaatio:

  1. Baseline: Hormuzin salmi auki, OPEC-tuotanto stabiili, ei merkittäviä geopoliittisia eskalaatioita. GPR-indeksi <100.
  2. Eskalaatio: USA–Iran-välikohtaus, tankkereiden viiveet 1–4 viikkoa, LNG-spot-hintapiikki 30–50 %. GPR 100–200.
  3. Kriisi: Pitkittynyt salmen sulku, LNG-virrat ohjautuvat pysyvästi muualle, Euroopan kaasun hinta 2–3x. GPR >200.

Malli tuottaa ehdollisen estimaatin per skenaario + agentti seuraa indikaattoreita ja päivittää skenaarioiden todennäköisyydet (Polymarket-tyyppisten ennustemarkkinoiden ja GPR-indeksin avulla).


6. MVP-toteutus, 14 päivän aikataulu

Päivä Tehtävä Deliverable
1–2 Data-pipeline Toimiva ETL Tilastokeskus + Eurostat + Fingrid + Nord Pool → Pandas DataFrame oikeassa muodossa
3 nowcast_lstm-asennus ja ensimmäinen ajo Baseline-malli ajossa, default-hyperparametrit, MAE/RMSE-tulos
4 ARMA-benchmark ja vintage-backtest Hopp:n tyylinen taulukko: ARMA vs LSTM, 5 vintagea
5 Geopoliittiset indikaattorit Brent + TTF + GPR + Hormuz AIS pipelineen, mallin uudelleenajo
6 Explainer Agent v1 LangGraph-pipeline joka tuottaa LLM-selityksen mallin outputista
7 Skenaariokerros Kolme skenaariota määritelty, ehdolliset estimaatit
8–9 Streamlit-UI Aikajana, luottamusväli, indikaattoritaulu, LLM-selitys, skenaariotodennäköisyydet
10 Hyperparametrien tuning Grid search, paras MAE/RMSE valittu
11 Vintage-backtest viimeisille 12 kk:lle “Näin malli olisi näyttänyt joka kuukausi takautuvasti”
12 Pitch deck 10 sliden esitys: ongelma, ratkaisu, demo, tieteellinen pohja, hinnoittelu
13 Sisäinen demo Idalle ja Pontukselle Feedback, säätö
14 Kontakti pilottiasiakkaaseen (HVK tai Vantaa) Tapaaminen sovittu

Resurssitarve: Sun oma aika, RTX 3060 työasema (riittää 10 LSTM-verkon kouluttamiseen), Anthropic API-budjetti LLM-selittäjälle (~50–100 €/kk).


7. Repositorin alustava rakenne

nowcast-huoltovarmuus/
├── README.md
├── pyproject.toml
├── .env.example                  # API-avaimet (Fingrid, ENTSO-E jos vaatii)
├── data/
│   ├── raw/                      # API:sta haettu raakadata
│   ├── processed/                # Kausitasattua, normalisoitua
│   └── models/                   # Talletetut LSTM-mallit (dill)
├── src/
│   ├── collectors/
│   │   ├── tilastokeskus.py      # Pohjautuu sun TKI-dashboard-koodiin
│   │   ├── eurostat.py
│   │   ├── fingrid.py
│   │   ├── nordpool.py
│   │   ├── entsoe.py
│   │   ├── geopolitics.py        # Brent, TTF, GPR, AIS Hormuz, Polymarket
│   │   └── base.py               # Yhteinen rajapinta
│   ├── preprocessing/
│   │   ├── seasonal.py           # X13-ARIMA-SEATS
│   │   ├── stationarity.py
│   │   └── alignment.py          # Mixed-frequency yhdistäminen
│   ├── model/
│   │   ├── nowcast_model.py      # nowcast_lstm wrapper
│   │   ├── arma_benchmark.py
│   │   ├── vintage_backtest.py
│   │   └── metrics.py            # MAE, RMSE, t-test
│   ├── agents/
│   │   ├── data_collector.py     # LangGraph: orkestroi collectorit
│   │   ├── nowcaster.py          # Ajaa mallin
│   │   ├── explainer.py          # LLM-selitys
│   │   └── scenario.py           # Skenaariokerros
│   └── ui/
│       └── streamlit_app.py
├── notebooks/
│   ├── 01_data_exploration.ipynb
│   ├── 02_baseline_lstm.ipynb
│   ├── 03_vintage_backtest.ipynb
│   └── 04_explainer_prototype.ipynb
└── tests/
    └── test_collectors.py

8. Kriittiset päätökset / avoimet kysymykset

  1. Kohdesarjan tarkka muoto. Tilastokeskuksen energiatase vs. Energiaviraston kuukausitilasto vs. ENTSO-E:n omavaraisuusluku. Päätetään ennen päivää 1.
  2. LLM-selittäjän malli. Claude Opus 4.7 antaa parhaan laadun, Sonnet 4.6 riittävän halvalla. Aloitetaan Sonnetilla.
  3. Skenaarioiden todennäköisyyspäivitys. Bayes-päivitys GPR-muutoksilla vai Polymarketin suora käyttö? Aloitetaan Polymarketilla (yksinkertaisempi).
  4. Hostaus. AWS eu-north-1 (sama tili kuin Optiwood) vai lokaali Fujitsu-palvelin Optiwoodin verkossa? Aloitetaan lokaalisti, viedään AWS:ään kun demo on valmis.

9. Mitä Claude Codelle annetaan ensimmäisessä sessiossa

  1. Tämä dokumentti (nowcast_huoltovarmuus_brief.md)
  2. Hopp (2021) PDF (UNCTAD Research Paper No. 62) ja nowcast_lstm-kirjaston README PyPI:stä
  3. Sun TKI-dashboardin scraping-koodi referenssinä
  4. Käsky: “Lue brief. Aloita repon alustaminen ja Tilastokeskuksen + Fingridin collector-moduulit. Käytä uv paketinhallintaan. Kirjoita testit jokaiselle collectorille. Älä yritä rakentaa mallikerrosta ennen kuin data-pipeline tuottaa puhdasta Pandas DataFramea jossa on sähköhuoltovarmuuden kohdesarja sekä vähintään 10 input-saraketta oikealla taajuudella.”

10. Liiketoiminnallinen kytkös


Liite A: Keskeiset koodisnipetit

A.1 nowcast_lstm peruskäyttö (Hopp:n README:stä)

from nowcast_lstm.LSTM import LSTM

# data: Pandas DataFrame, sarakkeet: date, target_col, feature1, feature2, ...
# Rivit kuukausifrekvenssissä, kvartaalimuuttujilla NaN väliriveissä

model = LSTM(
    data=training_data,
    target_variable="sahkohuoltovarmuus",
    n_timesteps=12,           # 12 kuukauden ikkuna
    fill_na_func=np.nanmean,  # ARMA myöhemmin
    fill_ragged_edges_func="ARMA",
    n_models=10,              # 10 verkon keskiarvo
    train_episodes=200,
    batch_size=30,
    decay=0.98,
    n_hidden=20,
    n_layers=2,
    dropout=0,
    criterion="MSE",
    optimizer="Adam",
    optimizer_parameters={"lr": 1e-2}
)

model.train()
predictions = model.predict(test_data)

A.2 Vintage-backtest -periaate

for vintage in ["2_months_before", "1_month_before", "month_of", "1_month_after", "2_months_after"]:
    artificial_data = simulate_vintage(full_data, vintage, publication_lags)
    pred = model.predict(artificial_data)
    mae = mean_absolute_error(actuals, pred)
    rmse = root_mean_squared_error(actuals, pred)
    # Vertaa ARMA-benchmarkkiin t-testillä

A.3 Explainer Agent (LangGraph-luuranko)

from langgraph.graph import StateGraph

class NowcastState(TypedDict):
    current_nowcast: float
    previous_nowcast: float
    input_changes: dict[str, float]
    scenario_probabilities: dict[str, float]
    explanation: str

def explain_node(state):
    prompt = f"""
    Sähköhuoltovarmuusestimaatti muuttui {state['previous_nowcast']} -> {state['current_nowcast']}.
    Suurimmat input-muutokset: {top_n_changes(state['input_changes'], 5)}.
    Skenaariotodennäköisyydet: {state['scenario_probabilities']}.

    Kirjoita 3-4 lauseen tilannekuva suomeksi huoltovarmuusvastaavalle.
    Yhdistä numeerinen muutos geopoliittiseen tilanteeseen jos GPR-indeksi tai
    Hormuz-indikaattorit muuttuivat merkittävästi. Älä spekuloi syillä joita
    data ei tue.
    """
    response = anthropic_client.messages.create(...)
    return {"explanation": response.content[0].text}

graph = StateGraph(NowcastState)
graph.add_node("explain", explain_node)
# jne.

Yhteenveto Claude Codelle: Aloita data-pipelinellä. Älä lähde rakentamaan mallia ennen kuin saat puhtaan DataFramen. Pidä koodi modulaarisena niin että samaa pipelineä voi käyttää muille kohdesarjoille (logistiikka, elintarvike) myöhemmin. Validointi joka kerros (testit collectoreille, validointi mallille, vintage-backtest agentille).