Lokale LLMs auf macOS: Ollama, LM Studio, MLX, llama.cpp
Automatische Übersetzung
Dieser Artikel wurde automatisch aus der englischen Originalversion übersetzt.
Wer lokale Models auf einem Apple-Silicon-Mac betreibt, muss die gesamte Last einplanen und nicht nur ein Model wählen, das sich herunterladen lässt. Apple Silicon kann alltägliche Prompts ohne Remote-API verarbeiten, weil CPU und GPU einen gemeinsamen Unified-Memory-Pool nutzen. Die Model Weights teilen sich diesen Speicher aber mit dem Cache für den Kontext, den Arbeitspuffern der Runtime und macOS selbst.
Wenn Model, Kontext und Speicherreserve zusammenpassen, wählst du das Tool, das zu deiner Arbeitsweise passt: Ollama für einen verwalteten lokalen Dienst, LM Studio zum Erkunden von Models auf dem Desktop, llama.cpp für direkte Kontrolle über die Runtime-Flags oder MLX-LM für Apple-natives Python. Du erfährst, wie du den Speicherbedarf schätzt, wofür jedes Tool gedacht ist, wie du es startest und wie du alle auf demselben Workload vergleichst.
Eine kompakte Entscheidungstabelle findest du in Lokale LLM-Tools auf macOS im Jahr 2026.
Wie viel Speicher ein lokales Model braucht
Vier Begriffe tauchen in diesem Artikel immer wieder auf:
- Quantization speichert Model Weights mit weniger Bits, um Speicher zu sparen. In einem Dateinamen wie
Llama-3.1-8B-Instruct-Q4_K_M.ggufstehtQ4für ein 4-Bit-Schema.Q4_K_Mkommt im Mittel auf knapp unter 5 Bit pro Weight, wenn man die Skalierungsfaktoren und einige Tensoren mit höherer Präzision mitzählt. - GGUF ist das Einzeldatei-Modellformat von llama.cpp und den darauf aufbauenden Tools. MLX-LM lädt stattdessen Models, die für MLX konvertiert wurden. Dasselbe Model gibt es also als getrennte GGUF- und MLX-Downloads.
- KV cache speichert die Attention-Keys und -Values für jeden Token im Kontext. Er wächst mit der Kontextlänge und mit der Zahl paralleler Requests.
- Checkpoint-Familie meint ein Basismodell in einer Größe, etwa Llama 3.1 8B Instruct, unabhängig von Dateiformat oder Quantization.
Das Diagramm addiert Weights und KV cache für Llama 3.1 8B mit Q4_K_M bei 8K und 32K Kontext. Es vergleicht diese Teilsummen mit dem empfohlenen GPU Working Set, das ein M1-Mac mit 16 GB gemeldet hat; Runtime-Arbeitsspeicher und macOS brauchen zusätzlichen Speicher.
Die Größe der quantisierten Weights ist nur der erste Summand:
peak memory ≈ model weights
+ KV cache
+ runtime workspace
+ multimodal components
+ application and OS memory
Kontextlänge, Cache-Datentyp, parallele Requests und Model-Architektur verändern das Ergebnis. Den KV cache steuerst du am direktesten über die Kontextlänge:
KV bytes per token = 2 × layers × KV heads × head dimension × bytes per value
Für Llama 3.1 8B (32 Layer, 8 KV-Heads, Head-Dimension 128) mit einem 16-Bit-Cache sind das 2 × 32 × 8 × 128 × 2 = 131.072 Bytes, also 128 KiB pro Token. Ein Kontext von 8K braucht 1 GiB Cache pro Request, ein Kontext von 32K braucht 4 GiB. Die Q4_K_M-Weights sind eine 4,9 GB große Datei (4,6 GiB). Vor den Arbeitspuffern der Runtime braucht das Model etwa 5,6 GiB bei 8K Kontext und etwa 8,6 GiB bei 32K.
Metal meldet eine empfohlene GPU-Working-Set-Größe, recommendedMaxWorkingSetSize. Sie schätzt, wie viel GPU-Speicher sich ohne Einbußen bei der Runtime-Performance belegen lässt. Das ist eine Performance-Empfehlung, keine erzwungene Zuweisungsgrenze. In einem Bericht von 2023 gab llama.cpp auf einem M1 mit 16 GB 10.923 MB aus, etwa 10,7 GiB oder zwei Drittel des RAM. Gegenüber dieser Empfehlung bleiben bei 8K 5,1 GiB für Runtime-Arbeitsspeicher und Reserve, bei 32K 2,1 GiB. Prüfe den Wert auf deinem eigenen Mac und miss die gesamte Last, bevor du entscheidest, ob sie hineinpasst. Ein Mac mit 8 GB hat weniger Reserve; allein diese Weights brauchen bereits 4,6 GiB.
Plane auch Speicherplatz auf der Platte ein. Jedes 4-Bit-Model mit 7B oder 8B ist ein Download von 4–5 GB, und eine kleine Bibliothek mit Models in beiden Formaten belegt 10–20 GB.
Nutze beim Testen die Aktivitätsanzeige oder die eigenen Metriken der Runtime. Apple definiert den Speicherdruck anhand von freiem Speicher, Swap-Rate, reserviertem Speicher und gecachten Dateien. Lass genug Reserve, damit es nicht dauerhaft zu Swapping kommt. Ein Model, das zwar lädt, das System aber unter Speicherdruck setzt, eignet sich nicht für interaktive Nutzung.
Jeder Tool-Abschnitt unten zeigt, wo du die Kontextlänge einstellst, denn diese Einstellung verändert den KV cache am stärksten.
Die vier Tools lösen unterschiedliche Workflow-Probleme
| Tool | Primäre Oberfläche | Modellformat | Lizenz | Wähle es, wenn |
|---|---|---|---|---|
| Ollama | CLI und lokale HTTP-API | Verwaltete Modell-Bundles, meist GGUF | MIT | eine Anwendung einen einfachen, verwalteten lokalen Dienst braucht |
| LM Studio | Desktop-UI, CLI, SDKs, lokale APIs | GGUF und MLX | Proprietäre App, für die Arbeit kostenlos; MIT-SDKs | ein Mensch Models visuell finden, vergleichen, untersuchen und bereitstellen will |
| llama.cpp | CLI, C/C++-Bibliothek, lokaler Server | GGUF | MIT | du direkte Flags, Konvertierungs- und Quantization-Tools oder eingebettete Inference brauchst |
| MLX-LM | Python und CLI | Weights im MLX-Format | MIT | du Python für Apple Silicon schreibst oder ein Model auf demselben Mac feintunest |
Das ist eine Tabelle der Zuständigkeiten, kein Geschwindigkeitsranking. Drei der Tools teilen sich eine Tensor-Bibliothek. Ollama führt GGUF-Models mit einer eigenen Engine aus, die auf GGML aufbaut, der Bibliothek unter llama.cpp. Ollamas MLX-Preview vom März 2026 führt auch ausgewählte Models auf Macs mit mehr als 32 GB Speicher aus. LM Studio führt GGUF-Models mit llama.cpp aus und MLX-Models mit MLX. Eine gemeinsame GGML-Bibliothek bedeutet keine identischen Inference-Engines. Selbst bei derselben GGUF-Datei können Standardwerte wie Kontextlänge und Batch-Größe, Engine-Implementierungen und Backend-Versionen die Geschwindigkeit beeinflussen.
Das Diagramm zeigt die Model-Formate und gemeinsamen Bibliotheken der Tools, einschließlich Ollamas bedingtem MLX-Pfad.
Wenn du noch nicht weißt, welchen Workflow du hast, nutze die letzte Spalte der Tabelle. Fang mit Ollama an, wenn du heute einfach etwas zum Laufen bringen willst.
Eine Aufgabe liegt außerhalb der vier Tools: KoboldCpp, ein llama.cpp-Fork mit Web-UI, ist für lange Fiktion und Rollenspiele gebaut. Es steht unter der AGPL, was wichtig wird, wenn du es in ein Produkt einbaust.
Eine API für alle vier Tools
Alle vier Tools können eine OpenAI-kompatible API auf localhost bereitstellen. Anwendungscode, der den openai-Client nutzt, kann das Tool wechseln, indem er base_url ändert, und derselbe Client kann alle vier benchmarken.
| Tool | Server-Befehl | Standard-Base-URL |
|---|---|---|
| Ollama | ollama serve (die macOS-App startet es) | http://localhost:11434/v1 |
| LM Studio | lms server start | http://localhost:1234/v1 |
| llama.cpp | llama-server -hf <repo>:<quant> | http://localhost:8080/v1 |
| MLX-LM | mlx_lm.server --model <repo> | http://localhost:8080/v1 |
Der Client verlangt einen API-Key-Wert. Verwende local als Platzhalter, wenn die Server-Authentifizierung deaktiviert ist, und dein konfiguriertes Token, wenn sie aktiviert ist. llama-server und mlx_lm.server verwenden beide standardmäßig Port 8080. Starte einen von beiden mit --port 8081, um beide gleichzeitig zu betreiben.
Die Python-Beispiele, die openai importieren, brauchen das Paket openai. Der Benchmark unten enthält einen Befehl, der das gespeicherte Skript mit dieser Abhängigkeit ausführt.
from openai import OpenAI
# Swap base_url for :1234 (LM Studio) or :8080 (llama.cpp, MLX-LM).
client = OpenAI(base_url="http://localhost:11434/v1", api_key="local")
Der Benchmark-Abschnitt weiter unten nutzt diesen Client, um alle vier Tools mit einem Skript zu messen.
Ollama: verwalteter lokaler Dienst
Ollama verwaltet Model-Downloads, Templates, den Prozess-Lebenszyklus und eine localhost-API. Es ist nützlich, wenn Anwendungscode einen stabilen lokalen Dienst ansprechen soll, statt die Inference-Flags selbst zu besitzen.
MODEL=llama3.2
ollama pull "$MODEL"
ollama show "$MODEL" # architecture, parameters, context length, quantization
ollama run "$MODEL" "Explain unified memory."
curl http://localhost:11434/api/chat \
-H 'Content-Type: application/json' \
-d '{
"model": "'"$MODEL"'",
"messages": [{"role": "user", "content": "Explain unified memory."}],
"options": {"num_ctx": 8192},
"stream": false
}'
Die Option num_ctx setzt die Kontextlänge für einen Request. Um sie für den ganzen Server zu setzen, starte ihn mit OLLAMA_CONTEXT_LENGTH=8192 ollama serve oder nutze den Regler in den App-Einstellungen. Ohne beides wählt Ollama einen Standardwert anhand des verfügbaren Speichers: 4K Tokens, wenn weniger als 24 GiB GPU-Speicher verfügbar sind. ollama ps zeigt den Kontext, den jedes geladene Model verwendet.
Ein kurzer Bibliotheksname wie llama3.2 bezeichnet keine feste Datei. Derselbe Name kann nach einem Update auf einen anderen Build zeigen. Halte bei jeder Auswertung die ID fest, die ollama list ausgibt, also den Anfang des Model-Digests.
Ollama tauscht etwas Einblick auf niedriger Ebene gegen den Komfort im Lebenszyklus. Wechsle zu llama.cpp oder einer anderen Runtime, wenn du eine GGUF-Datei, ein Chat-Template, eine Cache-Einstellung oder ein neues Backend-Feature direkt steuern musst.
LM Studio: Desktop-Erkundung und lokale APIs
LM Studio ist nützlich, wenn Model-Suche, Ladekonfiguration, Chat-Inspektion und der direkte Vergleich durch Menschen in einem Workflow zusammengehören. Es bietet native SDKs für Python und TypeScript, OpenAI-kompatible Endpunkte, Structured Output, Tool Use und einen Headless-Daemon, ist also mehr als eine Desktop-GUI. Die Chat-Ansicht akzeptiert außerdem angehängte .pdf-, .docx- und .txt-Dateien als Kontext. Damit lassen sich einfache Fragen zu Dokumenten ohne Code beantworten.
Das aktuelle Python-SDK verbindet sich mit einem bereits heruntergeladenen Model. Starte den lokalen Server von LM Studio, speichere dies als lmstudio_demo.py und führe uv run --with lmstudio python lmstudio_demo.py aus. Setze bei aktivierter Authentifizierung LM_API_TOKEN; das SDK liest es automatisch.
import lmstudio as lms
MODEL_KEY = "ibm/granite-4-micro"
with lms.Client() as client:
model = client.llm.model(MODEL_KEY)
response = model.respond("Write one sentence about local inference.")
print(response)
Starte die lokale API im Developer-Tab oder über die CLI. lms load setzt beim Laden eines Models die Kontextlänge, und --estimate-only gibt die Speicherschätzung aus, ohne etwas zu laden:
lms server start
lms load ibm/granite-4-micro --context-length 8192 --estimate-only
lms load ibm/granite-4-micro --context-length 8192
LM Studio kann auf localhost oder in einem lokalen Netzwerk bereitstellen und unterstützt API-Tokens in den API-Authentifizierungseinstellungen. Lass es auf Loopback, solange Fernzugriff nicht ausdrücklich gewollt ist. Wenn du es in einem LAN freigibst, verlange die dokumentierte API-Token-Option, setze eine Firewall-Regel auf dem Host und prüfe den Zugriff von Tools und Integrationen.
llama.cpp: direkte GGUF-Ausführung
llama.cpp ist das Referenztool für GGUF-Dateien, wenn du die Runtime-Flags selbst setzen willst. Es unterstützt Apple Metal sowie CPU und weitere Hardware-Backends.
brew install llama.cpp
# Download through the Hugging Face integration and select a quantization.
MODEL_REPO=ggml-org/gemma-3-1b-it-GGUF
QUANT=Q4_K_M
llama-cli -hf "$MODEL_REPO:$QUANT"
# The same model with explicit settings: one turn, then exit.
llama-cli -hf "$MODEL_REPO:$QUANT" \
-c 8192 -n 256 --temp 0.7 -st \
-p "Write a Python function that sorts a list."
# Or start an OpenAI-compatible local server with an 8K context.
llama-server -hf "$MODEL_REPO:$QUANT" -c 8192
-c (--ctx-size) setzt die Kontextlänge und damit die Größe des KV cache. -n begrenzt die Zahl der erzeugten Tokens, --temp setzt die Sampling-Temperatur, -st führt einen einzelnen Turn aus und beendet sich, und -p übergibt den Prompt.
Die Option -hf lädt auch einen passenden Multimodal-Projektor herunter, wenn das Repository einen enthält. Model-Unterstützung, Templates und CLI-Flags ändern sich schnell. Pinne also einen bekannten Build und bewahre den Startbefehl zusammen mit den Auswertungsunterlagen auf.
Wähle llama.cpp, wenn direkte Kontrolle das Ziel ist, und nicht, weil „näher an der Hardware“ automatisch schneller bedeutet. Ein verwaltetes Tool wählt vielleicht gute Standardwerte; direkte Flags können die Performance auch verschlechtern.
MLX-LM: Apple-native Python-Arbeit
MLX-LM baut auf Apples Array-Framework MLX auf. Es unterstützt Generierung, Chat, Konvertierung, Quantization und parametereffizientes Fine-Tuning für kompatible Models.
MODEL=mlx-community/Llama-3.2-3B-Instruct-4bit
uv run --with mlx-lm mlx_lm.generate \
--model "$MODEL" \
--max-kv-size 8192 \
--prompt "Explain Metal acceleration in one paragraph."
MLX-LM hat keine feste Kontexteinstellung: Der Cache wächst mit dem Prompt und der Ausgabe. --max-kv-size begrenzt den Cache auf so viele Tokens. Über dieser Grenze verwirft MLX-LM die ältesten Tokens und behält die ersten wenigen.
Python gibt direkten Zugriff auf Model und Tokenizer. Speichere dies als mlx_demo.py und starte es mit uv run --with mlx-lm python mlx_demo.py:
from mlx_lm import generate, load
MODEL = "mlx-community/Llama-3.2-3B-Instruct-4bit"
model, tokenizer = load(MODEL)
messages = [{"role": "user", "content": "Give one local-LLM benchmark rule."}]
prompt = tokenizer.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=True,
)
print(generate(model, tokenizer, prompt=prompt, max_tokens=80))
Der HTTP-Server von MLX-LM, mlx_lm.server, ist als Entwicklungsserver mit einfachen Sicherheitsprüfungen dokumentiert und nicht als Produktionsdienst. Nutze ihn für lokale Experimente, oder setze einen authentifizierten Proxy oder deinen eigenen API-Dienst davor.
Tools auf demselben Workload vergleichen
Teste dieselbe Checkpoint-Familie und, wo die Formate es erlauben, eine vergleichbare Quantization. Eine GGUF-Datei in Q4_K_M und ein 4-Bit-MLX-Model desselben Checkpoints sind vergleichbar, aber nicht identisch.
Nimm ein kleines Prompt-Set mit:
- einem kurzen interaktiven Prompt
- einem langen Prompt nahe am vorgesehenen Kontext
- Structured Output oder Tool Calls, falls die Anwendung sie braucht
- einer repräsentativen Generierungslänge
- einem wiederholten Request, um kaltes Laden von warmer Inference zu unterscheiden
Erfasse:
| Metrik | Warum sie wichtig ist |
|---|---|
| Aufgabenergebnis | Ein schnelles, falsches Model ist nutzlos |
| Time to first token | Reaktionsfähigkeit bei interaktiver Nutzung |
| Ausgabe-Tokens pro Sekunde | Generierungs-Throughput |
| Spitzenspeicher und Druck | Ob die Maschine nutzbar bleibt |
| Kaltladezeit | Erlebnis auf dem Desktop und bei Laden auf Abruf |
| Energie und thermisches Verhalten | Dauerhafte Nutzung auf dem Laptop |
| API-/Schema-Kompatibilität | Ob das Tool zur Anwendung passt |
Jedes Tool gibt die Geschwindigkeitswerte selbst aus:
- Ollama:
ollama run "$MODEL" --verbosegibt nach jeder Antwort Ladedauer, Prompt-Eval-Rate und Eval-Rate (Ausgabe-Tokens pro Sekunde) aus. - llama.cpp:
llama-bench -hf "$MODEL_REPO:$QUANT" -p 512 -n 128misst die Verarbeitung eines Prompts mit 512 Tokens und die Generierung von 128 Tokens, jeweils in Tokens pro Sekunde. - MLX-LM:
mlx_lm.generategibt nach jedem Lauf Prompt- und Generierungs-Tokens pro Sekunde sowie den Spitzenspeicher aus. - LM Studio: Die Chat-Ansicht zeigt unter jeder Antwort Tokens pro Sekunde und Time to first token, und die native REST-API liefert dieselben Werte im Feld
stats.
Um die vom Client beobachtete Latency zu vergleichen, miss einen Streaming-Request gegen die OpenAI-kompatiblen Endpunkte aus dem Abschnitt „Eine API für alle vier Tools“. Das Skript misst die gesamte Request-Dauer und die Zeit bis zum ersten sichtbaren Text und gibt dann die Antwort zur Prüfung aus. Sichtbarer Text kann erst nach Reasoning oder Tool-Ausgaben folgen. Diese Zeit entspricht daher nicht unbedingt der Runtime-Zeit bis zum ersten generierten Token.
Starte den gewählten Server mit einem heruntergeladenen Model, speichere das Skript als benchmark.py und führe uv run --with openai python benchmark.py aus. Ändere BASE_URL und MODEL pro Tool. Setze LOCAL_API_KEY auf dein konfiguriertes Token, wenn die Server-Authentifizierung aktiviert ist; sonst nutzt das Skript local als Platzhalter.
import os
import time
from openai import OpenAI
BASE_URL = "http://localhost:11434/v1"
MODEL = "llama3.2"
client = OpenAI(base_url=BASE_URL, api_key=os.environ.get("LOCAL_API_KEY", "local"))
start = time.perf_counter()
first = None
parts = []
stream = client.chat.completions.create(
model=MODEL,
messages=[{"role": "user", "content": "Explain unified memory in 200 words."}],
max_tokens=300,
stream=True,
)
for chunk in stream:
if chunk.choices and chunk.choices[0].delta.content:
if first is None:
first = time.perf_counter()
parts.append(chunk.choices[0].delta.content)
end = time.perf_counter()
print(f"request duration: {end - start:.2f} s")
if first is None:
print("time to first visible text: unavailable (no visible text)")
else:
print(f"time to first visible text: {first - start:.2f} s")
print("response:", "".join(parts))
Gestreamte Textabschnitte sind keine Token-Zählwerte. Verwende für Ausgabe-Tokens pro Sekunde die oben genannten Runtime-Zähler und halte fest, ob sie Reasoning oder Tool-Ausgaben enthalten. Beispielsweise meldet LM Studio Ausgabe-Tokens insgesamt und Reasoning-Tokens getrennt. Ein Stream ohne sichtbaren Text meldet dessen Fehlen, statt eine Text-Latency zu vergeben. Prüfe Reasoning, Tool Calls oder den Abschlussstatus über die Runtime-Oberfläche.
Führe jeden Request zweimal aus: Der erste kann das Laden des Models enthalten, der zweite kann geladene Weights und gecachte Prompt-Zustände wiederverwenden. Erfasse Runtime-Versionen und Prompt-Caching-Einstellungen, damit wiederholte Requests vergleichbar bleiben.
Vergleiche nicht das 4-Bit-Model eines Tools mit dem Model in voller Präzision eines anderen Tools und führe den Unterschied dann auf die Runtime zurück.
Checkliste für Sicherheit und Datenschutz
Trenne lokale Inference von Offline-Betrieb. Prompts können auf der Maschine bleiben, während die Anwendung trotzdem für Model-Downloads, Updates oder optionale Funktionen das Netzwerk nutzt. Ollama dokumentiert lokale Ausführung, Model-Downloads und optionale Cloud-Funktionen in seiner FAQ getrennt. Behandle Offline-Betrieb als Workflow-Anforderung, die du pro Anwendung prüfst: Lade zuerst die Artefakte herunter, trenne das Netzwerk und teste den gesamten Workflow.
Das Diagramm zeigt vier Netzwerkpfade, die du bei lokaler Inference prüfen solltest: welchen Teil des Mac sie erreichen, in welche Richtung Daten fließen und was du jeweils prüfen musst. Cloud-Funktionen und LAN-Zugriff hängen von der Anwendungskonfiguration ab.
- Binde APIs an Loopback, solange kein Netzwerkzugriff nötig ist.
- Wenn LAN-Zugriff nötig ist, nutze eine Host-Firewall und entweder die dokumentierte Authentifizierung des Tools oder einen authentifizierten Reverse-Proxy vor dem Dienst. Die Unterstützung für API-Tokens ist toolabhängig: LM Studio dokumentiert API-Tokens, und
llama-serverakzeptiert--api-key. Ollama lauscht standardmäßig auf127.0.0.1:11434, undOLLAMA_HOSTändert die Bind-Adresse. Seine lokale API verlangt keine Authentifizierung, setze also für LAN-Nutzung einen authentifizierten Proxy davor. - Behandle Model-Dateien als Artefakte von Dritten; halte Quelle, Revision, Lizenz und Hash fest.
- GGUF-Dateien enthalten keinen ausführbaren Code. Models im Hugging-Face-Format können Python-Code mitliefern; übergib
--trust-remote-codeweder an MLX-LM noch an Transformers für ein Repository, das du nicht geprüft hast. - Prüfe, ob optionale Funktionen für Dokumente, Tools, Updates oder Analytics Netzwerkaufrufe machen.
- Geh nicht davon aus, dass lokale Generierung abgerufene Dokumente, Logs oder Seiteneffekte von Tools sicher macht.