Alle llama.cpp-Router-Modelle entladen, ohne neu zu starten

Kostenfreier VRAM, ohne den llama-server zu beenden.

Inhaltsverzeichnis

llama.cpp Router-Modus ist eine der nützlichsten Änderungen an llama-server in den letzten Jahren. Er gibt lokalen LLM-Betreibern endlich etwas, das dem Modellmanagement-Erlebnis ähnelt, das man von Ollama erwartet, während er die rohe Leistung und die niedrige Kontrollstufe beibehält, die llama.cpp überhaupt erst interessant machen.

Doch es gibt eine scharfe Kante: Das Entladen aller Modelle ist kein einzelner magischer Button in der HTTP-API.

Der Router kann Modelle auflisten. Er kann ein Modell laden. Er kann ein Modell entladen. Er kann das am längsten nicht benutzte Modell verwerfen, wenn --models-max erreicht ist. Was er jedoch nicht als erstklassigen Endpunkt dokumentiert, ist ein universeller Aufruf für „alle Modelle jetzt entladen“.

Laptop und Desktop mit LLMs

Das ist kein echtes Hindernis. Das korrekte Muster ist einfach, explizit und skriptbar:

  1. Fragen Sie den Router, welche Modelle existieren.
  2. Filtern Sie die Modelle, deren Status loaded (geladen) ist.
  3. Rufen Sie /models/unload einmal pro geladenem Modell auf.

Dies ist der Ansatz, den ich für ernsthafte lokale LLM-Workflows empfehle. Er ist langweilig, sichtbar und einfach zu debuggen. Genau das wollen Sie, wenn Ihr Ziel darin besteht, VRAM freizugeben, ohne den gesamten Inferenzdienst neu zu starten.

Was der llama.cpp Router-Modus tatsächlich tut

Bei der klassischen llama-server-Nutzung starten Sie einen Server mit einem Modell:

llama-server \
  --model ./models/qwen3-8b.gguf \
  --port 8080

Der Router-Modus ändert dies. Anstatt den Server an eine GGUF-Datei zu binden, wird der Router zu einem Koordinator für mehrere Modelle. Er kann Modelle aus einem Cache oder einem Modellverzeichnis entdecken, sie bei Bedarf laden, Anfragen an das richtige Modell weiterleiten und Modelle bei Bedarf entladen.

Ein typischer Start im Router-Modus sieht so aus:

llama-server \
  --models-dir ./models \
  --models-max 4 \
  --port 8080

Die wichtige Option hier ist --models-max. Sie steuert, wie viele Modelle gleichzeitig geladen sein dürfen. Wenn das Limit erreicht ist, kann llama.cpp das am längsten nicht benutzte Modell verwerfen. Das ist nützlich, ersetzt aber keine bewusste Entladungsoperation. LRU-Verwerfung (Least Recently Used) ist reaktiv. Ein Entladungs-Skript ist operative Kontrolle.

Meine persönliche Ansicht: Wenn Sie lokale Modelle für echte Arbeit nutzen, sollten Sie den Router-Modus wie einen Inferenz-Prozess-Manager behandeln, nicht wie einen Spielzeug-Chat-Server. Explizite Lifecycle-Operationen sind wichtig.

Die Modellmanagement-Endpunkte, die Sie benötigen

Der Hauptendpunkt zur Entdeckung ist:

curl -s http://localhost:8080/models | jq

Dieser Endpunkt gibt die dem Router bekannten Modelle und ihren aktuellen Lifecycle-Status zurück. Die genaue JSON-Struktur kann zwischen Builds leicht variieren, daher sollten Sie Ihre eigene Antwort überprüfen, bevor Sie Automatisierung schreiben.

Eine häufige Antwortstruktur sieht so aus:

{
  "data": [
    {
      "id": "qwen3-8b",
      "status": "loaded"
    },
    {
      "id": "llama-3.2-3b",
      "status": "unloaded"
    }
  ]
}

Um ein Modell zu entladen, rufen Sie auf:

curl -s -X POST http://localhost:8080/models/unload \
  -H "Content-Type: application/json" \
  -d '{"model":"qwen3-8b"}' \
  | jq

Das ist die primitive Operation. Alles andere in diesem Artikel baut darauf auf.

Es gibt keinen dokumentierten „Alle entladen“-Endpunkt

Dies ist der Teil, der die Leute oft stolpern lässt.

Man könnte etwas in dieser Art erwarten:

curl -X POST http://localhost:8080/models/unload-all

Bauen Sie keine Annahmen darum auf. Die dokumentierte Operation erfolgt pro Modell. Sie übergeben einen Modell-Identifikator an /models/unload, und llama.cpp entlädt genau dieses eine Modell.

Dies ist nicht unbedingt schlechte API-Design. Eine pro-Modell-Operation ist sicherer. Sie lässt den Aufrufer entscheiden, was entladen werden soll. Sie vermeidet auch überraschendes Produktionsverhalten, bei dem eine Admin-Anfrage versehentlich jedes warme Modell beendet, das von anderen Clients verwendet wird.

Für einen Arbeitsplatz wäre eine „Alle entladen“-Abkürzung bequem. Für eine Multi-User-Inferenzmaschine sind explizite Schleifen besser.

Entladen Sie zuerst ein einzelnes Modell

Bevor Sie irgendetwas automatisieren, testen Sie den genauen Modell-Identifikator, den Ihr Router erwartet.

Listen Sie zuerst die Modelle auf:

curl -s http://localhost:8080/models | jq

Wählen Sie ein geladenes Modell aus der Ausgabe und entladen Sie es:

curl -s -X POST http://localhost:8080/models/unload \
  -H "Content-Type: application/json" \
  -d '{"model":"qwen3-8b"}' \
  | jq

Überprüfen Sie die Modellliste erneut:

curl -s http://localhost:8080/models | jq

Wenn sich der Modellstatus in unloaded (entladen) ändert, sind Ihr Endpunkt, Port und Modell-Identifikator korrekt.

Falls es nicht funktioniert, raten Sie nicht. Untersuchen Sie das JSON. Router-Aliasnamen, GGUF-Dateinamen und Modell-IDs sind oft nicht dieselbe Zeichenfolge.

Entladen Sie alle geladenen Modelle mit curl und jq

Sobald das Entladen eines einzelnen Modells funktioniert, ist das „Alle entladen“-Muster nur eine Shell-Schleife.

Verwenden Sie dies, wenn Ihre /models-Antwort .data[].id und .data[].status enthält:

curl -s http://localhost:8080/models \
| jq -r '.data[] | select(.status == "loaded") | .id' \
| while IFS= read -r model; do
    echo "Entladen: $model"
    curl -s -X POST http://localhost:8080/models/unload \
      -H "Content-Type: application/json" \
      -d "{\"model\":\"$model\"}" \
      | jq
  done

Das ist der ganze Trick. Er ist nicht glamourös, hat aber die richtige Form für eine Admin-Operation:

  • Er entlädt nur Modelle, die tatsächlich geladen sind.
  • Er gibt aus, was er tut.
  • Er schlägt Modell für Modell fehl, anstatt alles hinter einer undurchsichtigen Aktion zu verstecken.
  • Er funktioniert über cron, systemd-Hooks, SSH oder CI-Jobs.

Ein wiederverwendbares Skript für den Produktiveinsatz

Für alles, was Sie mehr als zweimal ausführen, hören Sie auf, One-Liners einzufügen. Speichern Sie ein Skript.

Erstellen Sie llama-router-unload-all.sh:

#!/usr/bin/env bash
set -euo pipefail

LLAMA_SERVER_URL="${LLAMA_SERVER_URL:-http://localhost:8080}"

models_json="$(curl -fsS "$LLAMA_SERVER_URL/models")"

loaded_models="$(printf '%s' "$models_json" \
  | jq -r '.data[] | select(.status == "loaded") | .id')"

if [ -z "$loaded_models" ]; then
  echo "Keine geladenen Modelle gefunden."
  exit 0
fi

printf '%s\n' "$loaded_models" | while IFS= read -r model; do
  [ -z "$model" ] && continue

  echo "Entladen: $model"

  curl -fsS -X POST "$LLAMA_SERVER_URL/models/unload" \
    -H "Content-Type: application/json" \
    -d "{\"model\":\"$model\"}" \
    | jq

done

echo "Fertig. Aktueller Modellstatus:"
curl -fsS "$LLAMA_SERVER_URL/models" | jq

Machen Sie es ausführbar:

chmod +x llama-router-unload-all.sh

Führen Sie es gegen den lokalen Standardserver aus:

./llama-router-unload-all.sh

Führen Sie es gegen einen anderen Host aus:

LLAMA_SERVER_URL=http://192.168.1.50:8080 ./llama-router-unload-all.sh

Das ist die Version, die ich tatsächlich in einem Verzeichnis für Werkzeuge behalten würde. Sie verwendet curl -f, sodass HTTP-Fehler das Skript abbrechen, und Sie können die Server-URL überschreiben, ohne die Datei zu bearbeiten.

Anpassen des Skripts an Ihre JSON-Struktur

Gehen Sie nicht blind davon aus, dass jeder llama.cpp-Build für immer exakt dieselben Felder zurückgibt. Der Router-Modus entwickelt sich noch immer weiter, und Ihr Build könnte eine leicht unterschiedliche JSON-Struktur aufweisen.

Beginnen Sie mit der Inspektion der Antwort:

curl -s http://localhost:8080/models | jq

Das Skript verwendet diesen Filter:

jq -r '.data[] | select(.status == "loaded") | .id'

Wenn Ihr Modell-Identifikator in .name steht, ändern Sie ihn zu:

jq -r '.data[] | select(.status == "loaded") | .name'

Wenn Ihr Statusfeld einen anderen Wert verwendet, passen Sie den Filter entsprechend an. Das Prinzip ist das, was zählt: Wählen Sie geladene Modelle aus, extrahieren Sie den von /models/unload akzeptierte Identifikator und rufen Sie dann für jedes Modell die Entladung auf.

Warum Modelle sich erneut laden können, nachdem Sie sie entladen haben

Dies ist die häufigste Quelle für Verwirrung.

Der Router-Modus unterstützt das laden bei Bedarf. Wenn ein Client eine Chat-Vervollständigungsanfrage für ein Modell sendet, das derzeit entladen ist, kann der Router es automatisch erneut laden.

Das bedeutet, dass diese Sequenz möglich ist:

  1. Sie entladen jedes Modell.
  2. Open WebUI, ein Testskript oder ein Agent sendet eine Anfrage.
  3. llama.cpp lädt das angeforderte Modell erneut.
  4. Sie denken, die Entladung sei fehlgeschlagen, aber das war sie nicht.

Die Lösung ist operativ, nicht technisch. Beenden Sie den Client-Verkehr zuerst, wenn Ihr Ziel darin besteht, VRAM frei zu halten.

Zum Beispiel:

  • Beenden Sie Benchmark-Skripte.
  • Pausieren Sie Agenten und Cron-Jobs.
  • Schließen oder trennen Sie Open WebUI-Sitzungen.
  • Deaktivieren Sie Health-Checks, die versehentlich echte Modell-Anfragen ausführen.

Entladen ist kein Firewall. Wenn Clients weiterhin nach Modellen fragen, erfüllt der Router-Modus seinen Zweck, indem er sie bedient.

Open WebUI und die Eject-Taste (Auswerfen)

Open WebUI kann die llama.cpp-Modell-Entladungsunterstützung integrieren. Wenn der Provider als llama.cpp konfiguriert ist, kann Open WebUI den Status geladener Modelle anzeigen und eine „Eject“-Aktion (Auswerfen) für Administratoren bereitstellen.

Im Hintergrund ruft diese Aktion die eigene Entladungs-API von Open WebUI auf, die dann den /models/unload-Endpunkt von llama.cpp auf der konfigurierten Verbindung aufruft.

Das ist schön für manuelle Operationen, aber ich würde das Shell-Skript trotzdem behalten. Ein UI-Button ist bequem. Ein Skript ist überprüfbar, wiederholbar und auf einer Headless-Maschine um 2 Uhr morgens nutzbar.

Wann Sie „Alle entladen“ verwenden sollten

Das Entladen aller geladenen Modelle ist nützlich, wenn Sie Folgendes tun möchten:

  • GPU-Speicher freimachen, bevor Sie ein größeres Modell starten.
  • Eine Entwicklungsbox zurücksetzen, ohne llama-server neu zu starten.
  • Sich auf einen Benchmark-Run mit einem sauberen Speicherzustand vorbereiten.
  • Lokale Inferenz-Workloads vor der Wartung entladen.
  • Sich von einer unübersichtlichen Sitzung erholen, in der zu viele Modelle „gewärmt“ wurden.

Es ist nicht das richtige Werkzeug, wenn aktive Benutzer von warmen Modellen abhängen. In diesem Fall sollten Sie --models-max anpassen, bewusste Routing-Strategien verwenden und LRU-Verwerfung einen Teil der Arbeit erledigen lassen. Wenn Sie intelligentere, timeout-basierte Entladungen mit Lifecycle-Kontrolle pro Modell benötigen, ist llama-swap ein speziell dafür entwickelter Proxy, der genau das auf jede llama-server-Konfiguration aufsetzt.

Meine Regel ist einfach: Nutzen Sie LRU für normalen Druck, nutzen Sie explizites Entladen für Operator-Absichten.

Fehlerbehebung

Der Modelle-Endpunkt gibt 404 zurück

Sie führen möglicherweise keinen Router-fähigen Build aus, oder Sie rufen den falschen Port auf.

Überprüfen Sie den Serverprozess und die verfügbaren Optionen:

llama-server --help | grep -i models

Testen Sie dann beide Endpunkte:

curl -s http://localhost:8080/models | jq
curl -s http://localhost:8080/v1/models | jq

Der /v1/models-Endpunkt ist die OpenAI-kompatible Modellliste. Der /models-Endpunkt ist der Router-Modellmanagement-Endpunkt. Sie sind verwandt, aber sie sind nicht dasselbe.

jq ist nicht installiert

Installieren Sie es, bevor Sie JSON-Parsing-Skripte schreiben.

Auf Ubuntu oder Debian:

sudo apt-get update
sudo apt-get install jq

Auf macOS mit Homebrew:

brew install jq

Die Entladungsanfrage gibt einen Fehler zurück

Die meisten Fehler entstehen dadurch, dass der falsche Modell-Identifikator übergeben wird. Verwenden Sie den exakten Identifikator, der von /models zurückgegeben wird, nicht den Dateinamen, von dem Sie denken, dass er funktionieren sollte.

Überprüfen Sie auch, ob Ihr Modellname Anführungszeichen, Schrägstriche oder Leerzeichen enthält. Das obige Skript behandelt normale Strings gut, aber ungewöhnliche Namen können eine sorgfältigere JSON-Konstruktion erfordern.

Für maximale Sicherheit können Sie den POST-Body mit jq erstellen:

jq -n --arg model "$model" '{model: $model}'

Eine defensivere Entladungsschleife würde diesen Body anstelle von manuell escapedem JSON verwenden.

VRAM wird nicht sofort freigegeben

Bestätigen Sie zuerst, dass sich der Modellstatus geändert hat. Überprüfen Sie dann, ob eine andere Anfrage ihn neu geladen hat. Denken Sie auch daran, dass GPU-Speicher-Tools verzögert sein können oder das Verhalten des Allocators melden, anstatt die sofortige Anwendungsebeneabsicht.

Der praktische Test ist einfach: Verkehr stoppen, Modelle entladen, Modellstatus auflisten, dann GPU-Speicher inspizieren. Für gemessene VRAM-Nutzung über Modellgrößen und Kontextfenster hinweg auf llama.cpp geben die 16 GB VRAM llama.cpp Benchmarks konkrete Zahlen zur Plausibilitätsprüfung.

Eine sicherere JSON-Body-Version

Wenn Ihre Modell-Identifikatoren ungewöhnliche Zeichen enthalten, verwenden Sie jq, um den JSON-Anfrage-Body zu generieren:

curl -s http://localhost:8080/models \
| jq -r '.data[] | select(.status == "loaded") | .id' \
| while IFS= read -r model; do
    echo "Entladen: $model"
    body="$(jq -n --arg model "$model" '{model: $model}')"
    curl -s -X POST http://localhost:8080/models/unload \
      -H "Content-Type: application/json" \
      -d "$body" \
      | jq
  done

Das ist die Version, die Sie verwenden sollten, wenn Ihre Modelle mit repository-stilisierten Identifikatoren, benutzerdefinierten Aliasnamen oder Pfaden benannt sind.

Fazit

Der llama.cpp Router-Modus ist ein großer Schritt nach vorn für lokale LLM-Operationen. Er gibt Ihnen dynamisches Laden, Modellwechsel und speicherbewusste Verwerfung auf, ohne die Direktheit von llama-server aufzugeben.

Aber warten Sie nicht auf einen perfekten „Alle entladen“-Endpunkt. Die saubere Lösung existiert bereits: Laden Sie die geladenen Modelle auf und entladen Sie sie einzeln.

Dieses Muster ist explizit. Es ist skriptbar. Es funktioniert über SSH. Es funktioniert gut mit Open WebUI. Und was am wichtigsten ist, es gibt VRAM frei, ohne den Router neu zu starten.

Für lokale AI-Infrastruktur ist das genau die Art von langweiliger, kontrollierbarer Oberfläche, die Sie wollen.

Abonnieren

Neue Beiträge zu Systemen, Infrastruktur und KI-Engineering.