ops-LXC, vfio auf allen GPU-Knoten (Bildschirm danach schwarz), Templates 9044/9046/9048/9052, API-Benutzer tofu@pve. Auftrag Sprachmodelle mit Abgleich gegen den echten Cluster unter docs/auftraege/. Die 4-TB-HDD ist die Toshiba BACKUP und scheidet für den Cluster aus. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
7.5 KiB
Auftrag: Sprachmodelle (Spracherkennung + Sprachausgabe) für NEX auf dem knaster-Cluster
Eingang 12.10.2026 (vom NEX-Team, ohne Schlüssel). Ausführung nach Task 3.2 (GPU-VMs mit Treiber), gern durch einen Subagenten. Im Plan als Task 6.5 geführt.
Abgleich mit dem echten Cluster (Stand 12.10.2026, vor Ausführung lesen)
Der Auftrag geht von einem älteren Bild aus. Es gilt:
| Auftrag sagt | Wirklichkeit |
|---|---|
| 2 Knoten + QDevice | 5 Knoten (pve44, pve46, pve48, pve52, pve61), 5 Stimmen, kein QDevice |
| Knoten A 2× P2000, Knoten B 2× M4000, GPU per LXC oder VM | Eine Ubuntu-24.04-VM pro GPU-Knoten mit allen Karten (D2): gpu-pve44, gpu-pve46, gpu-pve48 je M4000 + P2000, gpu-pve52 nur M4000. Treiber R580 in der VM |
| Feste IP per DHCP-Reservierung | D5 ist zurückgestellt. Gäste laufen per DHCP, der Nutzer hat keinen Zugriff auf den DHCP-Server. Vor der Abnahme klären: Reservierung durch die DHCP-Verwaltung oder statische IP außerhalb des DHCP-Bereichs |
Daraus folgt für die Umsetzung:
- Erkennung: whisper.cpp (CUDA 12,
CMAKE_CUDA_ARCHITECTURES="52;61") auf einer M4000. Naheliegend istgpu-pve52: Dort steckt nur die M4000, und Placement verteilt keine andere Rolle dorthin. Die P2000 bleiben für embed/rerank (pve44, pve46) undgpu-small(pve48). Die M4000 sind im Inventardisabledbis zum Benchmark-Tag (Task 3.3); die Messwerte aus 4. Abnahme liefern genau diesen Benchmark für whisper und gehören in Task 3.3. - Ausgabe Stufe 1 (Piper, CPU): laut Registry
tts-deim Infra-LXC (infra, Task 5.2). Solangeinfranicht steht, als Container in derselben GPU-VM wie die Erkennung (CPU reicht). - Firewall „nur von 192.168.100.29“: Proxmox-Firewall an der Netzkarte der VM (
firewall=1, Regeln für 8178/8179) plusufwin der VM. - Globale Vorgabe aus dem Plan passt: whisper-server auf Port 8178, nur von
.29,stt.openai.base_urlnur als IP-Literal.
Auftrag (Originaltext)
NEX sind Hermes-Agenten auf appsrv08 (192.168.100.29). Sprache läuft dort: Hermes → nex-router → LiteLLM → Sprach-Backend. Das Backend ist austauschbar (Eintrag in LiteLLM). Der Dienst auf dem Cluster ist das Rückfall-Modell. Solange kein Cloud-Anbieter Guthaben hat, ist er der einzige aktive Weg. Die NEX-Seite trägt danach nur IP:Port und Modellnamen in LiteLLM ein. Gebraucht werden zwei OpenAI-kompatible HTTP-Dienste im internen Netz. Ein Dienst für beides ist auch in Ordnung.
Formate laut Hermes-Code: mp3 als Standard, Opus für Sprachnachrichten, rohes PCM mit Sample-Rate-Header für das Streaming.
Hardware und Grenzen
- Treiber R580, die letzte Serie für Maxwell/Pascal.
- faster-whisper/CTranslate2 laufen nicht auf CC 5.2. Auf der M4000 nur whisper.cpp, und zwar als CUDA-12-Build, nicht CUDA 13 (
-DGGML_CUDA=ON -DCMAKE_CUDA_ARCHITECTURES="52;61"). - PyTorch-Unterstützung für sm_50/sm_61 in aktuellen Wheels vorher prüfen (
python -c "import torch; print(torch.cuda.get_arch_list())"), nicht annehmen. Keine Tensor-Cores: bei faster-whisperint8oderint8_float32.
1. Spracherkennung (Pflicht)
- Modell Whisper large-v3-turbo, Sprache fest
de.- Empfehlung M4000: whisper.cpp
whisper-servermit-m ggml-large-v3-turbo.bin -l de -bs 5 --convert --inference-path /v1/audio/transcriptions, ohne--print-realtime,--tmp-dirauf tmpfs (z. B./run/nex-whisper). Nach dem Start einmal mit 1 s Stille aufwärmen. - Alternative P2000: speaches (faster-whisper) mit
deepdml/faster-whisper-large-v3-turbo-ct2,int8_float32. - Optional mitmessen:
primeline/whisper-large-v3-turbo-german.
- Empfehlung M4000: whisper.cpp
- Schnittstelle:
POST /v1/audio/transcriptions, multipart- Felder:
file,model,language=de,response_format. filemuss wav, mp3, ogg/opus, webm und m4a annehmen (Umwandlung mit ffmpeg).response_format:json→{"text": "…"},text,verbose_json(wenn möglich mit Wort-Wahrscheinlichkeiten).- Unbekannte Felder ignorieren, nicht mit Fehler antworten.
- Felder:
2. Sprachausgabe (Pflicht Stufe 1, optional Stufe 2)
- Stufe 1: Piper Deutsch, CPU reicht. Stimmen:
de_DE-thorsten-highund eine weibliche deutsche Stimme. Genauen Namen nennen. Server OpenAI-kompatibel, z. B. speaches (kann Piper) oder ein schlanker Wrapper. - Schnittstelle:
POST /v1/audio/speech- JSON-Body
{model, voice, input, response_format, speed}. response_formatmuss können:mp3(Standard),opus(im Ogg-Container),wav,flac,pcm(rohes int16, little-endian, mono; Sample-Rate im HeaderX-Audio-Sample-Rateoder inContent-Type: audio/pcm; rate=<Hz>).- Antwort möglichst gestreamt (chunked), damit die Wiedergabe früh beginnt.
- JSON-Body
- Stufe 2 (optional, GPU, nach PyTorch-Prüfung): eine natürlichere deutsche Stimme.
- Lizenz für kommerzielle Nutzung prüfen. Nach Stand des NEX-Teams sind XTTS-v2 (Coqui Public Model License) und die Gewichte von Fish Speech/OpenAudio nicht kommerziell.
- Chatterbox Multilingual (MIT) ist ein Kandidat.
- Kokoro hat nach diesem Stand keine deutsche Stimme. Prüfen, nicht voraussetzen.
3. Für beide Dienste
GET /health→ 200.- Feste IP in
192.168.100.0/24(siehe Abgleich oben). Ports zum Beispiel 8178 (Erkennung) und 8179 (Ausgabe). - Firewall: Zugriff nur von 192.168.100.29. LiteLLM läuft dort in einem Bridge-Netz und erscheint mit der Host-IP.
- Kein API-Key nötig. Erzwingt der Server einen, einen festen Dummy-Wert nennen (kein Geheimnis).
- Autostart nach Neustart (systemd oder Docker
restart: unless-stopped), Energiesparen aus, Sicherheitsupdates. - Datenschutz: keine Ablage von Audio oder Text; Temp-Dateien nur im RAM, alte regelmäßig löschen; keine Transkripte oder vorgelesenen Texte in Logs.
4. Abnahme
Von appsrv08 aus prüfen, Testaudio ohne Kundendaten, danach löschen.
- Erkennung:
curl -s -w ' %{time_total}s\n' -F file=@t10.wav -F model=whisper -F language=de -F response_format=json http://IP:8178/v1/audio/transcriptions- Text muss deutsch und plausibel sein.
- Median aus 3 Läufen: 10 s Audio ≤ 4 s (Ziel ≤ 3 s), 60 s Audio ≤ 12 s. Den ersten Aufruf getrennt notieren.
- Ausgabe:
curl -s -o t.mp3 -w ' TTFB %{time_starttransfer}s gesamt %{time_total}s\n' -H 'Content-Type: application/json' -d '{"model":"piper","voice":"de_DE-thorsten-high","input":"Guten Tag, hier ist Ihr NEX-Assistent. Die Baubesprechung in Haslach ist am vierten November.","response_format":"mp3"}' http://IP:8179/v1/audio/speech- Ergebnis abspielbar, Zeit bis zum ersten Byte möglichst ≤ 1 s.
- Dasselbe mit
pcm(Sample-Rate-Header prüfen) undopus.
- Last: 2 Erkennungen gleichzeitig. Mit
nvidia-smiprüfen, dass GPU-Last und VRAM steigen.
5. Rückmeldung (genau so)
Je Dienst: Basis-URL (IP:Port) · Knoten und GPU · Software mit Version oder Image-Digest · Modellname(n), wie im Feld model erwartet · Stimmen-IDs · unterstützte response_format · PCM-Sample-Rate · Messwerte (Median, erster Aufruf, VRAM, RAM) · Autostart nach Neustart getestet (ja/nein) · Auffälligkeiten.
Gegenseite (NEX, zur Information)
Die Agenten fragen nur noch neutrale Namen an: nex-stt für die Erkennung, nex-tts für die Ausgabe. Welches Backend dahinter antwortet und in welcher Reihenfolge, legt allein LiteLLM fest: heute das Cluster, später ein Cloud-Anbieter davor und das Cluster als Rückfall. nex-router 0.2.3 wird um die Sprachausgabe (gestreamt) erweitert. Nach der Rückmeldung trägt das NEX-Team die Endpunkte in LiteLLM ein und testet die Kette. Live erst mit dem neuen Router-Image.