fm in de praktijk: use cases voor de publieke sector
De kern
De waarde van een lokaal model als fm zit niet in het antwoord dat het geeft, maar in de structuur die het afdwingt: de afwijsregel, de epistemische status en de lokale verwerking zelf. Dat is de rode draad onder zeven use cases voor wie in de publieke sector met vertrouwelijke documenten werkt. Elke use case krijgt hier het bijbehorende fm-commando, zodat je het direct kunt uitproberen.
De twee rode draden
In de engineering-analyse van fm staat waarom een model van enkele miljarden parameters op een MacBook operationeel interessanter kan zijn dan een veel groter model in de cloud. Het antwoord is niet modelkwaliteit, maar taakdecompositie en een selectieve-predictielaag eromheen. Twee gevolgen bepalen alles wat hieronder volgt.
Ten eerste: de afwijsregel en de epistemische status zijn het product, niet het gegenereerde antwoord. Een klein model dat betrouwbaar zegt "dit is niet voor jou" of "dit weet ik niet" wint het van een groot model dat alles met evenveel zelfvertrouwen samenvat. Ten tweede: lokaal is een producteigenschap op zich. De data blijft op de machine, en voor wie met vertrouwelijke of persoonsgegevens werkt, is die grens de netwerkgrens.
Eerst: aan de slag
De voorbeelden hieronder zijn getest op FoundationModels 2.0.68 (macOS 27.0). De syntax verschilt per build, dus parse fm --help vóór je op een vlag vertrouwt. Dat is niet voorzichtigheid, maar principe één uit de analyse: detecteer capabilities, neem ze nooit aan.
# 1. Accepteer de voorwaarden (eenmalig, machine-breed, door een beheerder)
sudo fm license
fm license --status
# 2. Je eerste lokale antwoord
fm respond 'Vat in een zin samen wat NIS2 betekent voor een gemeente.'
# 3. Capability-detectie, geen aanname: hash de help-output en log hem naast je build
fm --help | shasum -a 256
fm respond --help | shasum -a 256
sw_vers -productVersion
# 4. Bevestig welk model je draait
fm available --model system
fm heeft geen --version. Dat is geen nalatigheid; het is de reden dat stap drie bestaat. Wie de hash van de help-output naast de macOS-build logt, weet wélk model hij vandaag draait, ook als Apple dat niet vermeldt.
1. De weigeraar als product
Voor een beveiligingsverantwoordelijke is de ochtendstroom aan CVE- en NCSC-advisories een filterprobleem. fm kan die lokaal classificeren met constrained decoding die een enum afdwingt: relevant voor jouw scope, niet relevant, of onzeker. De besparing zit in wat wegvalt: zestig procent "niet relevant" gaat niet door naar een mens, veertig procent "onzeker" wel. De afwijsregel doet het werk; de samenvatting is bijzaak.
Sla dit schema op als triage.json:
{
"type": "object",
"title": "Triage",
"additionalProperties": false,
"x-order": ["status", "reden"],
"properties": {
"status": {"type": "string", "enum": ["relevant", "niet_relevant", "onzeker"]},
"reden": {"type": "string"}
},
"required": ["status", "reden"]
}
De enum dwingt de afwijsoptie af: het model kán alleen één van de drie statussen uitsturen, nooit een uitweiding. Vervolgens classificeer je een advies lokaal:
fm respond --schema triage.json \
-i 'Classificeer dit security-advies voor onze scope. Wees conservatief: bij twijfel kies onzeker.' \
'CVE-2026-12345 treft een component die wij niet gebruiken.'
Dezelfde truc werkt als eerste verdedigingslaag tegen prompt-injectie: screen een bijlage lokaal op instructie-achtige taal vóór iemand hem opent. fm hoeft de tekst niet te begrijpen; het hoeft alleen te vlaggen dat er mogelijk een ingebedde instructie staat.
2. Epistemische status als gap-analyse
Compliance-werk draait om weten wat je niet weet. Daar schittert een schema dat elk veld van een status voorziet: vastgesteld, vermoed of onbekend. Sla dit op als verplichting.json:
{
"type": "object",
"title": "Verplichting",
"additionalProperties": false,
"x-order": ["broncitaat", "onderwerp", "status", "tekst"],
"properties": {
"broncitaat": {"type": "string"},
"onderwerp": {"type": "string"},
"status": {"type": "string", "enum": ["vastgesteld", "vermoed", "onbekend"]},
"tekst": {"type": "string"}
},
"required": ["broncitaat", "onderwerp", "status"]
}
Let op de veldvolgorde: broncitaat staat vóór onderwerp en status. Dat is geen cosmetica. Autoregressief conditioneert wat eerst wordt gegenereerd wat volgt; het citaat vóór de interpretatie zetten dwingt het model om eerst te citeren en dán te duiden, in plaats van een oorzaak te verzinnen en er een citaat bij te zoeken.
fm respond --schema verplichting.json \
-i 'Geef het broncitaat letterlijk weer. Is de oorzaak niet vast te stellen, kies onbekend en laat tekst leeg.' \
'Na onderzoek kan geen oorzaak voor de vertraging worden vastgesteld.'
De winst is dat "onbekend" nu zichtbaar wordt: het is de gap die je anders pas in de DPIA-sessie of de audit ontdekt. fm die "onbekend" zegt, is geen falen; het is een vooraf gedane gap-analyse. Hetzelfde patroon werkt voor de BIO2-baseline (extraheer de genoemde beveiligingsmaatregelen en map ze op de relevante controles; waar ze ontbreken, staat onbekend) en voor de DPIA-voorbereider (verwerkingen, grondslagen en ontvangers, elk met broncitaat).
3. Lokaal is het product
Voor alles wat je nooit in een cloud-editor zou plakken, is de on-device aard van fm de hele reden van bestaan. Een incidentbeschrijving, een concept-advies aan het college, een personeelszaak: herschrijven gebeurt lokaal en de passage verlaat de machine niet.
Een vertrouwelijk overleg is hetzelfde verhaal met een schema. Sla dit op als actiepunt.json:
{
"type": "object",
"title": "Actiepunt",
"additionalProperties": false,
"x-order": ["actie", "eigenaar", "deadline", "status"],
"properties": {
"actie": {"type": "string"},
"eigenaar": {"type": "string"},
"deadline": {"type": "string"},
"status": {"type": "string", "enum": ["vastgesteld", "onbekend"]}
},
"required": ["actie", "eigenaar", "status"]
}
Het transcript lees je vanaf stdin, zodat het nooit als argument in de shell-geschiedenis belandt:
cat overleg.txt | fm respond --schema actiepunt.json \
-i 'Vermeld de eigenaar alleen als die in de tekst staat. Ontbreekt de eigenaar, kies onbekend.'
Waar de eigenaar ontbreekt, staat onbekend, en dat is precies wat je de voorzitter teruggeeft. Geen transcript naar een derde partij.
4. De contradiction-hunter en de canary
Twee taken waar fm uitblinkt omdat het juist geen samenvatting hoeft te maken. De versie-drift-jager vergelijkt twee versies van een beleidsdocument en vlagt waar versie twee iets stelt dat versie één anders stelde:
fm respond \
-i 'Citeer letterlijk wat versie 1 en versie 2 over dit onderwerp stellen. Vlag elke tegenstrijdigheid tussen beide.' \
'Versie 1: de bijdrage bedraagt 45.000 euro. Versie 2: de totale bijdrage bedraagt 54.000 euro.'
Je wilt de tegenstrijdigheden, niet de samenvatting. Dit is een bronverankeringstaak: fm citeert beide passages letterlijk en jij oordeelt. De prompt-injectie-canary is een lokaal document met een ingebedde instructie dat je permanent laat draaien tegen elk systeem dat documenten leest; volgt een ander systeem de instructie op, dan weet je het meteen.
5. fm als governance-les
Wie wil scripten, kan fm draaien als een lokaal OpenAI-compatibel endpoint. Geen sleutel, geen kosten per token, en alles blijft op de machine:
fm serve
from openai import OpenAI
client = OpenAI(base_url="http://127.0.0.1:1976/v1", api_key="ongebruikt")
antwoord = client.chat.completions.create(
model="system",
messages=[{"role": "user", "content": "Noem twee kleuren."}],
temperature=0.0,
)
print(antwoord.choices[0].message.content)
Let op twee dingen die een echte leverancier je anders zou vertellen. fm serve heeft geen authenticatie: houd hem op 127.0.0.1 of een Unix-socket, en laat nooit een browser- of netwerkroute ernaartoe wijzen. En max_tokens wordt geaccepteerd maar genegeerd, net als tool-calling op deze versie. Protocolcompatibel is niet gedragscompatibel; behandel het endpoint daarom als een adapter met een eigen conformance-check, niet als drop-in.
Die twee details zijn zelf de governance-les. fm heeft geen versiecommando, zijn endpoint negeert parameters die een agent-framework veronderstelt, en zijn schema vereist een ongedocumenteerde x-order-sleutel. Wie dat alle drie heeft vastgesteld, heeft de capability-detectie uit de aan-de-slag-sectie in de praktijk gebracht: aannemen is meetfout, en meten is wat je in een leveranciersgesprek laat zien.
De grens die alles draagt
Elke use case hierboven respecteert dezelfde randvoorwaarde. fm doet alleen de begrensde stap: selectie vooraf, contractvalidatie achteraf, en een acceptatiebeslissing die buiten het model ligt. Menselijke eindcontrole is overal het slotstuk. Dat is geen beperking van de toepassingen; het is de reden dat ze wél mogen.
Wie die discipline toepast, krijgt van een klein lokaal model meer betrouwbaar werk per minuut dan van een groter model zonder afwijsregel. De use cases hierboven zijn daar de praktische vorm van.
Bronnen
- Apple fm als lokale inferentiestap: een engineering-analyse, DjimIT, 2026
- fm-guide, praktische handleiding met geteste CLI-referentie, FoundationModels 2.0.68
- Build AI-powered scripts with the fm CLI and Python SDK, Apple WWDC26 sessie 334
- EU AI Act, EUR-Lex, verordening 2024/1689
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.