Bisher konnte jeder Client per Modellname llama-swap zum Wechseln bringen — ein Fremdprogramm haette ARIA das Modell unter den Fuessen weggetauscht. Jetzt: - Jede LLM-Karte einer Box (LLM_GPUS=1,2, alt LLM_GPU=1) haelt GENAU ein Modell, dauerhaft. Welches, legt nur die Diagnostic fest. Karten, die nicht fuers LLM vorgesehen sind, tauchen beim LLM nicht auf und werden als Ziel abgelehnt. - Clients (ARIA, Fremdprogramme ueber RVS, OpenHands ueber den OpenAI-Port) sehen nur die geladenen Modelle und laden nie: Anfrage fuer ein anderes → model_not_loaded mit Liste des Geladenen (RVS) bzw. HTTP 404 (OpenAI-Port). Nichts wird verdraengt. - Mehrere Clients koennen dasselbe Modell gleichzeitig nutzen. llm-adapter: Belegung in /models/aria_slots.json. Die llama-swap-Config enthaelt nur belegte Karten: pro Modell CUDA_VISIBLE_DEVICES=<Karte>, ttl 0, groups.swap=false, hooks.on_startup.preload. Alles gegen llama-swap ausprobiert (zwei Modelle gleichzeitig ready, keins verdraengt, Unbekanntes 404, env kommt beim jeweiligen llama-server an). llama-swap laeuft mit --watch-config; die frueher aufgerufenen Reload-Endpunkte (/reload, /api/config/reload) gibt es nicht (404). Neu: llm_unload_model (Karte leeren), llm_models_request → llm_models (Erkundung, jede Box antwortet einzeln). Fehlgeschlagenes Laden setzt die Karte auf ihr vorheriges Modell zurueck, sonst risse jedes Neuladen die anderen Karten mit. Uebernahme: ohne Belegungsdatei landet LLM_MODEL auf der ersten LLM-Karte. Compose: llama-swap sieht alle Karten (NVIDIA_VISIBLE_DEVICES=all) und zaehlt sie wie nvidia-smi (CUDA_DEVICE_ORDER=PCI_BUS_ID); das Pinnen pro Modell macht der Adapter. Bridge: uebernimmt models/slots auch aus worker_ping (nach "Entladen" sonst 30 s veraltet) und sagt sofort ab, wenn das Modell auf keiner Box liegt, statt per Broadcast in den Timeout zu laufen. Diagnostic: Flotte zeigt pro LLM-Karte Modell + Zustand + "Entladen"; Katalog waehlt eine Ziel-KARTE (leere vorausgewaehlt, Ersetzen mit Rueckfrage); Download-Fenster nennt Karte und was ersetzt wird. RVS: llm_unload_model, llm_models_request, llm_models freigegeben. docs/LLM-SCHNITTSTELLE.md: Schnittstelle fuer Drittprogramme (RVS + OpenAI- Port), Fehlercodes, Gleichzeitigkeit, Python-Beispiel. Tests: 23 gegen llama-swap (Adapter direkt) + Ende-zu-Ende ueber den echten RVS mit dem Adapter als Prozess: Laden per RVS mit Fortschritt, das Doku-Beispiel unveraendert (nur Adresse) findet beide Karten und bekommt eine Antwort, Absage/Schweigen wie dokumentiert, zwei Clients parallel. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Local-LLM-Adapter (AI-Box) — Plan B, Phase B0
Bringt ein lokales, schnelles LLM (Qwen3 8B) auf die AI-Box und haengt es
per RVS an ARIA — fuer die einfachen ~80 % der Turns (<1 s), waehrend Claude
das Tiefen-Hirn bleibt. Siehe docs/plan-local-llm-router.md im Repo-Root.
Zwei Container (in xtts/docker-compose.yml)
llama—llama.cpp-Server (CUDA), serviert das GGUF OpenAI-kompatibel auf:8081, nur im Compose-Netz.llm-adapter— verbindet sich per Token an den RVS (wie f5tts/whisper), nimmtllm_requestentgegen, ruftllamalokal, antwortetllm_response.
Modell — Auto-Download (nichts manuell ablegen)
llama.cpp zieht das GGUF beim ersten Start selbst von Hugging Face und
cached es unter xtts/models/ (Bind-Mount → kein Re-Download bei Restart).
Default: Qwen3 8B, Q4_K_M aus dem offiziellen Repo Qwen/Qwen3-8B-GGUF.
Modell/Quant wechseln = in der .env der AI-Box setzen (kein Code):
LLM_HF_REPO=Qwen/Qwen3-8B-GGUF # HF-Repo
LLM_HF_QUANT=Q4_K_M # Quant-Tag (Q4_K_M, Q5_K_M, Q8_0, …)
LLM_CTX=8192 # Kontextfenster (kleiner = weniger VRAM)
Mistral statt Qwen testen (A/B): LLM_HF_REPO auf ein Mistral-Small-3-GGUF-Repo
umstellen + Container neu — Ein-Zeilen-Wechsel, kein Code.
Der erste Start lädt mehrere GB — Log zeigt den Download-Fortschritt. Danach liegt das GGUF im Cache und der Start ist sofort.
Modell-Auswahl in ARIA Diagnostic (on-demand laden/aktivieren mehrerer
Modelle) ist ein geplanter Folge-Baustein via llama-swap — siehe
docs/plan-local-llm-router.md.
Start (auf der AI-Box)
cd xtts
docker compose up -d --build llama llm-adapter
docker logs -f aria-llm-adapter # "RVS verbunden — llm-adapter online"
Standalone-Test (ohne ARIA), direkt gegen llama.cpp
curl http://localhost:8081/v1/chat/completions -H "Content-Type: application/json" -d '{
"messages":[{"role":"system","content":"Du bist ARIA."},
{"role":"user","content":"sag kurz hallo"}],
"max_tokens":64
}'
VRAM-Hinweis (RTX 3060, 12 GB)
whisper-small (~1–2) + f5tts (~1–2) + qwen3-8b-q4 (~6) ≈ 9–10 GB. Passt, aber
knapp. Bei OOM: LLM_CTX reduzieren, -ngl senken (weniger Layer auf GPU),
oder kleineres Quant (Q4_K_S / IQ4_XS).
Nachrichten-Kontrakt (RVS)
llm_request→{ requestId, messages:[{role,content}], max_tokens?, temperature?, stop? }llm_response←{ requestId, ok, content, error?, model, elapsedMs }llm_partial— reserviert fuer B2 (Token-Streaming), noch ungenutzt.