Ga naar hoofdinhoud
← Terug naar blog

Apple fm als lokale inferentiestap: een engineering-analyse

AI

These: een stochastische functie met een OS-versienummer

fm is geen product maar een interface op een niet-stationaire, probabilistische functie f(x; θ_OS), waarbij θ wordt bepaald door de macOS-build en niet door jou. Wie dat serieus neemt, ontwerpt het model als één begrensde stap in een verder deterministisch systeem: selectie vooraf, contractvalidatie achteraf, en een acceptatiebeslissing die buiten het model ligt.

Apple levert sinds macOS 27 een CLI met zeven commando's (available, chat, count-tokens, license, respond, schema, serve) bovenop het Foundation Models-framework. De interessante vraag is niet of dat werkt, maar welke garanties elke laag geeft en welke niet. Dit stuk ontleedt die garanties langs vijf assen: interfacecontracten, constrained decoding, contextbudget, protocolcompatibiliteit en evaluatie onder modeldrift.

De kernclaim: de waarde van een on-device model van ~3B parameters wordt niet bepaald door modelkwaliteit, maar door de kwaliteit van de taakdecompositie en de selectieve-predictielaag eromheen. Een klein model met een goede afwijsregel verslaat een groot model zonder afwijsregel op elke metriek die er operationeel toe doet.

Drie lagen, drie contracten

Wie model, framework en CLI door elkaar haalt, test het verkeerde contract. Elke laag heeft een eigen capability-oppervlak, en die oppervlakken lopen per build uiteen.

LaagContractWat het niet belooft
Model (AFM 3, on-device)Een conditionele tokenverdeling p(y | x)Stabiliteit over OS-versies; kalibratie; feitelijkheid
Framework (Swift/Python)Sessies, guided generation, tool calling, transcriptenGelijke features in elke frontend
CLI fmZeven tot negen subcommando's, stdin/stdout, lokale HTTPEen stabiel versiebaar artefact (fm --version ontbreekt)

Het bronartikel noemt zeven commando's en alleen het system-model. Apples eigen WWDC26-sessie toont daarnaast een Private Cloud Compute-route, en een onafhankelijke praktijktest beschrijft een fm models-commando dat system expliciet als AFM 3 Core Advanced labelt, plus --image en een OCR-tool (WWDC26 sessie 334, StarryHope). Dat is precies het punt: de CLI is geen stabiele specificatie maar een momentopname van een bewegend oppervlak.

De engineering-consequentie is capability-detectie in plaats van capability-aanname. Parse fm --help en fm <cmd> --help bij startup, hash de uitvoer en log die hash naast de macOS-build. Een pipeline die een subcommando of vlag verwacht die er niet is, moet hard falen met een herkenbare foutcode, niet stil terugvallen op een andere route.

Een tweede subtiliteit: modelalias ≠ modelidentiteit. Of system de 3B-dense Core of de sparse ~20B Core Advanced (met een fractie actieve parameters per token) bedient, bepaalt latency, geheugendruk en kwaliteit. Leg dat vast per run; aannemen is meetfout.

Constrained decoding: syntaxgarantie, geen semantiekgarantie

Guided generation garandeert taalvorm, niet waarheid. Formeel maskeert de decoder bij elke stap t alle tokens die geen geldige voortzetting zijn binnen de grammatica G die uit het schema volgt:

$$p_G(y_t \mid y_{<t}, x) = \frac{p(y_t \mid y_{<t}, x),\mathbb{1}[y_{\le t} \in \mathrm{Prefix}(G)]}{\sum_{v} p(v \mid y_{<t}, x),\mathbb{1}[(y_{<t}, v) \in \mathrm{Prefix}(G)]}$$

Daaruit volgen drie eigenschappen die in de praktijk worden onderschat.

1. Parse-zekerheid is 1, semantische correctheid is ongewijzigd of lager. Het masker verwijdert ongeldige vormen, maar herverdeelt de kansmassa lokaal en gretig. De resulterende sequentieverdeling is niet de oorspronkelijke verdeling geconditioneerd op G; dat verschil is in de literatuur over grammar-constrained decoding aangetoond als systematische distributievervorming.

2. Velden worden ingevuld omdat ze moeten bestaan. Een verplicht string-veld oorzaak dwingt het model iets te genereren. Het lege-string-idioom uit de bron werkt alleen als het model die optie in die positie hoge kans geeft. Robuuster is een expliciete somtype-codering: oorzaak: {status: "vastgesteld" | "vermoed" | "onbekend", tekst?: string}. Dan wordt epistemische status een enum die het masker afdwingt, niet een conventie die het model moet onthouden.

3. Veldvolgorde is chain-of-thought. Autoregressief geldt: wat eerst gegenereerd wordt, conditioneert wat volgt. Zet broncitaat vóór oorzaak en de oorzaak wordt geconditioneerd op het citaat; omgekeerd wordt het citaat gezocht bij een al gekozen oorzaak (post-hoc rationalisatie). Het Apple-specifieke x-order in schema's is dus geen formaliteit maar een causale ontwerpkeuze.

De verificatielaag moet dit spiegelen. Structuurvalidatie is triviaal (gegarandeerd). Grounding-validatie is goedkoop: zoek broncitaat letterlijk of na normalisatie terug in de bron. Entailment-validatie (ondersteunt het citaat de claim?) is de dure stap en vraagt een aparte NLI-check, een regelset of een mens. Die drie niet scheiden is de meest voorkomende fout in schema-gedreven extractie.

Context als schaars goed

Met 4K tot 8K tokens is context geen randvoorwaarde maar de dominante ontwerpvariabele. De begrotingsregel uit de bron klopt, maar mist dat het schema zelf tokens kost en dat Nederlandse tekst bij een Engels-georiënteerde tokenizer typisch 20 tot 40 procent meer tokens per woord vraagt (te verifiëren met count-tokens, niet aan te nemen):

$$T_{\mathrm{instr}} + T_{\mathrm{bron}} + T_{\mathrm{hist}} + T_{\mathrm{schema}} + T_{\mathrm{tools}} + T_{\mathrm{out}}^{\max} \le C_{\mathrm{model}}$$

Bij documenten die niet passen is decompositie verplicht, en elke decompositie heeft een eigen foutmodel:

  • Map-reduce samenvatten verliest cross-chunk relaties (een voorwaarde in sectie 2 die een bedrag in sectie 7 kwalificeert). Het verlies is niet-monotoon: meer chunks betekent kleinere lokale fout en grotere integratiefout.
  • Map-extract-merge naar gestructureerde tussenresultaten is beter controleerbaar, omdat de merge deterministisch kan (dedupliceren op sleutel, conflicten expliciet markeren). Dit is voor bedragen, datums en verplichtingen de enige verdedigbare route.
  • Retrieval-dan-genereren introduceert een tweede foutbron. Ontbind de eindfout: P(fout) = P(niet opgehaald) + P(opgehaald) × P(misgelezen | opgehaald). Alleen de tweede term is toe te schrijven aan fm; de eerste aan je index. Zonder die ontbinding optimaliseer je het verkeerde component.

Een klein-contextmodel heeft hier een onderschat voordeel: het dwingt tot expliciete provenance. Elk tussenresultaat draagt een bron-ID en offset, waardoor data lineage vanzelf ontstaat. Voor judiciële of andere overheidsdata is dat geen nicety maar een verantwoordingsvereiste.

fm serve: protocolcompatibel is niet gedragscompatibel

Een Chat Completions-endpoint dat max_tokens negeert, geen tool_calls teruggeeft en niet authenticeert (zoals de bron rapporteert voor FoundationModels 2.0.68) is syntactisch compatibel en semantisch een ander systeem. Agent-frameworks leunen precies op die drie: tokenbegrenzing voor kostenbeheersing, gestructureerde tool calls voor de controlelus, en authenticatie voor scheiding van tenants.

Behandel fm serve daarom als een adapter waarvoor je een conformance-suite schrijft, niet als drop-in. Minimaal: streaming-semantiek (SSE-chunks, finish_reason), annulering (stopt de serverberekening als de client afbreekt?), concurrency (serialiseert de server of interleaved hij sessies?), foutcodes bij contextoverschrijding en weigeringen.

Het dreigingsmodel van een ongeauthenticeerd loopback-endpoint is concreet:

  • Lokale privilege-grens vervalt. Elk proces onder elke gebruiker kan het model aanroepen; op een gedeelde of beheerde Mac is dat een laterale kanaal.
  • Browser-gebaseerde aanvallen. Een webpagina kan via DNS-rebinding of een te ruime CORS-configuratie 127.0.0.1:1976 bereiken. Controleer Origin-afhandeling en CORS-headers; dit is dezelfde klasse kwetsbaarheden die eerder lokale Ollama- en ontwikkelservers trof.
  • Resource-exhaustion. Zonder max_tokens en zonder rate limiting is één lus genoeg om de Neural Engine en het geheugen te bezetten.
  • Indirecte prompt-injectie blijft bestaan ongeacht netwerkgrens: het model leest bronmateriaal dat instructies kan bevatten.

De mitigatie hoort buiten fm: een reverse proxy op een Unix-socket of loopback met mTLS of een bearer-token, Origin-allowlist, harde time-outs en een tokenlimiet die de proxy afdwingt door de stream af te kappen. In BIO2-termen is dit gewoon toegangsbeveiliging en logging op een interne dienst; het feit dat de dienst op een laptop draait verandert de norm niet.

Het besturingssysteem als modelafhankelijkheid

Bij fm pin je geen gewichten; je erft ze via een OS-update die je beheerorganisatie om securityredenen juist snel wil uitrollen. Daarmee botsen twee legitieme doelen: patchsnelheid (BIO2, NIS2) en reproduceerbaarheid van modelgedrag.

Greedy decoding geeft determinisme alleen binnen dezelfde gewichten, dezelfde kernels en dezelfde sessietoestand. Over builds heen gelden geen garanties; zelfs floating-point-verschillen in een herziene Metal-kernel kunnen bij een argmax-gelijkstand een ander token kiezen, waarna de hele continuatie divergeert.

De passende discipline komt uit MLOps, niet uit klassiek testen:

  1. Gouden set + regressiegate. Een vaste, gelabelde set die bij elke macOS-build draait vóór uitrol naar productiewerkplekken. Gate op taakmetrieken met een vooraf vastgelegde tolerantie, niet op exacte stringgelijkheid.
  2. Gedragsfingerprint. Bewaar per build de uitvoer op een kleine canary-set met greedy decoding. Een gewijzigde fingerprint is het signaal dat de modelversie veranderde, ook als Apple dat niet vermeldt.
  3. Gefaseerde uitrol in MDM. Een pilotring met de nieuwe build en de regressiesuite, daarna pas de rest. Dat is gewoon change management (COBIT BAI06), toegepast op een component die zich voordoet als OS-patch.
  4. Adapters zijn geen uitweg. De bron constateert terecht dat de adaptertoolkit 26.0.0 niet compatibel is met macOS 27. Een eigen LoRA op een systeemmodel is per definitie gekoppeld aan één gewichtsversie en dus technische schuld bij elke update.

Voor een publieke organisatie volgt daaruit een architectuurprincipe in TOGAF-zin: modelgedrag dat juridisch of bestuurlijk relevant is, mag niet afhangen van een component waarvan de versie niet door de organisatie wordt bepaald. fm past dan alleen voor ondersteunende taken met menselijke eindcontrole.

Evaluatie: selectieve predictie in plaats van accuracy

De juiste vraag is niet hoe vaak het model gelijk heeft, maar hoeveel werk het met een afgesproken foutkans kan afhandelen. Dat is het risk-coverage-kader uit selective prediction: een acceptatiefunctie g(x, ŷ) ∈ {0, 1} bepaalt welke uitkomsten automatisch doorgaan.

$$\mathrm{coverage}(g) = \mathbb{E}[g], \qquad \mathrm{risk}(g) = \frac{\mathbb{E}[,\ell(\hat y, y), g,]}{\mathbb{E}[g]}$$

Je kiest g zo dat risk onder een bestuurlijk vastgestelde grens blijft, en maximaliseert daarbinnen coverage. De effectieve-doorvoermetriek uit de bron is daar een operationele projectie van, mits de teller echte correctheid is en niet validator-acceptatie.

Vier methodologische punten die in pilots stelselmatig misgaan:

  • Validator-bias. Als je validator ook je evaluator is, meet je zelfconsistentie. Houd een onafhankelijk gelabelde set aan en rapporteer het foutpercentage binnen de geaccepteerde fractie apart.
  • Zelfgerapporteerde confidence is ongekalibreerd. Een confidence-veld dat door het model wordt gegenereerd valt onder hetzelfde constrained-decoding-masker en meet niets tot je een betrouwbaarheidsdiagram hebt gemaakt en de expected calibration error kent. Betere signalen: zelfconsistentie over k samples met temperatuur > 0, of een mislukte grounding-check.
  • Steekproefomvang. Bij 200 testgevallen en 95 procent geobserveerde accuracy is het Wilson-interval ruwweg 91 tot 97 procent. Wie tolerantie van één procentpunt tussen builds wil detecteren, heeft een orde grotere set nodig. Vergelijk builds gepaard (McNemar) op dezelfde items, niet op twee losse percentages.
  • Stratificatie. Rapporteer per moeilijkheidsklasse: ontkenning, ontbrekende informatie, tegenstrijdigheid, codeswitching NL/EN en ingebedde instructies. Een gemiddelde van 92 procent verbergt makkelijk 60 procent op ontkenningen, en juist daar zitten in juridische tekst de dure fouten.

Voor AI-Act-conforme documentatie (ook buiten hoog-risicotoepassingen nuttig als good practice) leg je per run vast: build, modelalias en -variant, prompt- en schemahash, decodinginstellingen, dataset-versie en de gekozen g met haar risk-coverage-punt. Bias-analyse hoort in diezelfde stratificatie: meet de foutverdeling over taalvariëteit en documenttype, niet alleen het gemiddelde.

Positionering en soevereiniteit

fm ruilt controle in voor gemak: geen gewichtenbeheer, maar ook geen gewichtenbezit. Voor een soevereiniteitsanalyse is dat de kern, niet de inferentielocatie.

RouteGewichten in eigen beheerVersie door jou bepaaldUitvoeringslocatie aantoonbaarFinetuning
fm / framework, systemNeeNee (OS-gekoppeld)Ja, on-deviceNee (adapters niet voor macOS 27)
fm, Private Cloud ComputeNeeNeeApple-infrastructuurNee
MLX-LMJaJaJaJa (LoRA, kwantisatie)
OllamaJa, lokaal; nee voor cloudmodellenJaAlleen bij uitsluitend lokale modellenBeperkt

Drie consequenties voor de Nederlandse publieke sector:

  • CLOUD Act. De PCC-route verwerkt data op infrastructuur van een Amerikaanse onderneming. Apple's attestatie- en no-retention-architectuur is technisch sterk, maar neemt de juridische toegangsvraag onder de CLOUD Act niet weg. Voor vertrouwelijke of persoonsgegevens is een expliciete DPIA en soevereiniteitsafweging nodig; schakel PCC beleidsmatig uit (MDM) tenzij die afweging positief is. Hetzelfde geldt voor Ollama-cloudmodellen achter een lokaal endpoint.
  • On-device is niet hetzelfde als soeverein. De gegevensstroom blijft lokaal, maar het model, de licentievoorwaarden en de updatecadans liggen bij een niet-Europese leverancier. Dat is acceptabel voor productiviteitstaken; voor kernprocessen pleit het voor open gewichten via MLX of een Europese inferentieomgeving, waar je het hele stack-niveau (gewichten, runtime, logging) zelf in de architectuur-repository kunt vastleggen.
  • AI Act-classificatie volgt het gebruik, niet het gereedschap. Een lokaal model dat juridische stukken samenvat om rechterlijke beslissingen voor te bereiden valt onder bijlage III (rechtsbedeling) en dus onder hoog-risico-eisen, ongeacht of het op een MacBook draait. Daarmee worden versie-pinning, logging en menselijk toezicht verplichtingen, en fm kan die versie-pinning structureel niet leveren.

Praktisch advies: fm voor persoonlijke productiviteit en prototyping op niet-gevoelige of gesynthetiseerde data; MLX met open gewichten voor alles wat herhaalbaar, auditeerbaar of beleidsrelevant moet zijn. Een organisatiebrede uitrol (meer dan 1000 werkplekken) of een investering boven €500K in een op fm gebaseerde voorziening vraagt aanvullende validatie via de architectuurraad en de CISO.

Kritische kanttekeningen bij het bronartikel

Het bronartikel is zorgvuldig in toon en scheidt terecht model, framework en CLI. Op zes punten schiet het tekort of spreekt het zichzelf tegen.

  1. Interface-claim is te stellig. "Zeven commando's, alleen system" botst met Apple's eigen sessie (PCC-route) en met een praktijktest die fm models, --image en --tool beschrijft. Mogelijk verschillen builds; dan had het artikel zijn eigen advies moeten volgen en de build vermelden waarop de helptekst is gebaseerd.
  2. Modelidentiteit. De stelling dat system de variant niet identificeert, klopt niet als fm models haar wel toont (AFM 3 Core Advanced). Het principe (meet, neem niet aan) is juist; de feitelijke onderbouwing is achterhaald.
  3. Afhankelijkheid van één secundaire bron. De serve-bevindingen (geen auth, genegeerde max_tokens, ontbrekende tool_calls) en het x-order-detail komen uit één community-repository. Dat is waardevol, maar ongerepliceerd en versiegebonden; een blog op dit niveau hoort dat als hypothese te markeren en zelf te herhalen.
  4. Het lege-string-idioom voor onbekend is fragiel onder constrained decoding (zie boven). Een expliciete enum voor epistemische status is robuuster en direct evalueerbaar.
  5. Geen dreigingsmodel voor serve. Het artikel noemt het ontbreken van authenticatie, maar mist DNS-rebinding en CORS, de feitelijke aanvalsroute op lokale LLM-servers.
  6. Evaluatie zonder statistiek. 100 tot 300 voorbeelden worden terecht als startomvang gepresenteerd, maar zonder betrouwbaarheidsintervallen of gepaarde vergelijking kan een pilot geen regressie tussen builds aantonen. Het risk-coverage-kader ontbreekt, terwijl de effectieve-doorvoermetriek er impliciet op leunt.

Daarnaast valt op wat niet wordt besproken: beeldinvoer, tool calling via de CLI en de AI Act-implicaties van het gebruik. Voor een publiek-sectorlezer is dat laatste geen detail.

Conclusie: zeven ontwerpprincipes

fm is een uitstekende lokale taalprimitive en een slechte systeemgrens. De engineering-waarde zit in wat je eromheen bouwt.

  1. Detecteer capabilities per build; neem ze nooit aan.
  2. Codeer epistemische status als enum in het schema en orden velden causaal (bron vóór conclusie).
  3. Scheid structuur-, grounding- en entailment-validatie; alleen de eerste is gratis.
  4. Begroot context inclusief schema en antwoordreserve; decomponeer naar gestructureerde tussenresultaten met provenance.
  5. Behandel serve als adapter met conformance-suite en zet authenticatie, Origin-controle en tokenlimieten in een proxy.
  6. Gate elke macOS-build op een gestratificeerde gouden set met gepaarde statistiek.
  7. Kies de route op de vraag wie de gewichten en de versie beheert, niet alleen op waar de inferentie plaatsvindt.

Wie die discipline toepast, krijgt van een model van enkele miljarden parameters meer betrouwbaar werk per minuut dan van een groter model zonder afwijsregel. Dat is de eigenlijke les van on-device AI.

Bronnen

  • Apple WWDC26 sessie 334, Meet the fm command line tool
  • StarryHope, How to use the Mac's built-in AI model with Apple's fm command
  • Blake Crosley, Foundation Models from Python: the fm CLI
  • Bronartikel "Apple Foundation Models met fm voor lokale AI op de Mac" en de daarin geciteerde documentatie (o.a. llostinthesauce/fm-guide, apple/python-apple-fm-sdk)

Niet zelf uitgevoerd op macOS 27; claims over serve-gedrag en schema-details zijn ontleend aan derden en versiegebonden.

AI & Security Intelligence

Wekelijkse nieuwsbrief met AI updates, security alerts en compliance inzichten, direct in uw inbox.

Security & AI Operating Model

Advisory met executiekracht

Van BIO2 en NIS2 tot EU AI Act, embedded in uw operating model, niet als extern project. Maandelijks opzegbaar, met assessments als bewijsvoering.