1 Punkte von GN⁺ 3 시간 전 | 1 Kommentare | Auf WhatsApp teilen
  • Die Konfiguration eines lokalen Coding-Agenten ermöglicht es, Modelle unter macOS auch bei Internetausfällen über eine OpenAI-kompatible API auszuführen und in Pi Text- und Bildeingaben zu verarbeiten
  • Verwendet wurden llama.cpp Metal und das Modell Gemma 4 26B-A4B GGUF auf einem Apple M1 Max mit 64 GB und macOS 15.7.7; die Basis-Generierungsgeschwindigkeit lag bei 58.2 tok/s
  • Nach dem Hinzufügen eines MTP draft model und der Anpassung auf --spec-draft-n-max 3 stieg die Generierungsgeschwindigkeit auf 72.2 tok/s, also um rund 24 %
  • Damit Bildeingaben wie Screenshots übertragen werden, muss mmproj-BF16.gguf mit --mmproj geladen und die Modelleingabe in Pi auf ["text", "image"] gesetzt werden
  • Die endgültige Konfiguration betreibt den llama.cpp-Server unter 127.0.0.1:8080/v1, den Pi als lokalen Provider nutzt; Qwen3.6 35B-A3B zeigte zwar bessere Benchmarks für Coding-Agenten, war in diesem Test mit 55 tok/s jedoch langsamer

Ziel der lokalen Coding-Agent-Konfiguration

  • Mehrere Internetausfälle, durch die der Coding-Agent nicht nutzbar war, gaben den Anstoß, eine lokale Ausführungskonfiguration auszuprobieren
  • Die gewünschte Konfiguration sollte auf dem Mac schnell genug für den praktischen Einsatz sein und über eine OpenAI-kompatible API auch in anderen Tools nutzbar sein
  • Außerdem sollte sie bei Bedarf Screenshots oder Bilder verarbeiten können, damit vom Agenten erzeugte Ergebnisse wieder als Eingabe verwendet werden können
  • Die endgültige Konfiguration besteht aus llama.cpp, Gemma 4 26B-A4B GGUF, einem Q8 MTP draft model, dem Gemma-4-Multimodal-Projector und dem terminalbasierten Coding-Agenten Pi
  • Die Testumgebung war ein Apple M1 Max mit 64 GB Unified Memory und macOS 15.7.7

Modell

  • Das Hauptmodell war gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf und liegt im Hugging-Face-Repository unsloth-gemma-4-26B-A4B-it-GGUF
  • Die Datei ist etwa 16 GB groß; zusammen mit MTP draft head und Multimodal-Projector umfasst der Modellordner rund 17 GB
  • Der Benchmark-Prompt lautete Write a compact Python function that parses a unified diff and returns the changed file paths. Then explain two edge cases.
  • Jeder Benchmark erzeugte etwa 128 Token

Basislauf: llama.cpp + Metal

  • Das Hauptmodell wurde direkt mit llama.cpp und Metal-Beschleunigung ausgeführt
  • Der Startbefehl setzte bei llama-cli den Modellpfad sowie -ngl 999, -fa on, -c 4096 und -n 128
  • In der Basiskonfiguration lagen Prompt-Verarbeitung und Generierung bei 298.0 tok/s beziehungsweise 58.2 tok/s
  • 58 tok/s ist nicht besonders schnell, aber nutzbar; bei Coding-Agent-Aufgaben ist wegen der vielen Tool-Aufrufe jedoch möglichst hohe Geschwindigkeit wichtig

MTP draft model hinzufügen

  • Für Gemma 4 wird ein MTP draft model in der Form MTP/gemma-4-26B-A4B-it-Q8_0-MTP.gguf bereitgestellt
  • In llama.cpp wird es für spekulatives Dekodieren über --model-draft, --spec-type draft-mtp und --spec-draft-n-max geladen
  • Der erste Lauf mit MTP erreichte bei 4 Draft-Token 69.2 tok/s
  • Die Unsloth-Dokumentation empfiehlt --spec-draft-n-max 2 als Ausgangspunkt, rät aber dazu, je nach Hardware Werte von 1 bis 6 zu testen und den schnellsten zu verwenden
  • Nach dem Tuning von --spec-draft-n-max war der Wert 3 mit 72.2 tok/s bei der Generierung am schnellsten
  • Das Hauptmodell allein erreichte 58.2 tok/s, die Konfiguration mit Q8 MTP draft model 72.2 tok/s
  • Die Prompt-Verarbeitung blieb nahezu unverändert, die Generierung verbesserte sich um etwa 24 %

Ergebnisse des MTP-Tunings

  • Getestet wurden --spec-draft-n-max-Werte von 1 bis 6
  • Bei Wert 1 lagen die Werte bei 295.5 tok/s für Prompts und 68.4 tok/s für Generierung
  • Bei Wert 2 waren es 299.1 tok/s für Prompts und 72.0 tok/s für Generierung
  • Bei Wert 3 wurden mit 295.6 tok/s für Prompts und 72.2 tok/s für Generierung die besten Werte erreicht
  • Bei Wert 4 sank die Generierung auf 70.7 tok/s, bei Wert 5 auf 63.7 tok/s und bei Wert 6 auf 61.2 tok/s
  • Auf dem M1 Max war 3 am schnellsten, 2 lag aber sehr nahe daran

Vergleich mit MLX

  • Um eine schnellere Methode zum Ausführen des Modells auf dem Mac zu prüfen, wurden auch MLX-Modelle auf Basis von mlx-lm getestet
  • llama.cpp Metal + MTP erreichte mit der Kombination aus Unsloth GGUF Q4 und Q8 MTP 72.2 tok/s
  • llama.cpp Metal allein erreichte mit Unsloth GGUF Q4 58.2 tok/s
  • MLX-LM erreichte mit Unsloth UD MLX 4-bit 45.8 tok/s
  • MLX-LM erreichte mit mlx-community 4-bit 43.9 tok/s und mit mlx-community OptiQ 4-bit 38.1 tok/s
  • In dieser speziellen Konfiguration war llama.cpp schneller als MLX, und llama.cpp mit MTP war die beste Wahl
  • Ein Versuch mit gemma-4-swift-mlx, auch Gemma 4 MTP zu nutzen, wurde abgebrochen, weil der getestete 26B-4-bit-MLX-Checkpoint nicht zu den vom Loader erwarteten Weight-Keys passte und kein neues Modell heruntergeladen und angepasst werden sollte

Bildunterstützung hinzufügen

  • Damit sich in Pi Screenshots anhängen lassen, darf die Modelleingabe nicht nur Text unterstützen
  • Der lokale Modelleintrag war ursprünglich auf "input": ["text"] gesetzt; in diesem Fall konnte Pi die Ausgabe des Bild-Tools nicht korrekt an das Modell übergeben
  • Auch der llama.cpp-Server benötigt für Multimodalität den Gemma-4-Multimodal-Projector mmproj-BF16.gguf
  • Wird der Projector mit --mmproj geladen, meldet llama.cpp Multimodal-Unterstützung, sodass Pi Bilder senden kann
  • Ein Testlauf von llama.cpp Metal + MTP ohne Projector ergab 120.3 tok/s für Prompts und 71.4 tok/s für Generierung
  • Der endgültige Lauf mit geladenem mmproj-BF16.gguf erreichte 297.4 tok/s für Prompts und 72.2 tok/s für Generierung
  • Beim endgültigen Lauf mit geladenem Projector zeigte sich kein Rückgang der Textgenerierungsgeschwindigkeit

Installation von llama.cpp

  • Als Abhängigkeiten wurden per Homebrew cmake, git, tmux und python@3.11 installiert
  • Es wurde der Pfad ~/Developer/ML-Models/Gemma4/repos angelegt und das Repository ggml-org/llama.cpp nach repos/llama.cpp geklont
  • Der Build wurde mit cmake -B build -DCMAKE_BUILD_TYPE=Release -DGGML_METAL=ON -DGGML_ACCELERATE=ON konfiguriert
  • Anschließend wurde mit cmake --build build --config Release -j ein Release-Build ausgeführt
  • Der getestete Build verwendete die Einstellungen GGML_METAL=ON, GGML_ACCELERATE=ON, GGML_BLAS=ON, GGML_BLAS_VENDOR=Apple

Modelldateien herunterladen

  • Es wurde eine Python-3.11-Virtualenv erstellt und huggingface_hub sowie hf_xet installiert
  • Mit huggingface-cli download wurden das Gemma-4-Hauptmodell, mmproj-BF16.gguf und das MTP draft model heruntergeladen
  • Die heruntergeladenen Zieldateien waren gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf, mmproj-BF16.gguf und MTP/gemma-4-26B-A4B-it-Q8_0-MTP.gguf
  • Der endgültige Modellordner unter models/unsloth-gemma-4-26B-A4B-it-GGUF/ enthält diese drei Dateien

Lokalen Server starten

  • Der endgültige Server wird mit llama-server gestartet, wobei Hauptmodell, MTP draft model und Multimodal-Projector gemeinsam angegeben werden
  • Wichtige Optionen sind --spec-type draft-mtp, --spec-draft-n-max 3, -ngl 999, -fa on, -c 65536, --parallel 1
  • Der Server wird mit --host 127.0.0.1 --port 8080 ausgeführt
  • Der OpenAI-kompatible Endpunkt lautet http://127.0.0.1:8080/v1
  • Das Wrapper-Skript start_server.sh startet den Server in einer tmux-Session und schreibt Logs nach logs/llama-server-mtp.log
  • Nach chmod +x start_server.sh wird der Server mit ./start_server.sh gestartet
  • Ob der Server läuft, lässt sich mit curl http://127.0.0.1:8080/v1/models prüfen

Pi-Konfiguration

  • Pi liest die Modellanbieter-Konfiguration aus ~/.pi/agent/models.json
  • Die baseUrl des lokalen Providers gemma4-local zeigt auf http://127.0.0.1:8080/v1
  • api ist openai-completions, und da es sich um einen lokalen Server handelt, bleibt authHeader auf false
  • Als Modell-ID wird gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf gesetzt, als Name Gemma 4 26B-A4B Q4 + MTP
  • input muss auf ["text", "image"] stehen, sonst behandelt Pi das Modell als reines Textmodell
  • Das Kontextfenster wird auf 65536, die maximale Tokenzahl auf 8192 gesetzt
  • Falls nötig, können in ~/.pi/agent/settings.json defaultProvider auf gemma4-local und defaultModel auf den betreffenden GGUF-Dateinamen gesetzt werden
  • Bei pi --offline --list-models gemma sollte für die Bildunterstützung yes angezeigt werden
  • Das lokale Modell wird mit pi --provider gemma4-local --model gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf ausgeführt
  • Nicht-interaktive Ausführung erfolgt in der Form pi -p --provider gemma4-local --model gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf "Explain what this repository does"
  • Ein Screenshot als Eingabe wird in der Form pi -p @"/path/to/screenshot.png" "Describe this image and point out anything relevant to the UI" übergeben

Endgültige Konfiguration

  • Die endgültige Inferenz-Laufzeit ist llama.cpp
  • Die Beschleunigung unter macOS erfolgt über die Kombination Metal + Accelerate
  • Das Hauptmodell ist gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf
  • Das Draft-Modell ist gemma-4-26B-A4B-it-Q8_0-MTP.gguf
  • Die MTP-Einstellung ist --spec-draft-n-max 3
  • Der Multimodal-Projector ist mmproj-BF16.gguf
  • Der Server ist llama-server auf 127.0.0.1:8080
  • Die API ist das OpenAI-kompatible /v1
  • Der Coding-Agent ist Pi, und die Pi-Modelleingabe ist ["text", "image"]
  • Das MTP draft model erhöhte in dieser Umgebung die Generierungsgeschwindigkeit von Gemma 4 von 58.2 tok/s auf 72.2 tok/s, und die Konfiguration ist einfach genug, um als lokaler OpenAI-kompatibler Server zu laufen

Alternative: Qwen3.6 35B-A3B

  • Einige schlagen vor, statt Gemma 4 26B-A4B lieber Qwen3.6 35B-A3B zu verwenden
  • Nach nachvollziehbaren Benchmarks wird Qwen als deutlich besserer Coding-Agent als Gemma 4 bewertet
  • Die Qwen-Konfiguration war jedoch langsamer und erreichte mit Qwen3.6-35B-A3B-UD-Q4_K_XL.gguf, unsloth-Qwen3.6-35B-A3B-MTP-GGUF und mmproj-BF16.gguf 55 tok/s
  • 55 tok/s statt 72 tok/s macht für wartende Nutzer einen spürbaren Unterschied
  • Für den Download des Qwen-Modells werden aus unsloth/Qwen3.6-35B-A3B-MTP-GGUF Qwen3.6-35B-A3B-UD-Q4_K_XL.gguf und mmproj-BF16.gguf bezogen
  • Der Qwen-Server verwendet ebenfalls llama-server, läuft aber mit --port 8081
  • In der Pi-Konfiguration heißt der Qwen-Provider qwen36-local, mit baseUrl auf http://127.0.0.1:8081/v1
  • Die Qwen-Modellkonfiguration verwendet reasoning: true, input: ["text", "image"], contextWindow: 65536, maxTokens: 8192

1 Kommentare

 
GN⁺ 3 시간 전
Hacker-News-Kommentare
  • Wenn der Benchmark-Prompt lautete, „schreibe eine knappe Python-Funktion, die einen unified diff parst und die Pfade der geänderten Dateien zurückgibt, und erkläre zwei Edge Cases“, und jeder Benchmark dabei etwa 128 Token erzeugt hat, dann wirken 128 Token für ein gutes Ergebnis viel zu wenig
    Die MTP-Beschleunigung hängt davon ab, wie oft vorhergesagte Token übernommen werden; erfahrungsgemäß ist die Übernahmerate am Anfang der Ausgabe höher, sodass kurze Tests eine falsch positive Beschleunigung erzeugen können
    In llama.cpp gibt es ein spezielles Benchmark-Tool, das Parameter durchläuft, ohne dass man den Server neu starten und einen Prompt senden muss: https://github.com/ggml-org/llama.cpp/blob/master/tools/llam...
    Im Abschnitt zum Herunterladen von Modellen hätte auch erwähnt werden sollen, dass das -hf-Argument von llama.cpp das Modell stattdessen für einen herunterlädt. Danke, dass der Autor seine Erfahrungen geteilt hat, aber für Einsteiger ist das vielleicht nicht die beste Anleitung

    • Das war nicht als echter Entwickler-Guide gedacht. Die Bildschirmaufnahme bekam viele Bookmarks und ich bekam Nachrichten mit Fragen zur Einrichtung, also habe ich nur schnell zusammengefasst, wie ich diesen Test aufgebaut habe
      Nachdem ich die Ankündigung von Unclothe zu „2x Geschwindigkeit“ gesehen hatte, wollte ich wissen: „Wird das damit in der Praxis schnell genug, um es wirklich zu benutzen?“ und habe es selbst eingerichtet
      Letztes Jahr habe ich auch mit so etwas wie Devstral getestet, aber das war so langsam und so dumm, dass ich es nicht weiter benutzen wollte; diesmal habe ich endlich das Gefühl erreicht, dass es sowohl bei der Geschwindigkeit als auch bei der Intelligenz brauchbar ist
    • Realistisch betrachtet sollte man mit beliebigen Nutzer-Prompts plus einem ausreichend großen System-Prompt experimentieren. Mindestens 1000 Token, in der Praxis eher etwa 3000 Token, scheinen sinnvoll
      llama.cpp hat dafür ein Tool, und um sauber zu messen, muss man vor der Token-Generierung ein Prefill einfügen. Es wird auch immer wichtiger, die Token-Generierungsgeschwindigkeit bei langen Kontexten wie 32k oder 64k zu messen
    • Mit 128 Token benchmarkt man nicht die Oper, sondern nur die Ouvertüre
    • Das ist ungefähr so, als würde man sagen: „Läuft auf meinem Rechner“, ohne das eigentliche Problem anzuschauen. 128 Token sind wirklich fast nichts, nur etwas länger als eine kurze Begrüßungsantwort
  • Ich habe früher mit ollama und opencode schon einmal einen ähnlichen Beitrag geschrieben: https://blog.kulman.sk/running-local-llm-coding-server/

    • Ollama ist keine gute Wahl: https://sleepingrobots.com/dreams/stop-using-ollama/
      Verbraucht opencode mit seinem System-Prompt nicht zu viel Kontext? Lokale Modelle haben starke Kontextbeschränkungen, und wenn ich mich richtig erinnere, nutzt opencode dafür etwa 10k oder eine ähnliche Größenordnung
    • Es ist tatsächlich nützlich, und mit der ollama GUI könnte man es vermutlich noch einfacher machen
  • Wenn man nur llama.cpp nutzt, braucht man huggingface-cli offenbar nicht zwingend, um etwas herunterzuladen. Übergibt man -hf ..., lädt es das Modell herunter
    Wenn man den Download-Ort ändern will, setzt man LLAMA_CACHE:
    LLAMA_CACHE="models" ./llama-server \
    -hf unsloth/gemma-4-31B-it-GGUF:UD-Q4_K_XL \
    ...

    • Für Draft-Modelle kann man -hfd verwenden
  • Wenn der Unified-Memory-RAM groß ist, aber Teraflops und Bandbreite in GB/s nur mittelmäßig oder schlechter sind, ist in der Regel MoE am vielversprechendsten. In meiner Umgebung mit einem M2 Max 96GB ist derzeit nach (Intelligenz, tok/s, Kontexttiefe) die Nummer 1 DeepSeek-V4-Flash REAP25 <65gb gguf + ds4-server + pi agent
    Natürlich ist das nicht besser als eine Cloud-API, aber bei Bedarf ist es brauchbar genug, dass ich den Kompromiss eingehe. Selbst auf einem vierstündigen Flug ohne Internet hat ein lokales LLM mit 60 W genug Akkulaufzeit gehabt
    Der ds4-Branch mit REAP-Unterstützung ist hier: https://github.com/ljubomirj/ds4/tree/reap-compact-support
    Dass DS4F erst bei 784K Kontext auf unter 10 tok/s und damit auf ein unbrauchbares Niveau fällt, macht einen großen Unterschied

  • Ich frage mich, ob solche lokalen Modelle wirklich auch Nutzern helfen können, die keine Experten in einer bestimmten Programmiersprache sind, echte Probleme zu lösen
    Über Inline-Autovervollständigung oder die Implementierung einzelner Einheiten hinaus bin ich nicht sicher, ob sie tatsächlich funktionierende technische Spezifikationen entwerfen und zusammensetzen können

  • Mit llama.cpp/server ein lokales LLM zu starten und es zusammen mit Claude Code oder Codex-CLI zu verwenden, ist relativ einfach
    Da die nötigen Einstellungen für llama server oft verstreut sind, pflege ich hier Hinweise für einige populäre offene LLMs: https://pchalasani.github.io/claude-code-tools/integrations/...

    • Verwendest du das im Alltag? Die Prompts von Claude Code sind riesig, daher dauert die Prompt-Verarbeitung bei lokalen Modellen sehr lange, und kurz darauf ist auch schon der Kontext aufgebraucht
  • Mit omlx.ai habe ich ziemlich erfolgreich verschiedene MLX-Modelle heruntergeladen, die zu meiner Hardware passen, und mit diesen Modellen Open-Source- und geschlossene Harnesses (Claude Code, Codex) automatisch ausgeführt
    Das geht sowohl in einer Web- als auch in einer Desktop-UI, daher braucht man meiner Meinung nach mit omlx dem Blogpost gar nicht zu folgen

    • Auf einem 64GB M1 Max habe ich keinen besonderen Vorteil von oMLX oder MLX gegenüber GGUF in llama.cpp gesehen
      Die Gemma-4-MLX-Builds, die ich bisher gefunden habe, waren bei gleicher Quantisierung langsamer und mit MTP sogar deutlich langsamer
      Wenn man sich einmal für ein Modell entschieden hat, ist die eingebaute Web-UI von llama.cpp ziemlich gut, und für etwas Herumprobieren ist auch LM Studio okay
      Gemma-4 und Qwen 3.6 brauchen den großen allgemeinen opencode-System-Prompt-Block überhaupt nicht; es ist besser, ihn wegzulassen
    • Falls du eine Sandbox suchst, die sich an oMLX und Pi anbinden lässt, gibt es das hier: https://github.com/Dotnaught/pi-sandbox
    • Ich halte das für den State of the Art bei lokaler Inferenz auf dem Mac. Selbst wenn Regressionen auftreten, reagieren die Entwickler extrem schnell, und es ist eines der beeindruckendsten Open-Source-Projekte, die ich in letzter Zeit gesehen habe
  • DeepSeek v4 Flash mit antirez’ ds4 war ziemlich beeindruckend
    Beim „gespeicherten Wissen“ fühlt es sich wie ein Modell auf GPT-4-Niveau an, aber bei Tool-Calls in langen Abläufen macht es das besser als GPT-4-Klasse-Modelle
    Auf einem 128GB MBP M4 Max bekomme ich etwa 24 t/s bei der Generierung und etwa 200 t/s beim Prefill. Ich dachte, es würde langsam sein, und bei Aufgaben wie Code-Generierung ist es das auch tatsächlich, aber als Maschinen-Orchestrator für einfache Aufgaben ist es überraschend nützlich
    Für nicht-agentische Anwendungsfälle ist es auch als Gesprächsmodell völlig ordentlich, und es hat den Vorteil, vollständig selbstbetrieben und privat zu sein
    [0]https://github.com/antirez/ds4

  • Wenn man es maximal faul angehen will, öffnet man einfach Claude Code im Terminal, zeigt auf diesen Beitrag und sagt nur: „Mach das“

    • Ich benutze Google-Suche inzwischen fast gar nicht mehr. In 9 von 10 Fällen ist die Informationsqualität miserabel, und es ist schwer, inmitten des ganzen Spam das Nötige herauszufiltern
      Claude dagegen erledigt es auf einmal oder mit nur sehr wenig Nacharbeit sofort
      Das Tor zu Wissen und Ausführung ist jetzt das LLM, und Google Search wirkt wie ein Dinosaurier
      Es fühlt sich sogar noch beeindruckender an als das Smartphone, als wäre man ungefähr ein Jahrhundert in der Zukunft angekommen