Files
agentic-studio/network-poc/frontend/public/GUIDE.md
Jaakko Vanhala a8c4af0975 Frontend uudelleenrakennettu: Astro-komponentit, Wasm pääsäikeessä, ei Workeria
Vanha frontend siirretty temp/. Uusi rakenne:
- StatusBar.astro, Terminal.astro, Editor.astro, Guide.astro
- global.css erillinen
- Wasm pääsäikeessä (ei Worker — yksinkertainen, debugattava)
- Tab-completion, dropdown, projektikortti, Monaco, GUIDE.md
- Ei tokenisointia eikä koodilaboratoriota

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 20:17:39 +03:00

14 KiB

Kipinä Agentic Studio — Opas

Hajautettu AI-laskentaverkko jossa kielimallit ajavat koodia suoraan selaimessa. Tämä opas selittää miten kielimallit toimivat, miten niitä ohjataan, ja miten tuloksia voi parantaa.


Kielimallit ja niiden koot

Kielimalli on neuroverkko joka ennustaa seuraavan sanan (tokenin) edellisten perusteella. Mallin "koko" tarkoittaa parametrien (painojen) määrää:

Malli Parametrit Koko levyllä Nopeus selaimessa Koodinlaatu
SmolLM 135M 135 miljoonaa ~270 MB ~5 tok/s Yksinkertainen teksti
Qwen2.5-Coder:0.5B 500 miljoonaa ~990 MB ~3-6 tok/s Pienet funktiot
Qwen2.5-Coder:3B 3 miljardia ~6.2 GB ~0.4 tok/s Kokonaiset tiedostot
GPT-4 (vertailu) ~1800 miljardia ~3.6 TB pilvipalvelu Kokonaiset projektit

Parametrien vaikutus: Jokainen parametri on yksi liukuluku (float16 = 2 tavua) joka tallentaa opittua tietoa. 0.5B-malli tietää perusrakenteet mutta tekee loogisia virheitä. 3B-malli ymmärtää kontekstin paremmin. Ero on kuin sanakirjan ja oppikirjan välillä.

Miksi selaimessa? Malli ajetaan käyttäjän omalla laitteella WebAssemblyn kautta. Data ei lähde koneelta, eikä tarvita pilvipalvelua. Haittapuoli on hitaus — GPU-palvelimella sama 0.5B-malli tuottaa ~100 tok/s.


Tokenit — kielimallin "sanat"

Malli ei näe tekstiä kirjaimina vaan tokeneina. Tokeni on yleensä sanan osa, kokonainen sana tai välilyönti. Tokenisaatio tehdään BPE-algoritmilla (Byte Pair Encoding) joka oppii yleisimmät merkkijonot harjoitusdatasta.

Esimerkki: suomi vs. englanti

Alla oikea tokenisointitulos Qwen2.5-Coder-tokenisaattorilla. Jokainen värikoodattu lohko on yksi tokeni — huomaa miten suomi vaatii enemmän tokeneita saman merkityksen välittämiseen:

Tokenisointivertailu EN/FI

Huomaa miten:

  • Englannin yleiset sanat (the, in, a, function) ovat kokonaisia tokeneita
  • Suomen sanat pilkotaan pienempiin osiin (Hajautettu → 4 tokenia, Distributed → 2)
  • Suomi vaatii 30-50% enemmän tokeneita saman merkityksen välittämiseen
  • Koodiavainsanat (function, list, sort) ovat tehokkaita molemmilla kielillä

Miksi tämä merkitsee?

Jokainen tokeni = yksi laskentakierros. Jos suomi vaatii 50% enemmän tokeneita:

  1. Hitaampi vastaus: 100 tokenin englanninkielinen vastaus ≈ 150 tokenia suomeksi → 50% pidempi odotusaika
  2. Pienempi konteksti: Sama merkityssisältö vie enemmän tilaa konteksti-ikkunasta
  3. Huonompi ymmärrys: Pitkät sanat pilkotaan osiin jotka malli ei välttämättä tunnista → hallusinaatiot lisääntyvät

Siksi tekniset promptit ovat englanniksi — malli saa enemmän informaatiota samassa token-budjetissa ja ymmärtää ohjeet paremmin.

Token-budjetti tässä järjestelmässä:

Osa Tokeneita Osuus
System prompt ~30 kiinteä
Agent prompt ~25 kiinteä
Konteksti (aiemmat tiedostot) 0-300 kasvaa
Käyttäjän prompti ~20-50 vaihtelee
Syöte yhteensä ~75-400
Generoitu vastaus (max) 512 raja
Yhteensä ~600-900 /32 768

Konteksti-ikkuna on reilusti riittävä. Pullonkaula ei ole ikkunan koko vaan mallin kyky ymmärtää pitkää kontekstia — 0.5B-malli alkaa "unohtaa" ohjeet kun konteksti kasvaa yli ~200 tokenin.


Promptit — miten mallia ohjataan

Kolmitasoinen prompttirakenne

flowchart TD
    S["System prompt<br/><i>You are a coding assistant. Respond with ONLY code.</i><br/>🔒 Kiinteä, kovakoodattu — malli priorisoi tämän"]
    A["Agent prompt<br/><i>Olet kokenut ohjelmistokehittäjä...</i><br/>✏️ Käyttäjän muokattavissa UI:ssa"]
    U["User prompt<br/><i>Write ONLY the file main.py...</i><br/>📋 Vaihtelee joka kutsussa, sisältää kontekstin"]
    P["Prefill: ``` <br/>🎯 Pakottaa mallin aloittamaan koodilla"]
    S --> A --> U --> P
    P -->|malli jatkaa| R["Generoitu koodi"]

    style S fill:#1a1e2e,stroke:#f85149,color:#c9d1d9
    style A fill:#1a1e2e,stroke:#d29922,color:#c9d1d9
    style U fill:#1a1e2e,stroke:#3fb950,color:#c9d1d9
    style P fill:#1a1e2e,stroke:#a371f7,color:#c9d1d9
    style R fill:#0d1117,stroke:#58a6ff,color:#58a6ff

Miksi promptit ovat englanniksi?

Qwen2.5-Coder on harjoitettu pääosin englanninkielisellä koodilla ja dokumentaatiolla. Suomenkielinen ohje kuluttaa enemmän tokeneita JA malli ymmärtää sen huonommin. Agenttien nimet ja käyttöliittymä ovat suomeksi, mutta tekniset ohjeet mallille englanniksi.

Poikkeus: agenttipromptit ovat suomeksi koska ne menevät user-blokkiin (ei system-blokkiin) ja niiden tarkoitus on enemmän "persoonallisuus" kuin tekninen ohje.


Prefill-tekniikka

Normaalisti malli päättää vapaasti miten vastaa:

Ilman prefilliä:
  Malli: "Sure! Here is a Python program that prints Hello World:\n```python\nprint('Hello')\n```"
  → 25 tokenia, joista 15 turhia

Prefillin kanssa:
  Me syötämme: ```
  Malli jatkaa: python\nprint('Hello')\n```
  → 5 tokenia, kaikki hyödyllisiä

Prefill on kuin aloittaisit lauseen toisen puolesta — malli jatkaa siitä mihin jäit sen sijaan, että aloittaisi kohteliaalla johdannolla.

Sivuvaikutus: Malli tuottaa kielitunnisteen (python, rust) ja sulkevan ```:n. Nämä siivotaan jälkikäteen strip_markdown_wrapper-funktiolla.


Sampling — miten malli valitsee seuraavan tokenin

Malli ei "tiedä" oikeaa vastausta. Se laskee jokaiselle mahdolliselle seuraavalle tokenille todennäköisyyden ja valitsee yhden. Valintaa ohjataan kolmella parametrilla:

Temperature (0.7)

Kontrolloi "luovuutta" vs. "varmuutta":

Temperature 0.0 (greedy):  Aina todennäköisin tokeni → "def fibonacci(n):"
Temperature 0.7 (oletus):  Painottaa todennäköisiä mutta sallii vaihtelua
Temperature 1.5 (luova):   Lähes satunnainen → "async lambda fib = ..."

0.7 on kompromissi: tarpeeksi determinististä tuottamaan toimivaa koodia, mutta tarpeeksi vaihtelevaa välttämään toistoa.

Top-k (40)

Rajaa valinnan 40 todennäköisimpään tokeniin. Estää mallia valitsemasta täysin absurdeja vaihtoehtoja:

Ilman top-k:  150 936 vaihtoehtoa → voi valita minkä tahansa
Top-k 40:     40 vaihtoehtoa → järkevät vaihtoehdot
Top-k 1:      1 vaihtoehto → greedy (aina sama vastaus)

Repetition penalty (1.15)

Vähentää jo tuotettujen tokenien todennäköisyyttä. Estää mallia juuttumasta luuppiin:

Ilman rangaistusta:  "print print print print print..."
Penalty 1.15:        "print('Hello')\nprint('World')"

1.15 on lievä rangaistus — estää pahimman toiston mutta sallii saman avainsanan (esim. return) esiintymisen useasti.


Stop-sekvenssit — milloin generointi loppuu

Malli generoi tokeneita kunnes jokin näistä tapahtuu:

  1. EOS-tokeni (151645): Mallin oma "loppu"-merkki
  2. Max tokens (512): Kovakoodattu raja
  3. Stop-sekvenssi: Malli alkaa tuottaa selitystä
fn fibonacci(n: usize) -> usize {
    if n <= 1 { return n; }
    fibonacci(n-1) + fibonacci(n-2)
}
                                    ← Tähän asti koodia, ok
// Example usage:                   ← Stop! Tämä ei ole enää vastausta
let result = fibonacci(10);         ← Ei generoida

Tunnistetut stop-sekvenssit: ### , Explanation, Note:, Output:, // Example, # Example. Generointi katkaistaan ja teksti trimmataan stop-kohtaan.


Projekti-pipeline — miten agenttitiimi toimii

flowchart TD
    U["Käyttäjä: FastAPI + SQLite REST API for users"] --> M
    M["🟡 Manageri: Pilko tiedostoiksi"] -->|tiedostolista| C1
    C1["🟢 Koodari: models.py"] -->|"konteksti: models.py"| C2
    C2["🟢 Koodari: main.py"] -->|"konteksti: models + main"| C3
    C3["🟢 Koodari: pyproject.toml"] -->|kaikki tiedostot| T1
    T1["🔵 Testaaja: Review"] -->|bugeja löytyi| C4
    T1 -->|LGTM| Done["✅ Projekti valmis"]
    C4["🟡 Koodari: Korjaukset"] --> T2
    T2["🔵 Testaaja: Uudelleenarviointi"] --> Done

Kontekstin ketjutus on kriittistä: kun koodari kirjoittaa main.py:tä, se saa models.py:n sisällön promptissa. Ilman tätä se ei tietäisi mitä luokkia importata.

Riippuvuusjärjestys: Manageria pyydetään listaamaan riippuvuudet ensin (models.py ennen main.py) jotta kontekstiketju toimii oikeaan suuntaan.


Laadun parantaminen

1. Isompi malli (suurin vaikutus)

0.5B 3B Pilvi-API
Fibonacci Joskus virheitä Yleensä oikein Aina oikein
FastAPI CRUD Voi käyttää Flaskia Oikea kirjasto Täydellinen
Monimutkainen logiikka Hallusinoi Osaa perusasiat Syvä ymmärrys
Nopeus (selain) ~5 tok/s ~0.4 tok/s
Latauksen koko 990 MB 6.2 GB 0 (API)

Käytännössä: kpn load 2 lataa 3B-mallin. Hitaampi mutta huomattavasti parempi koodinlaatu. Suositus monimutkaisiin projekteihin.

2. Paremmat promptit (ilmaista)

Huono: "tee fibonacci"

  • Malli ei tiedä kieltä, formaattia tai kontekstia

Hyvä: "Write a fibonacci function in Rust that returns Vec<u64>"

  • Kieli, palautustyyppi ja rakenne määritelty

Promptin säännöt:

  • Englanniksi (tehokkaampi tokenisointi, parempi ymmärrys)
  • Konkreettinen (mainitse kieli, kirjastot, palautustyyppi)
  • Lyhyt (jokainen sana kuluttaa tokenin konteksti-ikkunasta)
  • Positiivinen ("Write X" ei "Don't write Y")

3. Kontekstin hallinta (pipeline-taso)

Ongelma: 0.5B-malli "unohtaa" promptin alun kun konteksti kasvaa.

Ratkaisu: Pienet, kohdennetut promptit:

  • Yksi tiedosto kerrallaan (ei "kirjoita koko projekti")
  • Vain relevantit aiemmat tiedostot kontekstina
  • Max 4 tiedostoa per projekti

4. Iterointi (review-luuppi)

Yksi generointikierros tuottaa harvoin virheetöntä koodia. Pipeline-arkkitehtuuri mahdollistaa:

  1. Generointi — ensimmäinen versio
  2. Review — testaaja löytää ongelmat
  3. Korjaus — koodari saa palautteen ja korjaa
  4. Uusi review — tarkistetaan korjaukset

Nykyinen järjestelmä tekee max 1 korjauskierroksen. Useampi iteraatio parantaisi laatua mutta kasvattaisi laskenta-aikaa.

5. Erikoistetut system promptit

Oletuspromptit ovat yleiskäyttöisiä. Projektikohtaiset promptit parantavat laatua merkittävästi:

Oletus: "Olet kokenut ohjelmistokehittäjä."

Parempi: "You are a Python backend developer specializing in FastAPI.
Always use Pydantic models for request/response schemas.
Always use dependency injection for database sessions.
Follow the repository pattern."

Agenttikohtaiset promptit voi muokata suoraan UI:ssa.

6. Few-shot esimerkit

Malli oppii parhaiten esimerkeistä. Sen sijaan, että sanot "kirjoita FastAPI endpoint", näytä miltä haluat tuloksen näyttävän:

Write a GET endpoint like this example:

@app.get("/items")
def list_items():
    db = SessionLocal()
    return db.query(Item).all()

Now write a similar endpoint for /users.

0.5B-malli jäljittelee rakennetta tehokkaasti — se on parempi kopioimaan kuin keksimään. Nykyinen pyproject.toml-esimerkki promptissa on tätä tekniikkaa.

7. Temperature-säätö tehtävän mukaan

Nykyinen temperature 0.7 on kompromissi. Eri tehtävät hyötyisivät eri arvoista:

Tehtävä Paras temperature Miksi
Tarkka koodi (CRUD, boilerplate) 0.2-0.4 Determinismi tärkeää
Luova koodi (algoritmit, arkkitehtuuri) 0.6-0.8 Vaihtelu löytää ratkaisuja
Vapaa teksti (kommentit, dokumentaatio) 0.8-1.0 Luonnollisempi kieli

Järjestelmä voisi valita temperaturen automaattisesti tehtävätyypin perusteella.

8. Ensemble — sama prompti usealle mallille

Lähetetään sama tehtävä kahdelle solmulle ja valitaan parempi vastaus. Nykyinen Proof of Compute -arkkitehtuuri tukee tätä periaatteessa: hub voisi reitittää saman task_id:n kahdelle solmulle ja verrata tuloksia.

Käytännössä tämä kaksinkertaistaa laskenta-ajan mutta parantaa laatua merkittävästi — virheellinen vastaus harvoin on sama kahdella ajolla koska sampling on stokastinen.

9. Post-processing (nykyinen)

Mallin raakavastaus siivotaan:

  1. Kielitunniste poistetaan (python, rust, ...)
  2. Sulkeva ``` poistetaan
  3. Johdantolauseet poistetaan ("Sure!", "Here is...")
  4. Selityskommentit poistetaan ("# This is a simple...")
  5. Stop-sekvenssit katkaisevat generoinnin

Tämä ei paranna mallin ajattelua mutta poistaa turhan roskan.

10. Mallin hienosäätö (fine-tuning)

Qwen2.5-Coder on yleiskäyttöinen koodimalli. Jos sitä hienosäätäisi omalla koodiaineistolla (esim. yrityksen koodikanta, tietty framework), se tuottaisi huomattavasti parempaa koodia juuri siihen kontekstiin.

LoRA-hienosäätö 0.5B-mallille vaatii ~4 GB GPU-muistia ja muutaman tunnin harjoittelua. Tulos on erikoistunut malli joka osaa tuottaa esimerkiksi juuri FastAPI + SQLAlchemy -koodia luotettavasti.


Välimuistiarkkitehtuuri — miksi toinen lataus on nopea

Ensimmäinen lataus (hidas):
  Verkko (HuggingFace CDN) → IndexedDB → RAM → Mallin rakennus
  ~990 MB lataus, ~30-60s

Toinen lataus samalla sivulatauksella (nopea):
  RAM-cache → Mallia ei rakenneta uusiksi, vain KV-cache nollataan
  ~0ms

Refresh jälkeen (keskitaso):
  IndexedDB → RAM → Mallin rakennus
  ~0 MB lataus, ~2-5s rakennus

Uusi selain/laite (hidas):
  Verkko → IndexedDB → RAM → Mallin rakennus
  Kuten ensimmäinen lataus

KV-cache: Mallin sisäinen muisti joka tallentaa aiempien tokenien laskenta tulokset. Nollataan (clear_kv_cache()) jokaisen promptin välillä jotta edellinen vastaus ei vuoda seuraavaan.


Lukuja käytännöstä

Yksittäinen funktio (esim. fibonacci):

  • Input: ~80 tokenia
  • Output: ~50-100 tokenia
  • Aika: ~10-20s (0.5B, selain)
  • Laatu: Yleensä toimiva, joskus loogisia virheitä

3 tiedoston projekti (esim. FastAPI CRUD):

  • Manageri: ~30 tok out
  • Koodari (3x): ~100-150 tok out per tiedosto
  • Testeri: ~50 tok out
  • Korjaukset: ~100 tok out (jos tarpeen)
  • Yhteensä: ~500-700 tokenia, ~3-5 min
  • Laatu: Rakenne oikein, yksittäisiä bugeja

Token-kustannus vs. pilvipalvelu:

  • Tässä järjestelmässä: 0 euroa (laskenta omalla koneella)
  • GPT-4 API: ~700 tokenia x $0.03/1K = ~$0.02 per projekti
  • Claude API: ~700 tokenia x $0.015/1K = ~$0.01 per projekti

Selaimessa ajettava malli on ilmainen mutta huomattavasti hitaampi ja heikompilaatuinen kuin pilvi-API. Sopii oppimiseen, prototypointiin ja tilanteisiin joissa data ei saa lähteä omalta koneelta.