# Plan B — Lokaler LLM-Router (Gamebox) neben Claude **Ziel:** „Gemini-Feeling" für den Alltag, ohne die Claude-Max-Subscription aufzugeben. Ein schnelles lokales LLM beantwortet die einfachen ~80 % der Turns in <1 s; nur die schweren 20 % (Tiefe, Code, Tools, Pentest, langer Kontext) gehen an Claude. Claude bleibt das Tiefen-Hirn. ## Warum das der einzige realistische Weg zu „live" ist Gemessen (10.07.2026): CLI-Round-trip über den Claude-Max-Proxy hat einen **harten Boden von ~3,5 s** (Subprozess-Start pro Turn). Streaming-API würde das brechen, kostet aber API-Geld → verliert die Max-Subscription. Ein lokales LLM für die einfachen Turns umgeht den 3,5-s-Boden komplett und ist **gratis** (läuft auf vorhandener Gamebox-GPU). Echtes Speech-to-Speech-Duplex (Gemini Live nativ) ist mit einem Text-Modell als Hirn prinzipiell nicht drin. ## Modell & Serving (entschieden) - **Modell:** Qwen3 8B, GGUF **Q4_K_M** (~6 GB). Bestes Tool-Calling der 7/8B- Klasse, solides Deutsch, Apache-2.0. Alt.: Mistral Small 3 7B (schneller, weniger Tool-Calling). - **Serving:** **llama.cpp `llama-server`** im Docker-Container auf der Gamebox (kein Ollama nötig — nativer OpenAI-kompatibler `/v1/chat/completions`). - **VRAM-Budget:** 12-GB-Karte, Whisper-small (~1–2 GB) + F5-TTS (~1–2 GB) → ~8–9 GB frei → passt. (FLUX ist auf 12 GB eh raus.) ## Anbindung: über den RVS, wie TTS/STT (kein IP-Pflegen) Die Gamebox ist ein anderer Host als das Brain. Statt direktem HTTP (IP/Port/ Firewall) läuft das LLM **über den RVS-Token-Room**, exakt wie Whisper/F5-TTS: - llama.cpp hört nur auf localhost der Gamebox. - Ein **dünner RVS-Adapter** daneben (Vorbild: whisper-/xtts-Bridge) verbindet sich mit dem RVS-Token, lauscht auf `llm_request`, ruft lokal llama-server, schickt `llm_response` (korreliert per requestId) zurück. - `rvs/server.js` `ALLOWED_TYPES` um `llm_request`, `llm_response` und (Phase 2) `llm_partial` erweitern. - Das Brain bekommt einen zweiten „Proxy" — nur über RVS statt direktem HTTP. ## Router-Logik im Brain Reihenfolge pro Turn (früh raus = schnell): - **Tier 0 — Fast-Path (existiert):** reine Steuerbefehle (Spotify, Licht) → Skill direkt, **kein LLM**. <1 s. - **Tier 1 — Lokal (Qwen3):** einfache Konversation, kurze Fakten, Smalltalk, Bestätigungen. Ziel <1 s. - **Tier 2 — Claude:** tief/technisch, Code, Tool-Use nötig, Pentest-Projekt, langer/komplexer Kontext. **Routing-Signal (heuristisch zuerst, deterministisch & schnell):** Nachrichtenlänge, Schlüsselwörter, ob ein Tool nötig scheint, Projekt-Kontext (Pentest-Projekt → immer Claude), Konversationstiefe. **Escalation statt perfekter Vorab-Klassifikation:** Das lokale Modell bekommt die Anweisung, bei Unsicherheit oder Tool-Bedarf **NICHT zu raten**, sondern zu eskalieren (z.B. Antwort `<>`). Das Brain routet den Turn dann an Claude. So sind Fehlklassifikationen billig — lieber einmal lokal→Claude als eine falsche lokale Antwort. ## Persona auf BEIDEN Modellen Das lokale Modell braucht ARIAs Identität, sonst bricht es aus der Rolle (gelernt aus dem `--system-prompt`-Debakel). Aber **schlanker**: - IDENTITY_SEED + Kern-Persona: ja. - Volles Memory / alle Skill-Schemas / Tool-Block: **nein** (Tier 1 macht keine Tools). Hält den lokalen Prompt klein → schnell. - Persona kommt lokal auch als echter System-Prompt (llama.cpp `system`-Rolle). ## Phasen - **B0 — Infra:** llama.cpp-Container + RVS-Adapter auf der Gamebox, `ALLOWED_TYPES`, `local_llm_chat()` im Brain. Isoliert testen („sag hallo"). - **B1 — Router:** Heuristik Tier-1/2 + Escalation, schlanke Persona lokal. Einfache Turns → lokal. Messen: Trefferquote & Latenz. - **B2 — Streaming/Voice:** `llm_partial` → TTS beginnt beim ersten Satz → der „live"-Sprung. **Hier den Gong-/Ohr-Re-Arm-Bug mit-fixen** (Barge-In, sauberes Re-Listen). - **B3 (optional):** dem lokalen Modell ein paar schnelle, sichere Tools geben. ## Offene Entscheidungen (für Stefan) 1. **Modell:** Qwen3 8B (Tool-Calling) — oder doch Mistral Small 3 7B (Speed)? 2. **Routing v1:** rein heuristisch + Escalation (empfohlen) — oder gleich ein Mini-Classifier? 3. **Tools lokal:** in v1 bewusst KEINE (alles Tool-artige → Claude) — ok? ## Folge-Baustein: Modell-Auswahl in ARIA Diagnostic (B0.5) Ziel: In Diagnostic ein Modell auswählen; ist es nicht da, lädt der Container es on-demand und aktiviert es. Spiegelt zwei bestehende Muster: den `whisperModel`-Hotswap (RVS-Config-Broadcast → Bridge hot-swapped) und die kuratierte Claude-Tier-Liste aus `models.json`. **Kernproblem:** `llama.cpp`-Server serviert **ein** Modell pro Prozess — „anderes aktivieren" = neu laden/swappen. **Lösung: `llama-swap`** (Proxy vor llama.cpp): kennt eine Liste von Modellen, lädt bei Anfrage das gewünschte on-demand (Download via `-hf` beim ersten Mal), swappt bei VRAM-Knappheit das alte raus. OpenAI-kompatibel — der llm-adapter zeigt statt auf `llama:8081` auf `llama-swap`. **Bausteine:** - `llama-swap`-Service in `xtts/docker-compose.yml` (ersetzt/ergänzt `llama`), Config mit den verfügbaren Modellen (Name → `-hf`-Command). - Kuratierte Liste `local_models.json` (analog `models.json`) — Diagnostic-UI liest sie, zeigt Dropdown „Lokales Modell". - Diagnostic → RVS-Config-Broadcast `localLlmModel` → llm-adapter setzt das `model`-Feld seiner llama-swap-Requests → swap/Download passiert automatisch. - Status zurück an Diagnostic (lädt / bereit / VRAM-OOM), analog whisper-Status. Bis dahin: **ein** Modell via `-hf` Auto-Download (B0, erledigt). Erst end-to-end grün, dann dieser Komfort-Layer. ## Nicht-Ziele - Kein echter Gemini-Live-Duplex-Klon (Text-Modell als Hirn). - FLUX bleibt optional/später (dickere GPU). Bild-Generierung separat als pluggbarer Provider (ChatGPT/DALL·E-Alternative) — eigenes Feature, nicht Teil B.