Skip to content

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ærmingAI-ens rolleBackendlogikk
Ren AIModellen konstruerer rått JSON, kjenner alle properties, håndterer alle defaultsMinimal -- bare validering og lagring
Deterministisk (vårt valg)Modellen velger riktig verktøy og sender noen få parametereTung -- 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øydefinisjonene

Steg 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:

  1. Genererer komplett textProperties-objekt med ~40 standardverdier (bakgrunn, border, skygge, padding, font, alignment, animasjon...)
  2. Sjekker bakgrunnsfargen på creativen og setter tekstfarge automatisk (hvit på mørk bakgrunn, svart på lys)
  3. Gir blokken en unik ID (textProperties-1)
  4. Plasserer blokken i riktig rekkefølge
  5. 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-UI

All 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øyHva det gjør
add_textLegger til tekstblokk med automatisk fargekontrast
add_buttonLegger til knapp med label og farger
add_groupLager en flexbox-gruppe for organisering
add_css_effectLegger til CSS-animasjon (usynlig HTML-blokk)
set_backgroundSetter bakgrunnsfarge på creativen

Flow-verktøy (bygger interaktivitet)

VerktøyHva det gjør
add_statementLegger til spørsmål/melding i flow
add_answerLegger til svaralternativ koblet til et spørsmål
add_showhideViser/skjuler blokker på et tidspunkt i flowen
add_delayVenter et antall millisekunder før neste steg
patch_showhideLegger til flere targets på en eksisterende show/hide
add_scriptLegger til JavaScript i en Tag-operator

Lavnivå-verktøy (for spesielle tilfeller)

VerktøyHva det gjør
patch_blockOppdaterer enkeltproperties på en blokk (dot-notation)
inspect_blockLeser properties på en blokk (read-only)
remove_blockSletter en blokk
reset_creativeNullstiller 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)
Iterasjoner1-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)
Iterasjoner3-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ærmingKostnad per sesjon
Deterministisk~$0.08
Ren AI~$0.48

Med Sonnet (bedre modell, $3/$15 per million tokens) i stedet for Haiku:

TilnærmingKostnad per sesjon
Deterministisk med Sonnet~$0.30
Ren AI med Sonnet~$1.80

Hvorfor kostnadsforskjellen er så stor

  1. Kortere output: Claude sender { text: "Welcome" } i stedet for 40+ felter med JSON
  2. Færre iterasjoner: Høynivåverktøy feiler sjelden, så Claude trenger ikke prøve på nytt
  3. Kortere systemprompt: Trenger ikke forklare JSON-skjemaer, bare verktøynavnene
  4. 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)
  • baseProperties kan 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_block fungerer 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ålitelighetNærmest 100%Varierer, spesielt med Haiku
Kostnad per sesjon~$0.08~$0.48
FeilhåndteringBackend validerer altModellen må selv korrigere
Nye funksjonerKrever ny backend-kode"Gratis" (bare prompt-endring)
KontrollFull kontroll over hva AI-en kan gjøreBegrenset til prompt-guardrails
KonsistensIdentisk med manuell byggingKan 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.

Internal documentation