596 lines
21 KiB
Markdown
596 lines
21 KiB
Markdown
# 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:
|
||
|
||

|
||
|
||
**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
|
||
|
||
```mermaid
|
||
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
|
||
|
||
```mermaid
|
||
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.
|
||
|
||
---
|
||
|
||
## Rakennuspalaset vs. vapaa generointi
|
||
|
||
Kielimalli voi generoida koodia kahdella perustavanlaatuisesti eri tavalla.
|
||
Ymmärtäminen milloin kumpikin toimii on avain luotettavaan koodigenerointi-pipelineen.
|
||
|
||
### Tapa 1: Vapaa generointi (naivi)
|
||
|
||
LLM generoi jokaisen tiedoston tyhjästä. Prompti kuvaa mitä halutaan,
|
||
malli tuottaa koko tiedoston — importeista lähtien.
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
P["Prompti"] --> LLM1["LLM: models.py"]
|
||
LLM1 --> V1{"Validointi"}
|
||
V1 -->|virhe| LLM1
|
||
V1 -->|ok| LLM2["LLM: schemas.py"]
|
||
LLM2 --> V2{"Validointi"}
|
||
V2 -->|virhe| LLM2
|
||
V2 -->|ok| LLM3["LLM: main.py"]
|
||
LLM3 --> V3{"..."}
|
||
|
||
style V1 fill:#1a1e2e,stroke:#f85149,color:#c9d1d9
|
||
style V2 fill:#1a1e2e,stroke:#f85149,color:#c9d1d9
|
||
style V3 fill:#1a1e2e,stroke:#f85149,color:#c9d1d9
|
||
```
|
||
|
||
**Ongelma:** Pieni malli (0.5B–7B) tekee toistuvia rakenteellisia virheitä:
|
||
|
||
| Virhe | Esiintymistiheys | Selitys |
|
||
|-------|:---:|------|
|
||
| Puuttuva import | ~60% | `from datetime import date` unohtuu |
|
||
| SQLite `connect_args` | ~80% | Malli ei muista SQLite-erityisyyttä |
|
||
| Väärä Enum-käyttö | ~50% | Sekoittaa `sqlalchemy.Enum` ja `enum.Enum` |
|
||
| Poetry pyproject.toml:ssa | ~40% | Malli suosii Poetryä vaikka ohje sanoo uv |
|
||
| Testit kopioivat koko appin | ~70% | Malli ei osaa importata, luo uudet reitit |
|
||
|
||
Retry-loopilla (virhe → uusi yritys virheviestin kanssa) osa korjautuu,
|
||
mutta **sama malli toistaa samoja virheitä** koska ne johtuvat harjoitusdatasta.
|
||
7 tiedoston projekti vaatii 7–14 LLM-kutsua ja 80–120 sekuntia.
|
||
|
||
### Tapa 2: Rakennuspalaset (template pipeline)
|
||
|
||
LLM:ltä pyydetään **vain JSON-speksi** — entiteetit, kentät ja tyypit.
|
||
Koodi kootaan mekaanisesti valmiista pohjista joiden rakenne on todistettavasti
|
||
oikein.
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
P["Projektin kuvaus"] --> LLM["LLM: JSON-speksi"]
|
||
LLM --> S["{ entities: [...] }"]
|
||
S --> T1["Template: models.py"]
|
||
S --> T2["Template: schemas.py"]
|
||
S --> T3["Template: main.py"]
|
||
S --> T4["Template: test_main.py"]
|
||
S --> T5["Template: Dockerfile"]
|
||
T1 & T2 & T3 & T4 & T5 --> D["Docker build + pytest"]
|
||
|
||
style LLM fill:#1a1e2e,stroke:#d29922,color:#c9d1d9
|
||
style S fill:#1a1e2e,stroke:#3fb950,color:#c9d1d9
|
||
style D fill:#1a1e2e,stroke:#58a6ff,color:#c9d1d9
|
||
```
|
||
|
||
**Idea:** Malli on hyvä päättämään *mitä* (entiteetit, kentät), mutta huono
|
||
muistamaan *miten* (importit, engine setup, testikonfiguraatio). Annetaan
|
||
mallin tehdä se missä se on hyvä, ja hoidetaan loput mekaanisesti.
|
||
|
||
### LLM:n ainoa tehtävä
|
||
|
||
Malli tuottaa JSON-rakenteen kuten:
|
||
|
||
```json
|
||
{
|
||
"project_name": "todo-app",
|
||
"entities": [
|
||
{
|
||
"name": "Todo",
|
||
"table_name": "todos",
|
||
"fields": [
|
||
{"name": "title", "sa_type": "String(255)", "py_type": "str", "nullable": false},
|
||
{"name": "due_date", "sa_type": "Date", "py_type": "date | None", "nullable": true},
|
||
{"name": "status", "sa_type": "String(20)", "py_type": "str", "default": "pending"}
|
||
]
|
||
}
|
||
],
|
||
"extra_imports": ["from datetime import date"]
|
||
}
|
||
```
|
||
|
||
Tämä on yksinkertainen tehtävä jossa pienikin malli onnistuu luotettavasti:
|
||
entiteettien tunnistus projektin kuvauksesta ja kenttätyyppien valinta.
|
||
|
||
Speksi sisältää myös **relaatiot** entiteettien välillä:
|
||
|
||
```json
|
||
{
|
||
"entities": [
|
||
{"name": "Author", "table_name": "authors", "fields": [...]},
|
||
{"name": "Book", "table_name": "books", "fields": [
|
||
{"name": "title", "sa_type": "String(255)", "py_type": "str", "nullable": false},
|
||
{"name": "author_id", "sa_type": "Integer", "py_type": "int", "nullable": false}
|
||
]}
|
||
],
|
||
"relationships": [
|
||
{"from": "Book", "field": "author_id", "to": "Author", "type": "many-to-one"}
|
||
]
|
||
}
|
||
```
|
||
|
||
Templateit generoivat relaatioista automaattisesti:
|
||
- `ForeignKey('authors.id')` models.py:hin
|
||
- `relationship("Book", back_populates="author")` molempiin suuntiin
|
||
- `BookDetail`-schema jossa author-data mukana
|
||
- `GET /authors/{id}/books/` nested endpoint
|
||
- FK-validointi: 404 jos parent-entiteettiä ei ole
|
||
|
||
### Architect-agentti: speksin laatu ratkaisee
|
||
|
||
Arkkitehti on **kriittisin agentti** koko pipelinessa. Jos speksi on hyvä
|
||
(oikeat entiteetit, kentät, relaatiot), kaikki muu seuraa automaattisesti.
|
||
Jos speksi on huono, templateitkaan eivät pelasta.
|
||
|
||
Arkkitehtia ohjataan:
|
||
1. **Chain-of-thought**: "Mieti ensin entiteetit, sitten kentät, sitten relaatiot"
|
||
2. **Domain-esimerkit**: Todo, verkkokauppa, blogi — malli näkee miltä hyvä speksi näyttää
|
||
3. **Anti-patternit**: "Ei turhia ID-kenttiä, ei Enumeita, ei suomenkielisiä nimiä koodissa"
|
||
4. **Relaatiosäännöt**: "Jokainen `_id`-kenttä tarvitsee vastaavan relationship-merkinnän"
|
||
|
||
Isompi malli (tai API) tässä yhdessä kohdassa parantaa kaikkien projektien laatua
|
||
koska speksi on ainoa paikka jossa LLM:n ymmärrys vaikuttaa.
|
||
|
||
### Template täyttää loput
|
||
|
||
Jokainen template on kuin madlib — aukot täytetään speksin datalla:
|
||
|
||
**models.py template (yksinkertaistettu):**
|
||
```python
|
||
from sqlalchemy import create_engine, Column, Integer, {sa_types}, ForeignKey
|
||
from sqlalchemy.orm import sessionmaker, relationship
|
||
# ... aina samat importit, engine setup, SessionLocal ...
|
||
|
||
class {entity.name}(Base):
|
||
__tablename__ = "{entity.table_name}"
|
||
id = Column(Integer, primary_key=True, index=True)
|
||
{field.name} = Column({field.sa_type}, nullable={field.nullable})
|
||
# FK-kentät: ForeignKey + relationship automaattisesti
|
||
{fk_field} = Column(Integer, ForeignKey('{parent_table}.id'))
|
||
{parent_lower} = relationship("{Parent}", back_populates="{children}")
|
||
```
|
||
|
||
Tulos: importit ovat aina oikein, `connect_args` on aina mukana,
|
||
relaatiot generoituvat oikein, testit importoivat `main.py`:stä eivätkä kopioi sitä.
|
||
|
||
### Vertailu: mittaustulokset
|
||
|
||
| | Vapaa generointi | Rakennuspalaset |
|
||
|---|:---:|:---:|
|
||
| LLM-kutsuja | 7–14 | **3** (speksi + requirements + README) |
|
||
| Aika | 80–120s | **~25s** |
|
||
| Syntaksi OK | ~70% | **100%** |
|
||
| Docker build | vaihteleva | **100%** |
|
||
| Pytest läpi | 0% | **100%** |
|
||
| API toimii | ~30% | **100%** |
|
||
| Relaatiot (FK) | ei koskaan | **100%** |
|
||
| Nested endpointit | ei koskaan | **automaattisesti** |
|
||
|
||
### Milloin kumpikin toimii
|
||
|
||
**Rakennuspalaset** kun:
|
||
- Projektin rakenne on tunnettu (FastAPI + SQLAlchemy CRUD)
|
||
- Laatu ja luotettavuus ovat tärkeitä
|
||
- Malli on pieni (0.5B–7B)
|
||
|
||
**Vapaa generointi** kun:
|
||
- Projektin rakenne on epätavallinen
|
||
- Tarvitaan custom-logiikkaa jota template ei kata
|
||
- Malli on riittävän iso (>70B tai pilvi-API)
|
||
|
||
Paras lopputulos syntyy yhdistelmällä: **rakennuspalaset perusrakenteelle,
|
||
vapaa generointi business-logiikalle**.
|
||
|
||
---
|
||
|
||
## 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.
|