Replace vision hotswap with native multimodal profiles

This commit is contained in:
Mikei386
2026-08-20 14:24:56 +02:00
parent 8a45a0d851
commit cb07779f5a
19 changed files with 169 additions and 719 deletions
+18 -51
View File
@@ -11,10 +11,10 @@ Clients (Open WebUI, Hermes, Apps)
|
v
AI Profile Router :8081
|-- qwen-fast (72K, maximale Geschwindigkeit)
|-- qwen-fast (76.8K, maximale Geschwindigkeit)
|-- qwen-medium (92K, reines IQ4_XS)
|-- qwen-long (128K, CPU-Offload)
|-- Vision-Hotswap
|-- integrierte Qwen-Vision (kein Hotswap)
|-- lokale Bildgenerierung
|-- Whisper STT
`-- XTTS TTS
@@ -61,8 +61,8 @@ llama.cpp :8080 + profilabhängige MCP-Server
Kleiner OpenAI-kompatibler Proxy (Python, nur Standardbibliothek) vor einem
lokalen llama.cpp-Server. Er leitet normale OpenAI-Requests transparent
weiter (Streaming, Tool Calls, JSON), schaltet zwischen drei festen
llama.cpp-Profilen um, orchestriert lokale Bildgenerierung mit
weiter (Streaming, Tool Calls, JSON und Bilder), schaltet zwischen drei festen
multimodalen llama.cpp-Profilen um, orchestriert lokale Bildgenerierung mit
FLUX.2 [klein] 4B Base (GPU-Hotswap: Qwen stoppen → FLUX laden → Bild
→ FLUX entladen → Qwen wiederherstellen) und stellt lokale deutsche
Sprachausgabe bereit (XTTS-v2, CPU-only, OpenAI-kompatibel).
@@ -84,7 +84,7 @@ Sprachausgabe bereit (XTTS-v2, CPU-only, OpenAI-kompatibel).
| Profil | Modell | Kontext |
|---|---|---|
| `fast` | `qwen-fast` | 73728 |
| `fast` | `qwen-fast` | 76800 |
| `medium` | `qwen-medium` | 94208 |
| `long` | `qwen-long` | 131072 |
@@ -105,7 +105,6 @@ Sprachausgabe bereit (XTTS-v2, CPU-only, OpenAI-kompatibel).
| `POST /v1/audio/transcriptions` | Deutsche Spracherkennung (whisper.cpp, OpenAI-kompatibel) |
| `GET /v1/audio/models` | Verfügbare Audio-Modelle (STT + TTS) |
| `GET /v1/audio/voices` | Verfügbare TTS-Stimmen |
| `POST /vision/test` | Direkter Vision-Test (Bild + Frage → Q3-Analyse) |
| alles andere | Transparente Weiterleitung an llama.cpp |
Bis auf `GET /health` und `GET /ready` benötigen alle Endpunkte einen
@@ -243,41 +242,19 @@ VRAM-Check).
Das Venv liegt unter `/opt/mike-ai/ai-profile-router/venv/` und wird von
`install.sh` automatisch angelegt/aktualisiert.
## Vision (Q3 "Augen")
## Integrierte Vision
Bilder in `POST /v1/chat/completions` werden automatisch analysiert, ohne
dass das Hauptmodell (Fast/Medium/Long) ein Vision-Modell braucht:
Alle drei Qwen-Profile laden denselben BF16-Multimodalprojektor direkt beim
Start. Der Projektor bleibt mit `--no-mmproj-offload` im System-RAM und
verbraucht dadurch keinen zusätzlichen VRAM. Bilder in
`POST /v1/chat/completions` werden nach Größen- und URL-Prüfung unverändert an
das aktive Qwen-Profil weitergereicht. Es gibt kein separates Q3-Modell, keinen
Vision-Port, keinen Analyse-Cache und keinen Modellwechsel mehr. Folgefragen
bleiben dadurch im normalen multimodalen Chatverlauf.
1. **Neues Bild** (in der letzten User-Message, noch nicht analysiert):
Der Router entlädt das Hauptprofil, startet kurzzeitig einen
Q3-Vision-Server (llama.cpp + mmproj, Port `VISION_PORT`), analysiert
das Bild und stellt das Hauptprofil wieder her. Die Analyse wird im
internen Cache (keyed by Bild-Hash) gespeichert.
2. **Finale Antwort**: Das (wiederhergestellte) Hauptmodell erzeugt die
sichtbare Antwort. Die Vision-Analyse wird als interne User-Message
injiziert – sie erscheint **nie** als Assistant-Turn in Open WebUI.
3. **Folgefragen**: Open WebUI schickt den multimodalen Verlauf erneut.
Der Router ersetzt **alle** Bild-Parts durch die gecachte Analyse
(klar gekennzeichnet) und entfernt Base64/URLs komplett – das
Nicht-Vision-Hauptmodell bekommt also keine Bilddaten mehr
(kein `image input is not supported`). Bereits analysierte Bilder
triggern **keinen** neuen Hotswap (Cache-Treffer).
- **Zentrale GPU-Lock**: Vision und FLUX schließen sich gegenseitig aus
(kein gleichzeitiges Modell-Laden).
- **Fehlerbehandlung**: Bei jedem Fehler wird das Hauptprofil
wiederhergestellt; `finally` dient nur als Cleanup-Sicherung.
- **Test**: `POST /vision/test` mit `{"image_url": "...", "question": "..."}`
liefert die Analyse direkt (ohne finale Hauptmodell-Antwort).
### Verhalten während eines Vision-Jobs
- `GET /status` → `vision.phase` (`idle`, `stopping-main`,
`loading-vision`, `analyzing`, `unloading-vision`, `restoring-main`)
und `vision.analysis_cache_size`.
- `/v1/streams/lookup` antwortet fail-fast (`[]`), statt zu blockieren.
- Timing-Log: `Vision-Timing: main_unload=… vision_load=… vision_infer=…
vision_unload=… main_restore=… | Gesamt … s`.
Externe Bild-URLs sind standardmäßig gesperrt; Data-URLs dürfen dekodiert
höchstens 20 MiB groß sein. Die FLUX-Bildgenerierung bleibt ein separater
GPU-Hotswap und ist von dieser Änderung nicht betroffen.
## Sprachausgabe (XTTS-v2, CPU-only)
@@ -549,18 +526,8 @@ Die Installation ist idempotent (Update = erneut ausführen).
| `TTS_WORKER_URL` | `http://127.0.0.1:8085` | TTS-Worker (Router-Seite) |
| `TTS_TIMEOUT` | `300` | Timeout pro Synthese (s) |
| `TTS_CONNECT_TIMEOUT` | `5` | Connect-Timeout TTS-Worker (s) |
| `VISION_MODEL` | `/opt/mike-ai/models/qwen3.8-27b/Qwen3.8-27B-Q3_K_M.gguf` | Q3-Vision-Modell |
| `VISION_MMPROJ` | `/opt/mike-ai/models/qwen3.8-27b-nvfp4/mmproj-BF16.gguf` | Vision-Projektor |
| `VISION_CTX` | `32768` | Kontext des Vision-Servers |
| `VISION_PORT` | `8086` | Port des Vision-Servers (nur lokal) |
| `VISION_LOAD_TIMEOUT` | `300` | Warten auf Vision-Ready (s) |
| `VISION_INFER_TIMEOUT` | `300` | Timeout pro Vision-Inferenz (s) |
| `VISION_UNLOAD_TIMEOUT` | `120` | Warten auf VRAM-Freiheit (s) |
| `VISION_MAX_TOKENS` | `4096` | Max. Tokens der Vision-Analyse |
| `VISION_CACHE_MAX` | `64` | Größe des Analyse-Caches (LRU) |
| `VISION_MAX_IMAGE_BYTES` | `20971520` | maximales dekodiertes Bild (20 MiB) |
| `VISION_ALLOW_REMOTE_URLS` | `false` | externe Bild-URLs; standardmäßig SSRF-sicher aus |
| `VISION_LOG` | `/opt/mike-ai/ai-profile-router/vision_server.log` | Vision-Server-Log |
| `CHAT_IMAGE_MAX_BYTES` | `20971520` | maximales dekodiertes Chatbild (20 MiB) |
| `CHAT_IMAGE_ALLOW_REMOTE_URLS` | `false` | externe Bild-URLs; standardmäßig SSRF-sicher aus |
TTS-Worker (`mike-ai-xtts.service`):