# Superagentti — itseoppiva koodausjärjestelmä

Visio: järjestelmä joka **oppii joka iteraatiolla** ja kehittyy lopulta superagentiksi ohjelmointitehtäviin.

## Miksi tämä on realistista

Benchmark-järjestelmä (`model-benchmark.mjs`) tarjoaa jo valmiin **fitness-funktion**: pytest-tulokset antavat yksiselitteisen signaalin (6/6 vs 0/6). Se on itseoppivan järjestelmän vaikein osa — ja se on valmis.

Puuttuvat palaset ovat analysoija ja promptin evoluutio.

## Arkkitehtuuri

```
    ┌──────────────┐
    │  Benchmark   │ ← nykyinen model-benchmark.mjs
    │  (suorita)   │
    └──────┬───────┘
           │ results.json + _pytest.txt + _code_raw.txt
           ▼
    ┌──────────────┐
    │  Analysoija  │ ← luokittele virheet automaattisesti
    │              │   "pyproject: poetry vs pep621"
    │              │   "testi kutsuu olematonta endpointia"
    └──────┬───────┘
           │ virheluokat + korjausohjeet
           ▼
    ┌──────────────┐
    │  Promptin    │ ← muokkaa prompteja tulosten perusteella
    │  evoluutio   │   lisää sääntöjä, few-shot-esimerkkejä
    └──────┬───────┘
           │ parannetut promptit
           ▼
    ┌──────────────┐
    │  Benchmark   │ ← aja uudestaan parannetuilla prompteilla
    │  (uusinta)   │
    └──────────────┘
         ↻ toista kunnes 100%
```

## Toteutustasot

### Taso 1 — Virhepohjainen promptin korjaus

Helpoin ja nopein toteuttaa. Pytest-virheistä tunnistetaan virheluokka ja lisätään sääntö promptiin automaattisesti.

**Esimerkki:**
- Benchmark tuottaa: `pyproject.toml` käyttää Poetry-muotoa
- Analysoija tunnistaa: `[tool.poetry]` → virheluokka `wrong-pyproject-format`
- Evoluutio lisää promptiin: `"pyproject.toml MUST use PEP 621 [project] format, NOT [tool.poetry]"`
- Seuraava ajo onnistuu

**Virheluokkia** (havaittu ensimmäisistä ajoista):
| Virheluokka | Kuvaus | Promptikorjaus |
|-------------|--------|----------------|
| `wrong-pyproject-format` | Poetry-muoto PEP 621:n sijaan | Lisää sääntö: "use [project], not [tool.poetry]" |
| `missing-endpoint-test` | Testi kutsuu endpointia jota ei ole | Lisää sääntö: "only test endpoints defined in main.py" |
| `missing-import` | Puuttuva import | Korjaussilmukan asia (taso 4) |
| `unique-constraint` | Testi ei käsittele duplikaatteja | Lisää sääntö: "use unique test data per test" |

### Taso 2 — Few-shot oppiminen

Onnistuneet generoinnit talteen "kultaisiksi esimerkeiksi" joita syötetään tuleviin prompteihin.

**Miten toimii:**
1. Benchmark-ajo tuottaa 100% PASS -tuloksen (esim. blog-skenaario)
2. Generoidut tiedostot tallennetaan `golden-examples/blog/` -hakemistoon
3. Seuraavissa ajoissa CODE_SYSTEM-promptiin liitetään: "Tässä on toimiva blog-projekti, generoi vastaava todo-projektille"
4. Malli näkee konkreettisesti mitä odotetaan

**Etu:** Laatu nousee nopeasti koska malli saa tarkan esimerkin odotetusta rakenteesta — tiedostomarkerit, importit, pyproject-muoto.

### Taso 3 — Monimalliorkesteri

Eri malli eri vaiheeseen. Benchmark-data kertoo mikä malli on missä paras.

**Esimerkki:**
| Vaihe | Paras malli | Perustelu |
|-------|-------------|-----------|
| Vaatimukset | qwen3:30b | Nopea, hyvä suomenkielinen ymmärrys |
| JSON-speksi | gemma4:31b | Tarkka strukturoitu output |
| Koodigenerointi | qwen3-coder-next | Suunniteltu koodaukseen |
| Korjaus | devstral:24b | Hyvä virheiden analysointi |

**Kahden GPU:n hyödyntäminen:** Vaiheita voi ajaa rinnakkain eri malleilla eri GPU:illa. Esim. speksi GPU1:llä samalla kun edellinen koodi validoidaan GPU2:lla.

### Taso 4 — Itsekorjaava agenttilooppi

Nykyinen korjaussilmukka (max 2 kierrosta) käyttää staattista validaattoria. Taso 4 syöttää **oikean pytest-virheviestin** mallille.

**Nykyinen (rajoitettu):**
```
validaattori → "ISSUE: relatiivinen import" → LLM korjaa → aja uudestaan
```

**Taso 4 (itsekorjaava):**
```
pytest → "IntegrityError: UNIQUE constraint failed" → LLM analysoi → korjaa → pytest → ✓
```

**Iteraatiolooppi:**
1. Aja pytest
2. Jos virheitä: syötä virheilmoitus + koodi mallille
3. Malli korjaa koodin
4. Aja pytest uudestaan
5. Toista kunnes PASS tai max N kierrosta

Tämä on lähellä sitä miten Claude Code ja Cursor toimivat sisäisesti.

### Taso 5 — Promptin evoluutio (geneettinen)

Automaattinen promptien optimointi geneettisellä algoritmilla.

**Algoritmi:**
1. Generoi N promptivarianttia (mutaatiot: lisää sääntö, poista sääntö, muokkaa sanamuotoa)
2. Aja benchmark jokaisella variantilla
3. Pisteytä: `fitness = testsPassed / testsTotal`
4. Valitse parhaat (top-K)
5. Risteytä ja mutaatioi uusia variantteja
6. Toista

**Mutaatio-operaatiot:**
- `add_rule`: Lisää uusi sääntö promptiin (peräisin virheanalyysistä)
- `remove_rule`: Poista sääntö joka ei vaikuta tuloksiin
- `rephrase`: Muotoile sääntö uudelleen (esim. "MUST" → "ALWAYS", esimerkin lisäys)
- `reorder`: Vaihda sääntöjen järjestystä (promptin alku painottuu enemmän)

## Superagentti syntyy kun

Yhdistetään kaikki tasot: järjestelmä **valitsee parhaan mallin tehtävään** (taso 3), **käyttää opittuja prompteja** (taso 2), **korjaa virheensä itse** (taso 4), ja **parantaa promptejaan joka kierroksella** (taso 5).

## Benchmark — kehityksen todentaminen

Ilman kunnollista pisteytystä ja historiaa ei voi todentaa kehitystä. Benchmark-järjestelmä tarvitsee kolme kerrosta: **metriikat**, **vaikeustasot** ja **historiavertailu**.

### Metriikat

Yksittäinen "PASS/FAIL" ei riitä. Jokainen ajo pisteytetään moniulotteisesti:

| Metriikka | Mitä mittaa | Pisteytys |
|-----------|------------|-----------|
| **Parsittavuus** | Tuottiko malli kaikki 5 tiedostoa oikeilla markereilla? | 0–5 (tiedostoa) |
| **Syntaksi** | Parsitaanko koodi virheettä? | 0–4 (.py-tiedostot) |
| **Importit** | Ovatko kaikki importit resolvable? | 0/1 per tiedosto |
| **Testit** | Pytest pass rate | passed / total (0.0–1.0) |
| **Korjauskierrokset** | Montako korjausta tarvittiin? | 0 = paras, >2 = huono |
| **Token-tehokkuus** | Tokenia per läpäisty testi | pienempi = parempi |
| **Nopeus** | tok/s ja kokonaisaika | isompi tok/s = parempi |
| **Varoitukset** | Deprecation warnings, style issues | 0 = paras |

**Kokonaispistemäärä** (0–100):

```
score = (
    parsittavuus/5 * 15 +       # 15p: tiedostot syntyvät
    syntaksi/4 * 15 +            # 15p: koodi parsitaan
    testit * 40 +                # 40p: testit menevät läpi (tärkein)
    (1 - korjaukset/max) * 10 +  # 10p: ei tarvitse korjauksia
    tehokkuus_norm * 10 +        # 10p: vähän tokeneita per testi
    nopeus_norm * 10             # 10p: nopea generointi
)
```

Testien paino on 40% koska toimiva koodi on tärkein. Parsittavuus ja syntaksi ovat "pääsyvaatimuksia" — ilman niitä testejä ei voi edes ajaa.

### Vaikeustasot

Kolme nykyistä skenaariota (todo, users, blog) ovat kaikki samaa tasoa. Kehityksen mittaamiseen tarvitaan portaikko:

**Taso 1 — Perus-CRUD** (nykyiset)
- Yksi entiteetti, ei relaatioita
- Esim. todo, users
- Odotettu tulos: 100% kaikilla kelvollisilla malleilla

**Taso 2 — Relaatiot** (nykyinen blog)
- 2–3 entiteettiä, foreign key -viittaukset
- Esim. blog (author → post), kirjasto (author → book)
- Haaste: relaatioiden oikea käsittely, cascade

**Taso 3 — Liiketoimintalogiikka**
- Validointisääntöjä, tilasiirtymiä, laskentaa
- Esim. verkkokauppa (tuote → tilaus → tilausrivi, varastosaldo, hintalaskenta)
- Haaste: pelkkä CRUD ei riitä, tarvitaan custom-endpointeja

**Taso 4 — Kehittyneet patternit**
- Autentikointi, middleware, taustatehtävät, WebSocket
- Esim. chat-sovellus (käyttäjä → huone → viesti, reaaliaikainen, online-status)
- Haaste: arkkitehtuuriosaamisesta, ei vain tietomallista

**Skenaariot per taso:**

```python
SCENARIOS = [
    # Taso 1 — Perus-CRUD
    {"id": "todo",      "level": 1, "prompt": "Todo-sovellus: tehtävien hallinta, deadline, prioriteetti ja status"},
    {"id": "users",     "level": 1, "prompt": "REST API käyttäjähallinnalle SQLite-tietokannalla"},
    {"id": "notes",     "level": 1, "prompt": "Muistiinpanosovellus: otsikko, sisältö, tagit, luontipäivä"},

    # Taso 2 — Relaatiot
    {"id": "blog",      "level": 2, "prompt": "Blogi-API: kirjoittajat ja artikkelit, julkaisupäivämäärä ja status"},
    {"id": "library",   "level": 2, "prompt": "Kirjasto-API: kirjailijat, kirjat ja lainaukset, palautuspäivä ja sakko"},
    {"id": "school",    "level": 2, "prompt": "Kouluhallinto: opettajat, kurssit ja ilmoittautumiset, arvosanat"},

    # Taso 3 — Liiketoimintalogiikka
    {"id": "shop",      "level": 3, "prompt": "Verkkokauppa: tuotteet, tilaukset ja tilausrivit, varastosaldo vähenee tilauksessa, kokonaishinta lasketaan automaattisesti"},
    {"id": "booking",   "level": 3, "prompt": "Varausjärjestelmä: resurssit ja varaukset, päällekkäiset varaukset estetään, peruutus vapauttaa ajan"},
    {"id": "project",   "level": 3, "prompt": "Projektinhallinta: projektit, tehtävät ja kommentit, tehtävän status-siirtymät (todo→doing→done), projektin edistymisprosentti lasketaan tehtävistä"},
]
```

### Historiavertailu

Tulokset tallennetaan aikasarjana jotta kehitys näkyy:

```
benchmark-history/
├── 2026-04-14_1200_v1.json    ← ensimmäinen ajo
├── 2026-04-14_1500_v2.json    ← prompti paranneltu
├── 2026-04-15_0900_v3.json    ← few-shot lisätty
└── latest.json                ← symlink uusimpaan
```

**Jokainen tallennus sisältää:**
```json
{
    "version": "v3",
    "timestamp": "2026-04-15T09:00:00Z",
    "prompts_hash": "a3f2c1...",
    "results": [
        {
            "model": "qwen3-coder-next",
            "scenario": "todo",
            "level": 1,
            "score": 85,
            "metrics": {
                "parsability": 5,
                "syntax": 4,
                "tests_passed": 6,
                "tests_total": 6,
                "fix_rounds": 0,
                "tokens": 2100,
                "tok_per_sec": 72,
                "warnings": 0
            }
        }
    ],
    "summary": {
        "avg_score": 72,
        "pass_rate": 0.67,
        "by_level": {"1": 95, "2": 72, "3": 48}
    }
}
```

**Kehitysraportti** (automaattinen vertailu edelliseen):

```
╔═══════════════════════════════════════╗
║  Kehitysraportti v2 → v3             ║
╠═══════════════════════════════════════╣
║  Kokonaispistemäärä:  62 → 72 (+10)  ║
║  Pass rate:          44% → 67% (+23) ║
║  Taso 1:              80 → 95 (+15)  ║
║  Taso 2:              60 → 72 (+12)  ║
║  Taso 3:              45 → 48 (+3)   ║
║                                       ║
║  Parantunut:  pyproject-muoto ✓      ║
║  Parantunut:  import-ongelmat ✓      ║
║  Ennallaan:   liiketoimintalogiikka  ║
╚═══════════════════════════════════════╝
```

### Regressiotunnistus

Jos promptimuutos parantaa yhtä skenaariota mutta rikkoo toisen, se pitää havaita:

- Jokaisella ajolla verrataan **kaikkia skenaarioita** edelliseen
- Jos mikä tahansa skenaario laskee >10 pistettä → **varoitus**
- Jos taso 1 (perus-CRUD) laskee → **esto** (perustason pitää aina toimia)

## Toteutusjärjestys

```
Taso 1  ██████████  ← aloita tästä (päivä)
Taso 4  ████████    ← seuraavaksi (päivä)
Taso 2  ██████      ← golden examples (päivä)
Taso 3  ████        ← monimalli (2-3 päivää)
Taso 5  ██          ← evoluutio (viikko)
```

Taso 1 antaa suurimman hyödyn nopeimmin. Taso 4 (itsekorjaava looppi) on toiseksi tärkein koska se moninkertaistaa onnistumisprosentin. Taso 5 on pitkän aikavälin investointi.

## Mallisuositukset VRAM-luokittain

Testattu 2026-04-14 Kipinä CodeBench -benchmarkilla (3 skenaariota: todo, users, blog). Kaikki ajot `think: false`, `num_ctx: 16384`.

### Suositellut mallit

| VRAM | Malli | Pisteet | Testit | tok/s | VRAM-käyttö |
|------|-------|---------|--------|-------|-------------|
| **4 GB** | qwen3:4b | ★★☆☆☆ 33p | 6/6* | 47 | ~3.5 GB |
| **8 GB** | **qwen3:8b** | **★★★★★ 95p** | 25/27 (93%) | **99** | ~7 GB |
| **16 GB** | **qwen3:14b** | **★★★★★ 100p** | 25/25 (100%) | 60 | ~11 GB |
| **24 GB** | **qwen3-coder:30b** | **★★★★★ 97p** | 23/24 (96%) | **123** | ~22 GB |
| **48 GB** | qwen3-coder:30b + qwen3:14b | — | — | — | ~33 GB |

*qwen3:4b: todo 6/6 täydellinen, mutta users ja blog epäonnistuvat speksivaiheessa

### Perustelut

**4 GB** — qwen3:4b (2.5 GB + ~1 GB KV-cache). Ainoa toimiva vaihtoehto. Riittää yksinkertaisiin CRUD-tehtäviin mutta monimutkaisten skenaarioiden speksivaihe epäonnistuu.

**8 GB** — qwen3:8b on benchmarkin paras hinta-laatu. 95p ja 99 tok/s viidellä gigalla. Lähes yhtä hyvä kuin 2× isompi qwen3:14b.

**16 GB** — qwen3:14b, benchmarkin kokonaisvoittaja: 100p kaikissa skenaarioissa. 4 GB jää muulle käytölle (IDE, selain, OS).

**24 GB** — qwen3-coder:30b, nopein huippumalli (123 tok/s). Agenttiloopissa nopeusero on merkittävä: 3 skenaariota 94 sekunnissa vs. qwen3:14b 152 sekunnissa.

**48 GB** — kaksi mallia rinnakkain: qwen3-coder:30b raskaaseen koodingenerointiin, qwen3:14b kevyempiin tehtäviin (korjaukset, speksit, refaktorointi). Yhteensä ~33 GB, 15 GB puskuria.

### Hylätyt vaihtoehdot

| Malli | Koko | Pisteet | Miksi ei |
|-------|------|---------|----------|
| qwen2.5-coder:3b | 1.9 GB | 33p | qwen3:4b parempi samoilla pisteillä |
| qwen2.5-coder:7b | 4.7 GB | 26p | qwen3:8b päihittää selvästi (95p vs 26p) |
| qwen2.5-coder:32b | 19.9 GB | 79p* | qwen3-coder:30b parempi ja nopeampi |
| qwen3.5:35b | 24 GB | 40–60p | Epätasainen, 0/1 collection erroreja |
| qwen3.5:27b | 17.4 GB | 54p | qwen3:14b parempi ja pienempi |
| gemma4:31b | 19.9 GB | 80p | Hyvä laatu mutta 4× hitaampi (28 tok/s) |
| gemma4:e4b | 9.6 GB | 58p | qwen3:8b parempi ja pienempi |
| codestral:22b | 12.6 GB | 88p | Mistral-perheen paras, varamalli |
| devstral:24b | 14.3 GB | 44p | Agentti-malli, huono koodigeneroinnissa |
| mistral-small3.1:24b | 15.5 GB | 30p | Heikko, test_main.py puuttui usein |
| qwen3-coder-next | 51 GB | 69p | Pettymys suhteessa kokoon |

*epätasainen: todo 100p, users 0p, blog 63p

### Thinking-moodi

Testattu qwen3:14b ja qwen3:8b thinking-moodilla (`--think`). Tulos: **thinking huonontaa tuloksia**.

| Malli | No-think | Think | Ero |
|-------|----------|-------|-----|
| qwen3:14b | ★★★★★ 100p | ★★★☆☆ 51p | −49p |
| qwen3:8b | ★★★★★ 95p | ★★★★☆ 77p | −18p |

Ajattelu tuottaa 2–3× enemmän tokeneita mutta laatu laskee. Suositus: **käytä aina `think: false`** koodingenerointiin.

### Yllätykset

1. **Yleismallit voittivat kooderimallit.** qwen3:8b (5 GB yleismalli, 95p) päihittää qwen2.5-coder:32b (20 GB kooderimalli, 79p).
2. **qwen3:14b on paras.** 9.3 GB malli sai 100p — parempi kuin mikään isompi malli.
3. **Koko ei ratkaise.** qwen3-coder-next (51 GB) sai vain 69p. gemma4:31b (20 GB) sai 80p. qwen3:14b (9.3 GB) sai 100p.
