Lokaler LLM-Betrieb konkret
In Was ist ein LLM? habe ich lokalen Betrieb nur als eine von zwei Betriebsformen erwähnt. Dieser Beitrag holt das nach und beantwortet die Fragen, die in der Praxis zuerst kommen: Welche Hardware brauche ich, wie schnell wird das, und was gewinne ich damit tatsächlich?
Die Antworten sind erfreulich rechenbar. Man braucht dafür kein Fachwissen über neuronale Netze, sondern zwei Zahlen: die Parameterzahl des Modells und die Speicherbandbreite der Maschine. Wer lieber tippt als rechnet, findet weiter unten eine vollständige Installation auf einem Mac, an der sich alle Formeln überprüfen lassen.
Was „lokal“ konkret heißt
Gemeint ist: Das Modell läuft auf einer Maschine, über die man selbst die Kontrolle hat. Das kann der eigene Arbeitsrechner sein, ein Server im Haus oder eine gemietete virtuelle Maschine. Entscheidend ist nicht die Entfernung, sondern dass keine Anfrage an einen fremden Dienst geht, dessen Nutzungsbedingungen und Protokollierung man nicht selbst bestimmt.
Technisch ist der Aufbau schlicht. Ein Inferenz-Server lädt die Modellgewichte einmal in den Speicher und nimmt danach Anfragen über eine lokale Schnittstelle entgegen, meist über HTTP. Die eigene Anwendung spricht also nicht mit einem Anbieter im Netz, sondern mit einem Prozess auf localhost. An der Anwendungsarchitektur ändert sich dadurch wenig, an der Betriebsverantwortung viel.
Zwei Werkzeuge
llama.cpp ist eine in C und C++ geschriebene Inferenz-Engine, also das Programm, das die eigentliche Rechnung ausführt. Sie lädt Modelle im Dateiformat GGUF, das die Gewichte zusammen mit den nötigen Metadaten in einer einzigen Datei ablegt. llama.cpp läuft auf CPU (dem Hauptprozessor) und GPU (dem Grafikprozessor) und kann beides mischen: Ein Teil der Netzschichten liegt im Grafikspeicher, der Rest im Arbeitsspeicher. Das nennt sich Offloading und ist der Grund, warum ein Modell auch dann noch startet, wenn die Grafikkarte eigentlich zu klein ist. Schnell ist es dann allerdings nicht mehr, dazu unten mehr.
Ollama setzt auf derselben Grundlage auf und verpackt sie in etwas, das sich wie ein Paketmanager bedient: Modell herunterladen, starten, über eine lokale Programmierschnittstelle (API) ansprechen. Wer schnell etwas ausprobieren oder ein Modell in eine Anwendung einbinden will, ist damit in Minuten arbeitsfähig. Wer jeden Parameter selbst kontrollieren will, greift direkt zu llama.cpp. Für den Fall vieler paralleler Nutzer:innen gibt es weitere Serving-Stacks, die Anfragen bündeln; für den Einstieg und für einzelne Arbeitsplätze sind die beiden genannten die naheliegende Wahl.
Quantisierung: der entscheidende Hebel
Trainiert werden Modelle typischerweise mit 16 Bit pro Gewicht, also 2 Byte. Quantisierung speichert die Gewichte gröber, etwa mit 8 oder 4 Bit. Das ist keine Kompression im üblichen Sinn, sondern ein bewusster Genauigkeitsverlust: Statt vieler feiner Abstufungen bleiben wenige grobe übrig, jeweils blockweise mit einem Skalierungsfaktor versehen.
Der Speichergewinn ist der ganze Punkt. Für ein Modell mit 7 Milliarden Parametern ergibt sich:
In der Praxis liegt die 4-Bit-Variante etwas darüber, weil die Skalierungsfaktoren mitgespeichert werden und einzelne besonders empfindliche Schichten feiner bleiben. Effektiv landet man eher bei 4,8 Bit pro Gewicht:
Das deckt sich mit den Dateigrößen, die man bei fertigen GGUF-Modellen dieser Größenordnung tatsächlich vorfindet, üblicherweise gut 4 GB.
Der Preis ist Qualität. Die verbreitete Erfahrung: 8 Bit ist praktisch nicht vom Original zu unterscheiden, 4 Bit kostet wenig und ist für die meisten Anwendungen der vernünftige Standard, unterhalb von 4 Bit werden die Einbußen schnell spürbar. Diese Faustregel ersetzt keine Messung. Soll das Modell eine konkrete Aufgabe erfüllen, etwa Befundtexte strukturieren, dann gehören beide Varianten auf genau dieser Aufgabe verglichen, nicht auf allgemeinen Benchmarks.
Der Speicherbedarf, durchgerechnet
Die Gewichte sind nur der eine Posten. Der zweite ist der KV-Cache (Key-Value-Cache), in dem das Modell Zwischenergebnisse für jedes bereits verarbeitete Token behält, damit es sie nicht bei jedem neuen Token erneut berechnen muss. Er wächst linear mit der Kontextlänge, und genau das wird regelmäßig übersehen.
Für ein typisches Modell dieser Größe mit 32 Schichten, 8 Key-Value-Köpfen und 128 Werten pro Kopf, gespeichert mit 2 Byte:
Die führende 2 steht dafür, dass sowohl Keys als auch Values gespeichert werden. Bei 4 096 Tokens Kontext sind das rund 0,5 GB, bei 32 768 Tokens bereits etwa 4,3 GB. Die Kontextlänge kostet also am Ende ähnlich viel Speicher wie das Modell selbst.
Zusammen mit einem knappen halben Gigabyte für Puffer und Zwischenergebnisse ergibt sich:
Dasselbe Modell, dieselbe Quantisierung: Allein die achtfache Kontextlänge sprengt das Speicherbudget.
Gegenprobe mit einem größeren Modell: 13 Milliarden Parameter in 4 Bit ergeben GB allein an Gewichten. Auf einer Karte mit 8 GB bleibt für den Kontext nichts mehr übrig, das Modell verlangt also die nächste Ausbaustufe. Genau so grob rechnet man vor dem Hardwarekauf.
Wie schnell wird das?
Beim Erzeugen der Antwort muss für jedes einzelne Token einmal die gesamte Gewichtsmenge durch den Prozessor gelesen werden. Die Ausgabegeschwindigkeit ist deshalb nicht durch Rechenleistung begrenzt, sondern durch Speicherbandbreite. Die obere Schranke lautet:
Auf einer Grafikkarte mit 500 GB/s ergibt das für unser 4,2-GB-Modell rund 119 Tokens pro Sekunde, deutlich schneller als jemand lesen kann. Im Arbeitsspeicher eines gewöhnlichen Rechners stehen eher 50 GB/s effektiv zur Verfügung, also etwa 12 Tokens pro Sekunde. Das ist benutzbar, aber spürbar zäh. Und hier liegt der Haken beim eingangs erwähnten Offloading: Sobald ein Teil der Schichten im langsamen Arbeitsspeicher liegt, bestimmt dieser Teil das Tempo. Halb auf der Grafikkarte ist nicht halb so schnell, sondern fast so langsam wie ganz ohne.
Eine Ausnahme gibt es: Das Einlesen des Prompts läuft parallel über alle Tokens und ist rechen-, nicht bandbreitenbegrenzt. Deshalb ist die Wartezeit bis zum ersten Token oft kurz, auch wenn die Ausgabe danach träge tröpfelt.
Eine Installation zum Nachmachen
So weit die Theorie. Der folgende Durchlauf auf einem Mac mit Apple-Silicon-Prozessor macht daraus etwas Nachvollziehbares und liefert nebenbei die Messwerte, um die obigen Rechnungen zu überprüfen.
Einrichten
Die Installation läuft über Homebrew, den verbreiteten Paketmanager für macOS:
brew install ollama
ollama serve
ollama serve startet den Inferenz-Server, der danach unter http://localhost:11434 lauscht. Wer lieber klickt, lädt stattdessen die App von der Projektseite, die dasselbe im Hintergrund tut. In einem zweiten Terminal holt man ein Modell und startet es:
ollama pull qwen2.5:14b
ollama run qwen2.5:14b
Qwen ist eine offen lizenzierte Modellfamilie, die in mehreren Größen vorliegt. Der Zusatz 14b steht für die Parameterzahl, qwen2.5:7b wäre die kleinere Schwester. Ollama liefert standardmäßig 4-Bit-quantisierte Fassungen aus, also genau den Fall der Rechnung von oben. Was man bekommen hat, zeigt:
ollama show qwen2.5:14b
Die Ausgabe nennt Architektur, Parameterzahl (14,8 Mrd.), Kontextlänge (32 768), Einbettungslänge und Quantisierung (Q4_K_M), außerdem die Lizenz. Bei diesem Modell ist es Apache 2.0. Das lohnt einen Blick, denn die Lizenzen frei verfügbarer Modelle unterscheiden sich erheblich, und für den kommerziellen oder klinischen Einsatz ist das keine Nebensache.
Passt es auf die Maschine?
Auf Apple Silicon teilen sich Hauptprozessor und Grafikprozessor denselben physischen Speicher. Es gibt also keinen getrennten Grafikspeicher, sondern ein gemeinsames Budget, von dem das System dem Grafikteil grob zwei Drittel des verbauten Arbeitsspeichers zugesteht. An der Rechnung ändert das nichts, nur die Obergrenze heißt anders.
Ob es tatsächlich passt, beantwortet der laufende Prozess selbst:
ollama ps
NAME ID SIZE PROCESSOR CONTEXT UNTIL
qwen2.5:14b 7cdf5a0187d5 15 GB 100% GPU 32768 4 minutes from now
Entscheidend ist die Spalte PROCESSOR. 100% GPU heißt, das komplette Modell liegt im schnellen Speicher. Steht dort eine Aufteilung zwischen CPU und GPU, greift das weiter oben beschriebene Offloading, und die Ausgabe wird deutlich zäher. Die Spalte UNTIL verrät nebenbei, dass Ollama ein Modell nach einigen Minuten Untätigkeit wieder aus dem Speicher wirft. Der erste Aufruf danach dauert entsprechend länger, im gemessenen Fall gut 6 Sekunden, weil 9 GB von der Platte gelesen werden müssen.
Die Rechnungen gegen die Wirklichkeit
Jetzt lassen sich alle drei Formeln überprüfen. Erstens die Gewichte: 14,8 Milliarden Parameter zu effektiv 4,8 Bit ergeben
und ollama list weist für das Modell 9,0 GB aus. Zweitens der KV-Cache: ollama show nennt 48 Schichten, 40 Aufmerksamkeitsköpfe und 8 Key-Value-Köpfe bei einer Einbettungslänge von 5 120, also Werte pro Kopf. Damit
und bei den vollen 32 768 Tokens Kontext rund 6,4 GB. Zusammen also 15,3 GB, und exakt 15 GB meldet ollama ps als belegten Speicher. Der Aufschlag von zwei Dritteln gegenüber der reinen Modelldatei ist kein Messfehler, sondern der Preis des großen Kontextfensters.
Drittens die Geschwindigkeit. Der Schalter --verbose hängt an jede Antwort eine Messung an:
ollama run qwen2.5:14b --verbose "Nenne in einem Satz, was Quantisierung bedeutet."
prompt eval rate: 119.90 tokens/s
eval rate: 29.69 tokens/s
Die nominelle Speicherbandbreite dieser Ausbaustufe liegt bei 400 GB/s, geteilt durch die 9,0 GB Modellgröße also rund 44 Tokens pro Sekunde als obere Schranke. Gemessen werden 29,7, das sind etwa zwei Drittel des theoretischen Maximums. Genau in dieser Größenordnung landet man in der Praxis: Die Schranke ist eine Schranke, kein Versprechen, aber sie sagt die richtige Größenordnung voraus. Sichtbar wird im selben Durchlauf auch der Unterschied zwischen Einlesen und Erzeugen, denn der Prompt wurde mit 120 Tokens pro Sekunde verarbeitet, die Antwort mit weniger als einem Viertel davon.
Aus eigenem Code ansprechen
Der Server nimmt Anfragen als JSON entgegen (JavaScript Object Notation, das übliche Austauschformat für Web-Schnittstellen):
curl -s http://localhost:11434/api/chat -d '{
"model": "qwen2.5:14b",
"messages": [{"role": "user", "content": "Antworte nur mit OK."}],
"stream": false
}'
Daneben bietet Ollama unter /v1/chat/completions eine Schnittstelle an, die dem verbreiteten Industriestandard nachgebildet ist. Bestehender Code braucht dadurch oft nur eine andere Basis-URL und läuft dann gegen das lokale Modell statt gegen einen externen Dienst. Genau das macht den Vergleich billig: Man kann eine Anwendung gegen beides laufen lassen und messen, ob das lokale Modell für die konkrete Aufgabe ausreicht.
Zum Aufräumen listet ollama list alle vorhandenen Modelle und ollama rm qwen2.5:14b entfernt eines wieder. Die Dateien liegen unter ~/.ollama/models und sind, wie die Rechnung nahelegt, entsprechend groß.
Datenhoheit ist kein Freibrief
Der eigentliche Grund für lokalen Betrieb ist meist nicht Geschwindigkeit und selten der Preis, sondern die Frage, wo die Daten liegen. In regulierten Umfeldern, im medizinischen Bereich etwa, ist das oft die einzige Frage, die zählt: Patientendaten verlassen das Haus nicht, damit entfällt die gesamte Diskussion über Auftragsverarbeitung und Drittlandtransfer.
Zwei Einschränkungen gehören dazu. Erstens ersetzt lokaler Betrieb keine Zugriffskontrolle, keine Protokollierung und keine Löschkonzepte. Ein Modell auf dem eigenen Server ist ein System wie jedes andere und unterliegt denselben Anforderungen. Zweitens ändert lokaler Betrieb nichts an den inhaltlichen Grenzen: Ein lokal laufendes Modell halluziniert genauso wie ein gehostetes, und die frei verfügbaren Modelle sind den größten gehosteten in der Qualität weiterhin unterlegen. Man tauscht Fähigkeiten gegen Kontrolle, bewusst und mit offenen Augen.
Fazit
Lokaler LLM-Betrieb ist kein Forschungsprojekt, sondern eine Kapazitätsplanung. Parameterzahl mal Bytes pro Parameter ergibt den Speicherbedarf der Gewichte, die Kontextlänge mal Bytes pro Token den des KV-Caches, und Bandbreite geteilt durch Modellgröße die obere Schranke der Ausgabegeschwindigkeit. Alle drei haben sich am laufenden System bestätigt, und mit ihnen lässt sich schon vor dem ersten Download entscheiden, ob ein Vorhaben auf der vorhandenen Hardware Sinn ergibt.
Was danach bleibt, ist die inhaltliche Arbeit: prüfen, ob das gewählte Modell die konkrete Aufgabe gut genug erfüllt, und seine Ausgaben behandeln wie jede andere unsichere Eingabe.