Appearance
AI Assistant: Arkitekturvalg og designprinsipper
Dokument for intern gjennomgang. Forklarer hvorfor vi har valgt en deterministisk tilnærming fremfor ren AI, og hva det betyr i praksis.
Kjerneide
AI-assistenten lar brukere modifisere creatives gjennom naturlig språk. Brukeren skriver f.eks. "Lag en tekstblokk med teksten Welcome" i et chatpanel, og AI-en utfører endringen.
Den sentrale designbeslutningen er: hvor mye ansvar gir vi AI-modellen?
| Tilnærming | AI-ens rolle | Backendlogikk |
|---|---|---|
| Ren AI | Modellen konstruerer rått JSON, kjenner alle properties, håndterer alle defaults | Minimal -- bare validering og lagring |
| Deterministisk (vårt valg) | Modellen velger riktig verktøy og sender noen få parametere | Tung -- backend bygger komplett JSON, setter defaults, validerer, håndterer plumbing |
Vi har valgt det deterministiske. AI-modellen er en "beslutningstaker", ikke en "JSON-bygger".
Hvordan det fungerer i praksis
Eksempel: "Lag en tekstblokk med teksten Welcome"
Steg 1: Bruker sender melding
AIAssistantPanel.vue (Frontend)
| POST /ai-assistant/chat { message: "Lag en tekstblokk...", creativeId: "abc123" }
v
AiAssistantController.ts (Backend)
| Henter creative fra DB, parser JSON-blob
v
AiAssistantService.ts
| Bygger system prompt + oppsummering av creative
| Sender til Claude API med verktøydefinisjoneneSteg 2: Claude velger verktøy
Claude ser verktøyet add_text med disse parameterne:
json
{
"text": "Welcome",
"fontSize": "24px"
}Det er alt Claude trenger å sende. To felter.
Steg 3: Backend gjør resten
Når backend mottar add_text({ text: "Welcome", fontSize: "24px" }), gjør den:
- Genererer komplett textProperties-objekt med ~40 standardverdier (bakgrunn, border, skygge, padding, font, alignment, animasjon...)
- Sjekker bakgrunnsfargen på creativen og setter tekstfarge automatisk (hvit på mørk bakgrunn, svart på lys)
- Gir blokken en unik ID (
textProperties-1) - Plasserer blokken i riktig rekkefølge
- Lagrer oppdatert JSON-blob til database
Resultatet er en komplett, gyldig blokk. Ingen sjanse for at den mangler et felt eller har feil format.
Kontrast: Hvordan ren AI ville gjort det
Med ren AI måtte Claude selv konstruere hele JSON-strukturen:
json
{
"type": "textProperties",
"properties": {
"text": "Welcome",
"blockName": "textProperties-1",
"order": 1,
"hidden": false,
"rotate": 0,
"textStyling": {
"fontSize": "24px",
"fontFamily": "Roboto",
"fontWeight": "400",
"color": "#000000FF",
"lineHeight": "1.4",
"textAlign": "center",
"letterSpacing": "0px"
},
"background": {
"mode": "none",
"backgroundSettings": {
"backgroundColor": "#FFFFFFFF",
"backgroundGradient": { "type": "linear", "angle": 180, "stops": [] },
"backgroundImage": { "url": "", "size": "cover" }
}
},
"border": { "width": "0px", "style": "solid", "color": "#000000FF" },
"boxShadow": { "x": "0px", "y": "0px", "blur": "0px", "spread": "0px", "color": "#00000040" },
"...": "...20+ flere felter..."
}
}Problemene med dette:
- Claude må kjenne ~40 properties med eksakte navn og formater
- Feil i ett felt = ugyldig blokk som krasjer renderingen
- Systemprompten må være mye lengre for å forklare alt dette
- Haiku (modellen vi bruker) gjør feil på slike detaljerte JSON-strukturer relativt ofte
- Hvert forsøk bruker mange flere tokens (= høyere kostnad)
Filer som berøres
Application-Backend/
app/Services/AiAssistantService.ts -- Kjernelogikk: verktøy, defaults, validering, agentic loop
app/Controllers/Http/AiAssistantController.ts -- HTTP-endepunkt, auth, blob-håndtering
Application-Frontend/
src/services/aiAssistantService.ts -- API-klient (Axios)
src/store/modules/aiAssistant.ts -- Vuex: meldinger, loading, token-sporing
src/components/AIAssistant/AIAssistantPanel.vue -- Chat-UIAll verktøylogikk lever i én fil: AiAssistantService.ts. Det er der systemprompten, verktøydefinisjonene, validatorene og eksekveringen ligger.
Verktøy vi har i dag
Blokkverktøy (lager visuelle elementer)
| Verktøy | Hva det gjør |
|---|---|
add_text | Legger til tekstblokk med automatisk fargekontrast |
add_button | Legger til knapp med label og farger |
add_group | Lager en flexbox-gruppe for organisering |
add_css_effect | Legger til CSS-animasjon (usynlig HTML-blokk) |
set_background | Setter bakgrunnsfarge på creativen |
Flow-verktøy (bygger interaktivitet)
| Verktøy | Hva det gjør |
|---|---|
add_statement | Legger til spørsmål/melding i flow |
add_answer | Legger til svaralternativ koblet til et spørsmål |
add_showhide | Viser/skjuler blokker på et tidspunkt i flowen |
add_delay | Venter et antall millisekunder før neste steg |
patch_showhide | Legger til flere targets på en eksisterende show/hide |
add_script | Legger til JavaScript i en Tag-operator |
Lavnivå-verktøy (for spesielle tilfeller)
| Verktøy | Hva det gjør |
|---|---|
patch_block | Oppdaterer enkeltproperties på en blokk (dot-notation) |
inspect_block | Leser properties på en blokk (read-only) |
remove_block | Sletter en blokk |
reset_creative | Nullstiller alt -- fjerner alle blokker og operatører |
Høynivåverktøyene dekker det meste. Lavnivåverktøyene er en sikkerhetsventil for ting vi ikke har laget dedikerte verktøy for ennå.
Kostnadssammenligning
Vi bruker Claude Haiku 4.5 ($0.80 per million input-tokens, $4.00 per million output-tokens).
Deterministisk tilnærming (vårt valg)
| Typisk verdi | |
|---|---|
| Input-tokens per kall | ~2 000 (systemprompt + verktøy + melding) |
| Output-tokens per kall | ~200 (verktøyvalg + kort svar) |
| Iterasjoner | 1-3 |
| Totalt per request | ~3 000 input, ~400 output |
| Kostnad | ~$0.004 (0.4 cent) |
Ren AI (uten høynivåverktøy)
| Typisk verdi | |
|---|---|
| Input-tokens per kall | ~5 000 (lang systemprompt med JSON-skjemaer) |
| Output-tokens per kall | ~800 (full JSON-konstruksjon) |
| Iterasjoner | 3-6 (feil, retry, korrigeringer) |
| Totalt per request | ~15 000 input, ~3 000 output |
| Kostnad | ~$0.024 (2.4 cent) |
Deterministisk er ~6x billigere per kall.
For en bruker som sender 20 meldinger i en sesjon:
| Tilnærming | Kostnad per sesjon |
|---|---|
| Deterministisk | ~$0.08 |
| Ren AI | ~$0.48 |
Med Sonnet (bedre modell, $3/$15 per million tokens) i stedet for Haiku:
| Tilnærming | Kostnad per sesjon |
|---|---|
| Deterministisk med Sonnet | ~$0.30 |
| Ren AI med Sonnet | ~$1.80 |
Hvorfor kostnadsforskjellen er så stor
- Kortere output: Claude sender
{ text: "Welcome" }i stedet for 40+ felter med JSON - Færre iterasjoner: Høynivåverktøy feiler sjelden, så Claude trenger ikke prøve på nytt
- Kortere systemprompt: Trenger ikke forklare JSON-skjemaer, bare verktøynavnene
- Ingen feilretting: Deterministiske defaults betyr ingen "ops, galt felt"-sykluser
Fordeler med deterministisk tilnærming
Pålitelighet
Høynivåverktøy feiler nærmest aldri. Når Claude kaller add_text, får den en komplett, gyldig blokk -- uavhengig av modellens "dag". Med ren AI varierer kvaliteten fra kall til kall, spesielt med en rimeligere modell som Haiku.
Konsistens
Alle tekstblokker laget av AI-en ser like ut som de brukere lager manuelt i builderen. Samme defaults, samme format, samme struktur. Det er ingen risiko for at AI-en "finner opp" en property som ikke finnes.
Skalerbarhet
Vi kan oppgradere til en bedre modell (Sonnet) uten å endre noe -- de samme verktøyene fungerer enda bedre med en smartere modell. Og vi kan legge til nye verktøy uten å skrive om systemprompten.
Sikkerhet og kontroll
Validatorer hindrer farlige operasjoner:
<script>i HTML-blokker avvises (JavaScript må gå via Tag-operator)basePropertieskan ikke slettes (creativen trenger en bakgrunn)- Inputverdier normaliseres (farger til 8-tegns hex, etc.)
Begrensninger -- og hvorfor de er akseptable
"AI-en kan ikke gjøre ALT"
Det er riktig. AI-en kan i dag lage tekst, knapper, grupper, CSS-effekter, quiz-flows og tidsbaserte sekvenser. Den kan ikke (ennå) lage video-blokker, forms, slidere, eller sette animasjoner.
Hvorfor dette er greit:
- Vi ruller ut nye verktøy etter hvert som vi tester dem grundig
- Hvert nytt verktøy er 100% pålitelig fra dag én -- ingen "det funker av og til"
- Brukerne får guardrails, ikke fritt spillerom. De kan ikke ved et uhell ødelegge en creative med en vag instruksjon
patch_blockfungerer som sikkerhetsventil for alt vi ikke har laget dedikert verktøy for
"Krever mer backendkode"
Hver ny blokktype trenger en dedikert tool-executor med defaults. Det er mer arbeid enn å bare gi Claude et generisk verktøy. Men det arbeidet gjøres én gang, og resultatet er et verktøy som aldri feiler.
"Systemprompten må oppdateres"
Når vi legger til nye verktøy, må vi oppdatere systemprompten så Claude vet når den skal bruke dem. Men prompten er kort (~300 tokens) og endringene er små.
Oppsummering
| Deterministisk (vårt valg) | Ren AI | |
|---|---|---|
| Pålitelighet | Nærmest 100% | Varierer, spesielt med Haiku |
| Kostnad per sesjon | ~$0.08 | ~$0.48 |
| Feilhåndtering | Backend validerer alt | Modellen må selv korrigere |
| Nye funksjoner | Krever ny backend-kode | "Gratis" (bare prompt-endring) |
| Kontroll | Full kontroll over hva AI-en kan gjøre | Begrenset til prompt-guardrails |
| Konsistens | Identisk med manuell bygging | Kan avvike fra forventet format |
Den deterministiske tilnærmingen koster mer å utvikle, men gir et produkt som er billigere å kjøre, mer pålitelig, og tryggere for brukerne.