A/B-Aufbau fuer Qwen3.5-4B: Messstrecke und Konvertierungs-Kit

lab/ab-llm.mjs vergleicht zwei LLMs ueber reanalyze-llm (ohne
Neu-Diarisierung), mit snapshot/restore der Originalanalysen und einem
Report aus Tabelle plus Volltext-Vergleich.

tools/rkllm-qwen35/ konvertiert Qwen3.5-4B auf dem PC mit
rkllm-toolkit 1.3.0 (muss zur Board-Runtime passen), Parameter
identisch zum produktiven Modell: w8a8_g128, 3 NPU-Kerne,
max_context 16384.

Doku: Changelog 2026-09-29 (2) mit Recherchestand, Sicherung und
GOTCHAs, plus neuer Abschnitt "Modellwechsel und A/B-Tests" in
Kapitel 05 samt Mermaid-Ablauf.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-29 10:55:47 +02:00
co-authored by Claude Opus 5
parent fae5a9e5d0
commit e9ba48224e
7 changed files with 441 additions and 0 deletions
+34
View File
@@ -356,3 +356,37 @@ frei** statt 100 MB.
**Preis:** die nächste Analyse lädt rkllm neu. Der Kurz-Clip-Pfad verliert damit seinen „rkllm bleibt
warm"-Vorteil (Kap. 03) — dafür ist die Analyse verlässlich statt schnell-aber-manchmal-tot.
## Modellwechsel und A/B-Tests
Das aktive Modell steht in **einer** systemd-Zeile:
```bash
cat /etc/systemd/system/callrec.service.d/gemma-model.conf
# [Service]
# Environment=RKLLM_MODEL=/opt/rkllm-models/qwen3-4b-w8a8g128-16k.rkllm
systemctl daemon-reload && systemctl restart callrec
```
`llm.js:10` liest `process.env.RKLLM_MODEL` (Fallback: das alte qwen2.5-3b). Ein Wechsel ist damit
umkehrbar, solange die alte `.rkllm` liegen bleibt. **Vor jedem Restart prüfen, ob eine Analyse läuft**
— ein Restart killt sie ersatzlos.
Gemessen wird mit `lab/ab-llm.mjs` (seit 2026-09-29). Es ruft `reanalyze-llm` auf, also **ohne**
Neu-Diarisierung: gleiches Transkript, gleiche Sprecher, gleiche Kontextnotiz — der einzige Unterschied
zwischen zwei Läufen ist das Modell. `snapshot` sichert die Originalanalysen vorher, `restore` schreibt
sie zurück, `report` legt Tabelle und Volltext-Vergleich nebeneinander.
```mermaid
flowchart LR
SNAP["snapshot &lt;ids&gt;<br/>Originalanalysen sichern"] --> RUNA["run A<br/>aktuelles Modell"]
RUNA --> SWAP["gemma-model.conf umstellen<br/>daemon-reload + restart"]
SWAP --> RUNB["run B<br/>neues Modell"]
RUNB --> REP["report A B<br/>Dauer / Laenge / Todos + Volltext"]
REP --> DEC{"besser?"}
DEC -->|ja| KEEP["Drop-in bleibt<br/>altes .rkllm liegt als Rueckweg"]
DEC -->|nein| BACK["Drop-in zurueck<br/>restore schreibt Analysen zurueck"]
```
Die Konvertierung eines neuen Modells passiert **nicht** auf dem Board (kein CUDA), sondern auf dem PC
mit `tools/rkllm-qwen35/` — rkllm-toolkit-Version muss exakt zur Runtime auf dem Board passen.
+68
View File
@@ -3,6 +3,74 @@
Chronik der Entwicklungsschritte. **Regel: jede zukünftige Änderung bekommt hier einen Eintrag** (Datum,
Was, Warum, betroffene Dateien/Backups).
## 2026-09-29 (2) — A/B-Aufbau Qwen3.5-4B (Sicherung, Messstrecke, Konvertierungs-Kit)
**Anlass:** Recherche zur Frage, ob es inzwischen ein besseres LLM gibt als das produktive
Qwen3-4B-Instruct-2507. Ergebnis: **Qwen3.5** (02.03.2026, Apache 2.0, Größen 0,8/2/4/9B, hybride
Gated-DeltaNet-Architektur, 262k Kontext, 201 Sprachen) ist der ernsthafte Kandidat — im
Artificial-Analysis-Index springt die 4B von 18 auf 27. **rknn-llm v1.3.0** (17.06.2026) hat die
Unterstützung dafür gebracht, und genau diese Version läuft bereits auf dem Board
(`RKLLM SDK 1.3.0 | build 82bf4aa8e 2026-06-16`, NPU-Treiber v0.9.8) — **kein Runtime-Upgrade nötig.**
### Sicherung vor dem Test
Gezielte Sicherung nach `D:\Vibe Coding\_Spielplatz\Aime-Backup-2026-09-29` (nicht im Repo):
`/opt/callrec` ohne `recordings/`+`models/` (14,7 MB), `/etc/systemd/system` + `sudoers.d` + Netz/Host
(7,4 KB), WirePlumber/PipeWire-Drop-ins (1,5 KB), MariaDB-Dump (8,0 MB), Zustandsbericht mit den md5
aller `.rkllm`-Modelle. Alle Prüfsummen nach der Übertragung verifiziert. Aufnahmen (5,4 GB) und Modelle
(14 GB) bewusst nicht mitgezogen — die liegen unverändert auf dem Board, die Vollsicherung des rootfs
ist die vom 2026-08-03.
### Warum der Wechsel billig rückgängig zu machen ist
Das aktive Modell hängt an einer einzigen systemd-Zeile,
`/etc/systemd/system/callrec.service.d/gemma-model.conf` → `Environment=RKLLM_MODEL=...`
(`llm.js:10` liest `process.env.RKLLM_MODEL`). Zurückschalten = Pfad tauschen, `daemon-reload`,
`systemctl restart callrec`. Die alten `.rkllm` bleiben liegen.
### Neu: Messstrecke `lab/ab-llm.mjs`
Der Vergleich läuft über `POST /api/recordings/:id/reanalyze-llm` — **ohne** Neu-Diarisierung, also
gleiches Transkript, gleiche Sprecher, gleiche Kontextnotiz. Gemessen wird nur das Modell.
```
node lab/ab-llm.mjs snapshot 86 123 114 # Originalanalysen sichern (PFLICHT, reanalyze ueberschreibt)
node lab/ab-llm.mjs run qwen3 86 123 114 # Baseline mit dem aktuellen Modell
# ... Modell umstellen, callrec neu starten ...
node lab/ab-llm.mjs run qwen35 86 123 114
node lab/ab-llm.mjs report qwen3 qwen35 # Tabelle + Volltext-Vergleich als Markdown
node lab/ab-llm.mjs restore # Originalanalysen zurueckschreiben
```
Testfälle bewusst über die Pfadgrenzen gelegt: **#86** (8,4k Zeichen, kurzer Whole-Pass), **#123**
(19,3k — die Größenordnung, an der Gemma im Juli-A/B die Gewichtung verlor), **#114** (34,8k, also
über `WHOLE_MAX_CHARS`=32000 → gestückelter Sektions-Pfad).
### Neu: `tools/rkllm-qwen35/` (Konvertierung auf dem PC)
`Dockerfile` (CUDA 12.4 + torch 2.6.0-cu124 + rkllm-toolkit **1.3.0**, Version muss zur Board-Runtime
passen), `convert_qwen35.py` und `run_convert.ps1`. Parameter identisch zum produktiven Modell, damit der
A/B das Modell misst und nicht die Konvertierung: `w8a8_g128`, 3 NPU-Kerne, `max_context=16384`
(Toolkit-Obergrenze; die Runtime nutzt davon 12288, `rkllm_server.cpp:52`).
**GOTCHAs, festgehalten:**
- `run_convert.ps1` gehört in die **PowerShell**, nicht in die Git-Bash — die schreibt Docker-Mount-Pfade
um (`/data` → `C:/Program Files/Git/data`). Gleiche Falle wie bei der Qwen3-Konvertierung im Juli.
- torch wird im Dockerfile **vor** den übrigen Requirements und explizit als cu124-Rad installiert, und
`torch`/`torchvision` werden aus `requirements.txt` gefiltert — sonst zieht pip die CPU-Räder nach und
die Quantisierung läuft stundenlang auf der CPU.
- `auto_gptq` darf fehlschlagen (nur für den GPTQ-Pfad nötig, nicht für w8a8).
- Thinking ist kein Problem: Qwen3.5 denkt per Default, aber `rkllm_server.cpp:89` setzt bereits
`in.enable_thinking = false`.
**Kalibrierung:** `make_calib.py` baut aus echten deutschen Transkripten einen Kalibriersatz
(`[{"input":..,"target":..}]`, 64 Ausschnitte à ~1400 Zeichen). Der Satz bleibt bewusst **auf dem Board**
(`/tmp/calib-de.json`) — Gesprächsinhalte wandern nicht auf den PC. Wer ihn nutzen will, konvertiert auf
dem Board oder kopiert ihn bewusst; ohne `--dataset` nimmt das Toolkit seinen eingebauten Datensatz.
**Stand:** Baseline-Lauf `qwen3` gestartet, Modell noch nicht konvertiert — Ergebnis folgt in einem
eigenen Eintrag.
## 2026-09-29 — Aufnahmezeitpunkt in der Detailansicht
**Wunsch:** „Wenn man eine Aufzeichnung geöffnet hat, soll neben der Analysezeit auch das Datum und