Files
cluster-knaster/docs/auftraege/2026-10-12-sprachmodelle-nex.md
T
Robert RappandClaude Opus 5.5 47816bda68
ci / test (push) Successful in 28s
plan: Task 3.1 erledigt, 3.2 vorbereitet; Sprach-Auftrag NEX als 6.2, HDD-Befund in 5.1
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>
2026-10-12 19:10:36 +02:00

7.5 KiB
Raw Blame History

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 ist gpu-pve52: Dort steckt nur die M4000, und Placement verteilt keine andere Rolle dorthin. Die P2000 bleiben für embed/rerank (pve44, pve46) und gpu-small (pve48). Die M4000 sind im Inventar disabled bis 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-de im Infra-LXC (infra, Task 5.2). Solange infra nicht 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) plus ufw in der VM.
  • Globale Vorgabe aus dem Plan passt: whisper-server auf Port 8178, nur von .29, stt.openai.base_url nur 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-whisper int8 oder int8_float32.

1. Spracherkennung (Pflicht)

  • Modell Whisper large-v3-turbo, Sprache fest de.
    • Empfehlung M4000: whisper.cpp whisper-server mit -m ggml-large-v3-turbo.bin -l de -bs 5 --convert --inference-path /v1/audio/transcriptions, ohne --print-realtime, --tmp-dir auf 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.
  • Schnittstelle: POST /v1/audio/transcriptions, multipart
    • Felder: file, model, language=de, response_format.
    • file muss 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.

2. Sprachausgabe (Pflicht Stufe 1, optional Stufe 2)

  • Stufe 1: Piper Deutsch, CPU reicht. Stimmen: de_DE-thorsten-high und 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_format muss können: mp3 (Standard), opus (im Ogg-Container), wav, flac, pcm (rohes int16, little-endian, mono; Sample-Rate im Header X-Audio-Sample-Rate oder in Content-Type: audio/pcm; rate=<Hz>).
    • Antwort möglichst gestreamt (chunked), damit die Wiedergabe früh beginnt.
  • 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) und opus.
  • Last: 2 Erkennungen gleichzeitig. Mit nvidia-smi prü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.