Alle artikler

En AI-app uten server, uten konto, og ingenting forlater telefonen

· 10 min lesing

En lørdag i familiekalenderen: « Piscine 10h avec Tom ». Samme kveld får barnet et fransk diktat om svømmehallturen med Tom, skrevet på sitt nivå, som trener bøyningsregelen det tok feil av forrige uke.

Ingenting fra den lørdagen forlater telefonen. Ikke kalenderoppføringen, ikke barnets fornavn, ikke feilene. Det er ingen konto å opprette, ingen server å ringe, ingen statistikk. Sett enheten i flymodus, og appen oppfører seg nøyaktig som ett minutt tidligere.

Appen heter Dictée Ludique. Jeg har skrevet den, den ligger i App Store, og den er det klareste svaret jeg har på et spørsmål kunder nå stiller meg nesten hver uke: kan vi gjøre AI-delen uten å sende brukernes data noe sted?

På Apple-maskinvare er svaret ja, og det finnes i dag. Resten her handler om hva det krevde, hva det kostet meg, og hva iOS 27 endrer i september.

Hvorfor ikke bare spørre en chatbot

Det er det åpenbare spørsmålet, og hele appen ble født ut av det.

Jeg begynte som alle andre. Jeg ba en chatbot skrive et diktat til et barn på ni, og den skrev ett. Til og med et brukbart et.

Så gjorde jeg det igjen uken etter og så hva jeg egentlig hadde. En chatbot gir deg en tekst. Den gir deg ikke et system. Den vet ikke at dette barnet satt trygt på partisippbøyning i november og hadde mistet det i januar, at homofoner aldri er testet en eneste gang, eller at de tre siste tekstene alle handlet om den samme ferien. Det var jeg som bar alt det, og som tastet det inn på nytt i hver eneste ledetekst. Skrivingen var gratis. Regnskapsføringen var hele jobben.

Det jeg ville ha, var maskineriet rundt skrivingen. Femten staveferdigheter fra læreplanen, fulgt barn for barn, hver plassert på behersket, underveis, skjør eller ikke sett ennå. Et rettetrinn etter hvert diktat som flytter de tilstandene, og som tar forelderen omtrent femten sekunder. Deretter en neste tekst som først sikter mot det skjøre og etterpå mot det som ennå ikke har dukket opp, med lengde og tetthet som følger forrige resultat, og uten en eneste innstilling noen må sette opp.

Det måtte også føles som et spill, som er den andre halvdelen av navnet. Ikke poeng og merker. Det finnes bevisst ingen samlet poengsum noe sted i appen, for et gjennomsnitt over femten ferdigheter betyr ingenting og ville vært det ene tallet et barn husket. Spillet er at barnet får tre kort og velger ett, og at teksten handler om dets egen lørdag i stedet for en fremmeds. Et barn skriver annerledes når diktatet handler om bursdagen sin i stedet for naboens katt.

Genereringen viste seg å være den lille delen. Sløyfen rundt den er appen, og den har avgjort alt nedenfor.

Hvorfor skyen aldri var aktuell

Det finnes en regulatorisk grunn, og så finnes den jeg faktisk hadde.

Den regulatoriske er alminnelig. Dette er en barneapp som selges i Europa, så spørsmålene om personvern kommer med den første forelderen som åpner personvernskjermen, ikke etter en emisjon. Å samle inn ingenting betyr ingenting å oppgi, ingenting å lekke og ingenting å forklare.

Den som virkelig avgjorde: appen leser en familiekalender. Det er den mest private filen på en telefon. Der står sykehustimer, overleveringer ved delt omsorg, jobbintervjuer, uken da noen flyttet ut. Jeg skulle ikke bygge et rør derfra til et datasenter jeg ikke eier, og ingen personvernerklæring jeg kunne skrevet ville gjort meg rolig med det.

Begrensningen kom altså først, og arkitekturen måtte leve med den.

Kalenderen filtreres før modellen ser den

Dette er delen alle antar at AI-en gjør. Det gjør den ikke.

En rå hendelsestittel når aldri modellen. Det som når den, er en kanonisk nominalfrase fra en lukket liste med syttitre gjenkjente former. « Piscine 10h avec Tom » kommer ut som « la sortie piscine ». « Anniv de Tom » kommer ut som « l’anniversaire de Tom », og det fornavnet, fanget av et bevisst smalt mønster, er den eneste frie teksten i hele kjeden.

Sammenligningen skjer ved ordgrenser, noe som høres pedantisk ut helt til man ser hva det hindrer. « ski » må ikke slå til på « Kandinsky ». « colo », den franske forkortelsen for en sommerleir, må ikke slå til på « coloscopie ». Den lengste formen vinner, så « sortie scolaire » slår det nakne « sortie ».

En andre liste på sekstito ord diskvalifiserer hele hendelsen med det samme: sykehus, begravelse, skilsmisse, arbeidsledighet, fengsel, og resten av registrene en familiekalender er full av. « Anniversaire de mamie à l’hôpital » er ingen brukbar bursdag, selv om ordet bursdag står rett der.

Det listen ikke kjenner igjen, beholder ikke noe navn i det hele tatt. Det lander på foreldreskjermen som et forslag uten etikett, og det kan ikke brukes før forelderen selv skriver inn et navn på det. Avvist én gang blir det aldri foreslått igjen.

Lesevinduet er asymmetrisk med vilje: to år tilbake for enkelthendelser, to uker fram, og bare én uke tilbake for alt som gjentar seg. Et barn husker en reise i årevis. En judotime fra atten måneder siden er støy.

Alt dette er vanlig Swift. Det er deterministisk, det er dekket av tester, og det er delen som gjør det egentlige personvernarbeidet. Modellen er siste steg, ikke det første.

Modellen skriver teksten og ingenting annet

Genereringen kjører på Apples modell på enheten gjennom Foundation Models-rammeverket, som kom med iOS 26. Utdataene er styrt: en @Generable-struktur med en kort tittel og en tabell med setninger, med tak på tolv.

Setninger som tabell i stedet for én blokk prosa, for modellen holder en mållengde langt bedre når den teller setningene selv.

Modellen blir aldri spurt om hvor stavefellene ligger. Det er jobben til en deterministisk analyse med egne tester. En modell som merker sine egne utdata tar feil av og til uten at noen oppdager det, og det er verre enn å ta feil høylytt.

Den ser heller ingen mal. Det håndskrevne biblioteket må tjene ethvert barn, så det bærer plassholdere og et bøyningsmaskineri. Her kjenner appen allerede fornavnet og det grammatiske kjønnet, så den ber om « Léa est partie » i stedet for « {ENFANT} est parti{E_ENFANT} ». En hel klasse feil forsvinner.

Ingen generert tekst får fribillett

Hver generert tekst går gjennom den samme valideringen i sju trinn som det håndskrevne biblioteket: ordforråd tilpasset klassetrinnet, tillatte tider, setningslengde, forbudte registre, ferdighetene barnet skal trene, dets eget fornavn, og kalenderøyeblikket som faktisk nevnes.

En generert tekst har ingen forrang framfor en tekst et menneske har lest gjennom. Den har til og med litt mindre, fordi den trengte et tak biblioteket aldri hadde bruk for.

Når fem forsøk feiler, serverer appen en tekst fra biblioteket og sier ingenting. Barnet får aldri vite at modellen hadde et dårlig minutt.

Hva modellen på enheten faktisk kostet meg

Den delen står i ingen WWDC-sesjon, så her er tallene fra loggene på min egen enhet.

  • En generering løp løpsk i 48,9 sekunder før den døde på « Exceeded model context window size ». De fire andre forsøkene, med identiske instruksjoner, kom tilbake på 2 til 3,5 sekunder. Inndataene var aldri problemet. Utdataene ville ikke stoppe. Derfra kommer taket på tolv setninger.
  • Første utkast treffer jevnlig en tredjedel av bestilt lengde. Målt på én økt: 29 ord, så 184, så 34, mot en instruksjon som ba om 55 til 75. Å heve temperaturen rister bare på tilfeldigheten. Å fortelle modellen på klar fransk hva den nettopp bommet på, virker. Gjentakelsessløyfen sender derfor nå tilbake en setning som forklarer avviket, i stedet for bare å skru på temperaturen.
  • Modellen laget tekster som besto hver eneste kontroll og likevel var feil for leseren. Elleve setninger til et barn på ni, ordtallet innenfor rammen, hver setning under maksimum, og barnet får et telegram. Et menneske hadde skrevet hver mal i biblioteket, så den feilen fantes ikke der. Modellen gjør den med bemerkelsesverdig utholdenhet, derav taket på antall setninger.
  • Apples sikringer utløses uten å si hvorfor. Feilen lyder « Detected content likely to be unsafe » og ingenting mer. Fem gjentakelser ved stigende temperaturer med samme inndata feiler fem ganger på samme måte. Det appen gjør nå, er å fjerne ting i rekkefølge: først kalenderøyeblikket, siden det er det eneste innholdet appen ikke har skrevet selv, deretter innholdsregelen i instruksjonene. Trinnet som låser opp, er diagnosen, og det går i loggen som det.
  • EventKit kostet meg en ettermiddag av grunner som ikke hadde noe med AI å gjøre. En EKEventStore som opprettes før tillatelsen, beholder en tom hurtigbuffer så lenge prosessen lever, så kalenderoppslaget gir null hendelser selv etter at forelderen har trykket Tillat. Og authorizationStatus(for:) henger etter tildelingen: på iPad kom forespørselen tilbake som true mens statusen, lest tretten millisekunder senere, fortsatt sa notDetermined. Begge ser nøyaktig ut som en tillatelsesfeil, og ingen av dem er det.

En siste begrensning har formet appen mer enn alle de andre. Fem forsøk er taket når et barn ser på en skjerm som sier « vi skriver diktatet ditt ». Appen genererer derfor på forhånd. Å lese et diktat høyt tar minutter, og generatoren arbeider i det vinduet, med tak på ti runder per økt, knyttet til leseskjermen og avbrutt når den lukkes. Ingenting uvalidert havner noen gang i hurtigbufferen. Det kjøper tid, ikke mildhet.

Hva iOS 27 endrer

Mesteparten av listen ovenfor blir løst av versjonen som kommer i september, noe som er rart å skrive om et rammeverk som er ett år gammelt.

  • Modellen på enheten er bygget om, med bedre logikk, bedre verktøykall og sikringer som ifølge Apple gir færre falske alarmer. Det treffer direkte min dyreste feilmodus. Bedre etterlevelse av instruksjoner bør også senke antallet gjentakelser, og det er forskjellen mellom å generere på forhånd og å generere på forespørsel.
  • response.usage rapporterer nå tokens for inndata, utdata, hurtigbuffer og resonnement, model.contextSize viser vinduet, og tokenCount(for:) teller en ledetekst før den sendes. Utskeielsen min på 48,9 sekunder blir dermed noe jeg kan se komme, i stedet for noe jeg finner i en logg etterpå.
  • Modellen på enheten tar imot bilder, og rammeverket leverer et OCRTool på enheten, båret av Vision. Det er det jeg stadig tenker på. Beskrivelsen i App Store lover i dag at appen ikke fotograferer siden, fordi håndskriftgjenkjenning finner opp feil barnet aldri har gjort, og en staveapp som hallusinerer en feil er verre enn ingen app. Personvern var aldri den eneste grunnen til å si nei der. Men å kunne prøve det helt på enheten, uten noen opplasting, er nytt.
  • LanguageModel-protokollen lar hvilken som helst modell bære en økt. Appen hadde allerede den formen: én luke avgjør under kjøring om rammeverket finnes på dette systemet, og derfor betjener én binærfil både macOS 15 uten Apple Intelligence og macOS 26 med. Den omveien tilhører nå operativsystemet i stedet for meg.
  • DynamicProfile lar én økt bytte instruksjoner og verktøy midt i samtalen. Å skrive et diktat og å rette et er to forskjellige oppgaver i denne appen, og i dag to forskjellige økter.

Apples gratis skymodell, slått av som standard

Den samme versjonen gjør det svært lett å forlate enheten.

PrivateCloudComputeLanguageModel gir et kontekstvindu på 32 000 tokens og en innstilling for resonnement, uten API-nøkkel, uten konto og uten skyregning for små utviklere under en grense på to millioner førstegangsnedlastinger. Anthropic og Google publiserer Swift-pakker som kobles til den samme økttypen. Å bytte om denne appen er omtrent én linje, og teksten ville kommet tilbake lengre, bedre bygget og langt oftere godkjent allerede ved første forsøk.

Det finnes et reelt argument for å ta imot, og det er ikke det jeg ventet meg i starten. Modellen på enheten skriver et godt diktat til et barn på ni. Den blir tynn når den som spør er en voksen som lærer fransk og vil ha en lengre tekst med leddsetninger og bredere ordforråd, eller en forelder som vil ha noe mer ambisiøst enn nivåtabellen foreslår. De leserne finnes, de bruker allerede appen, og den minste modellen på telefonen skriver ikke egentlig for dem.

I iOS 27 vil appen derfor tilby det som en innstilling, og den innstillingen leveres avslått. Installer appen, ikke rør noe, og løftet den gir i dag holder fortsatt: ingenting forlater enheten, og flymodus beviser det på fire sekunder.

Det som i det hele tatt gjør alternativet mulig å tilby, er nettopp arbeidet lenger oppe. Selv med bryteren på krysser en rå kalendertittel fortsatt aldri nettverket. Hvitelisten har for lengst redusert den til en kanonisk nominalfrase, så det som reiser er « la sortie piscine » og et fornavn, aldri « RDV Dr Meunier, résultats ». Filteret ble bygget for å beskytte et barn mot modellen. Det viser seg å beskytte familien mot nettverket også.

Personvernskjermen vokser med én setning, og det er den delen jeg vil få riktig. Én linje som sier at ingenting forlater enheten, blir til to: ingenting forlater enheten, med mindre du slår på rikere tekster, og her står nøyaktig hva som går ut da. Apples private sky er et godt løfte og jeg tror på det. Det er fortsatt et løfte, og et løfte hører hjemme bak en bryter en forelder bevisst har slått på, ikke i en standardinnstilling de aldri har lest.

Enheten forblir standard også av en mindre glamorøs grunn. Et diktat på toget, i bilen, i et leid hus med dårlig wifi, er nøyaktig det øyeblikket en familie griper etter denne appen. Uansett hva innstillingen sier, må det fortsette å virke helt uten nettverk, så motoren på enheten går ingen steder.

Hvis du trenger dette i din egen app

Hvis du ser på en app der dataene ikke kan forlate enheten, og noen har fortalt deg at det utelukker AI, så er det rådet ett år gammelt. Helse, utdanning, HR, juss, alt som involverer barn, alt der en kundekontrakt navngir landet dataene må ligge i: veien over enheten finnes, og den virker nå.

Forbeholdene, som du heller bør høre fra meg enn oppdage i måned to:

  • Modellen på enheten er liten. Den skriver en god kort tekst. Den resonnerer seg ikke gjennom et langt dokument. Tilpass funksjonen til modellen i stedet for omvendt.
  • Du kommer til å skrive et valideringslag. Behandle modellen som en rask skribent uten dømmekraft, og legg deterministisk kode rundt den. Det er i den koden produktet faktisk bor.
  • Du trenger en reserve for enheten som ikke har Apple Intelligence i det hele tatt, og den må være usynlig. Her står et håndskrevet bibliotek bak modellen, og et barn kan ikke si hvilken av de to som skrev dagens tekst.
  • Enhet og sky er ikke et valg mellom to produkter. Legg filtreringen foran modellen i stedet for inni den, så kan du tilby skyen som en innstilling senere uten å skrive om et eneste ord av personvernskjermen din.
  • Ingenting av dette er webteknologi. Det er EventKit, et personvernmanifest, styrt generering og plattformoppførsel som bare viser seg på ekte maskinvare, én grunn til at native slår en cross-platform-wrapper når den vanskelige delen er operativsystemet.

Det hele, kalenderfilteret inkludert, tok dager og ikke måneder. Mesteparten av tiden gikk til valideringskjeden og feilveiene, ikke til ledeteksten.

Trenger du en app som ikke kan sende noe ut?

Native iOS og Android, bygget rundt AI på enheten, EventKit og plattform-API-ene en webview ikke når. En fungerende app på din egen enhet innen dagen er omme, fra 500 € eks. mva.

Snakk om prosjektet mitt