5.2 KiB
Templating — rakennuspalaset koodigeneroinnissa
Perusperiaate
Kielimalli päättää mitä rakennetaan (entiteetit, kentät, tyypit, yhteydet). Template-funktiot päättävät miten se rakennetaan (importit, engine setup, testikonfiguraatio).
Projektikuvaus → LLM → JSON-speksi → Templateit → Koodi → Validointi
LLM:n kontribuutio on yksi JSON-rakenne. Kaikki muu on determinististä — sama speksi tuottaa aina saman koodin.
Miksi tämä toimii
Pienen kielimallin (0.5B–7B) vahvuudet ja heikkoudet ovat epäsymmetrisiä:
| Tehtävä | LLM:n kyky | Ratkaisu |
|---|---|---|
| Tunnista entiteetit kuvauksesta | Hyvä | LLM tekee |
| Valitse kenttätyypit | Hyvä | LLM tekee |
| Muista importit oikein | Huono | Template tekee |
| SQLite connect_args | Huono | Template tekee |
| Testikonfiguraatio | Huono | Template tekee |
| Dockerfile-rakenne | Huono | Template tekee |
Annetaan mallin tehdä se missä se on hyvä. Hoidetaan loput mekaanisesti.
JSON-speksi
Kielimallin ainoa tuotos on JSON joka kuvaa projektin rakenteen:
{
"project_name": "library-app",
"entities": [
{
"name": "Author",
"table_name": "authors",
"fields": [
{"name": "name", "sa_type": "String(255)", "py_type": "str", "nullable": false, "default": null}
]
},
{
"name": "Book",
"table_name": "books",
"fields": [
{"name": "title", "sa_type": "String(255)", "py_type": "str", "nullable": false, "default": null},
{"name": "author_id", "sa_type": "Integer", "py_type": "int", "nullable": false, "default": null}
]
}
],
"relationships": [
{"from": "Book", "field": "author_id", "to": "Author", "type": "many-to-one"}
],
"extra_imports": []
}
Speksin laatu ratkaisee kaiken. Hyvä speksi → hyvä projekti. Huono speksi → teknisesti toimiva mutta sisällöllisesti väärä projekti.
Architect-promptin rooli
Architect-agentti (JSON-speksin generoija) on kriittisin kohta koko pipelinessa. Sitä ohjataan neljällä keinolla:
- Chain-of-thought — malli miettii ensin entiteetit, sitten kentät, sitten yhteydet, vasta lopuksi JSON
- Domain-esimerkit — Todo, verkkokauppa, blogi — malli näkee miltä hyvä speksi näyttää eri domaineissa
- Anti-patternit — turhat ID-kentät, Enum-tyypit, suomenkieliset nimet
- Yhteyssäännöt — jokainen
_id-kenttä tarvitsee relationship-merkinnän
Isompi malli tässä yhdessä kohdassa parantaisi kaikkien projektien laatua.
Templateit
Jokainen template on funktio joka ottaa speksin ja palauttaa koodia:
tmplModels(spec) → models.py (SQLAlchemy, ForeignKey, relationship)
tmplSchemas(spec) → schemas.py (Pydantic Create/Response/Detail)
tmplMain(spec) → main.py (FastAPI CRUD + nested endpoints + FK-validointi)
tmplTests(spec) → test_main.py (pytest + TestClient + helper-funktiot)
tmplPyproject(spec) → pyproject.toml (PEP 621)
tmplDockerfile() → Dockerfile (uv + non-root user)
Templateit generoivat automaattisesti:
- ForeignKey-constraintit ja relationship()-määrittelyt
- Nested endpointit (
GET /authors/{id}/books/) - FK-validointi (404 jos parent-entiteettiä ei ole)
- Detail-schemat (Book + author-data mukana)
- Test-helperit jotka luovat parent-entiteetit ensin
- Bad FK -testit (varmistaa että orpo-validointi toimii)
Validointi
Generoitu koodi validoidaan mekaanisesti ennen käyttöä:
- Syntaksitarkistus (AST parse)
- Projektin sisäiset importit (löytyykö nimi lähdetiedostosta)
- SQLite connect_args
- Relatiiviset importit (kielletty)
- Testien rakenne (ei saa kopioida appia)
- pyproject.toml (ei poetryä)
- Dockerfile (ei poetryä, uv cache -oikeudet)
Docker-testi ajaa koko projektin: build → pytest → API smoke test.
Rajoitukset
Templateit kattavat rakenteellisesti tunnetut projektit:
| Stack | Kattavuus |
|---|---|
| FastAPI + SQLAlchemy CRUD | Toimii hyvin |
| Streamlit + DuckDB dashboard | Toimii hyvin |
| Muu | Ei templatea → ei toimi |
Ei kata:
- Custom business-logiikka (algoritmit, laskenta, ML)
- Epätyypilliset arkkitehtuurit (WebSocket, graafit, tapahtumapohjaiset)
- Frontend-sovellukset (React, Vue)
- Mikä tahansa mitä template ei tunne
Arvio: templateit kattavat ~20% kaikista mahdollisista projekteista, mutta juuri sen 20% mitä opiskelu- ja prototyyppiympäristöissä tarvitaan useimmin.
Laajentaminen
Uuden stackin lisääminen vaatii:
- Uudet template-funktiot (käsityö, ~200–400 riviä per stack)
- JSON-speksin laajennos (uudet kentät jos tarvitaan)
- Validointisäännöt uudelle stackille
- Docker-testikonfiguraatio
Jokainen template on staattinen — se ei opi eikä sopeudu. Kattavuus kasvaa vain kirjoittamalla lisää templateja.
Hybridi: seuraava askel
Paras lopputulos syntyisi yhdistelmällä:
Speksi → Template (runko) → LLM (business-logiikka) → Validointi
Template tuottaa toimivan CRUD-pohjan. LLM lisää domain-kohtaisen logiikan pienissä palasissa (yksi funktio kerrallaan). Mekaaninen validointi tarkistaa jokaisen lisäyksen.
Tämä palauttaa LLM:n epäluotettavuuden takaisin peliin, mutta rajattuna: virheet ovat paikallisia (yksi funktio) eivätkä rakenteellisia (koko projekti).