GNAI-008: Planung für LLM-Auswahl und Parameter.

This commit is contained in:
2026-09-21 15:23:08 +02:00
parent 83668557e5
commit e9815adf25
6 changed files with 944 additions and 18 deletions
+5 -1
View File
@@ -1,6 +1,6 @@
# Ghostnet.AI – Dokumentationsindex und Projektstand
**Stand:** 2026-09-20
**Stand:** 2026-09-21
**Status:** Revisionen zusammengeführt; Sicherheitsumsetzung und technische Endabnahme offen
## 1. Dokumente und Zielgruppen
@@ -27,6 +27,8 @@
| [Bereichsindex](ai/README.md) | Einstieg in die KI-spezifische Dokumentation |
| [GNAI-003-INFRA_Architecture.md](ai/GNAI-003-INFRA_Architecture.md) | Gesamtzielarchitektur und Inventar des KI-Stacks; Intermediate IT |
| [GNAI-007-PLAN_Ansible-Deployment.md](ai/GNAI-007-PLAN_Ansible-Deployment.md) | nicht finaler Arbeitsentwurf zum Ansible-/Gitea-Deployment und zur geplanten Folgedokumentation; Infrastrukturadministratoren und Mitwirkende |
| [GNAI-008-PLAN_Llama-Model-Evaluation.md](ai/GNAI-008-PLAN_Llama-Model-Evaluation.md) | nicht finaler A/B- und Abnahmeplan für Swift, Unsloth, Kontext und MTP; KI-Administratoren und Tester |
| [GNAI-009-TECH_Llama-Serving.md](ai/GNAI-009-TECH_Llama-Serving.md) | technische Sollkonfiguration für Modellartefakte, rootless Quadlet, ROCm und `llama-server`; Infrastrukturadministratoren |
### Video-Encoding und Automatisierung
@@ -65,6 +67,8 @@ Die Rolle `amd_gpu_access` bestätigte am 20.09.2026 zwei Sapphire-Navi-21-Gerä
Das getrennte Playbook `verify-rocm-container.yml` lud am 20.09.2026 für `gnai-testing` den offiziellen `llama.cpp`-ROCm-Build `b11058` als unveränderliches amd64-Manifest `sha256:b429b8be10d3d0353a09c98f4ab840fe516f779858a28f9fd4e5bdf10bc63cb4`. Mit `/dev/kfd`, beiden Render-Nodes und `keep-groups` meldete `rocminfo` genau zwei `gfx1030`-Agents; `llama-server --list-devices` meldete `ROCm0` und `ROCm1` als Radeon RX 6900 XT. Der abschließende Lauf endete mit `ok=33 changed=0 unreachable=0 failed=0`. Die Probecontainer wurden entfernt; dauerhafter Container-, Modell- und Inferenzbetrieb sind damit noch nicht abgenommen.
Am 21.09.2026 wurden die Modellrecherche und die daraus abgeleitete Sollkonfiguration in GNAI-008 und GNAI-009 persistiert. Installiert werden sollen Swift-Qwen3.8-27B Q6_K und Unsloth Qwen3.8-27B UD-Q6_K, jeweils mit Q8-K/V, einem Zielkontext von 131.072 Token, einem Slot und zunächst ohne Vision-Projektor oder MTP. Revisionen und SHA-256 beider Artefakte sind festgehalten. Jedes Modell erhält ein eigenes Quadlet; systemd schließt deren gleichzeitigen Betrieb aus und führt den Wechsel als Stop vor Start aus. Der kontrollierte A/B-Test verwendet zunächst `xhigh` für beide Modelle; danach folgt Swift `xhigh` gegen Unsloth `medium`. Dies ist eine Planungsentscheidung und noch kein Nachweis für Modelldownload, 128k-Betrieb oder Inferenz.
## 3. Sicherheitsbefunde mit Priorität
| Befund | dokumentiertes Verfahren / Status |
+34 -15
View File
@@ -2,12 +2,12 @@
**Dokumenten-ID:** GNAI-007-PLAN
**Titel:** Ansible-Deployment für den KI-Server – Planungsstand
**Stand:** 2026-09-20
**Stand:** 2026-09-21
**Status:** Nicht finaler Arbeitsentwurf zur Persistierung des aktuellen Planungsstands
**Referenzen:** [Projektstand](../GNAI-000-DOC_Index.md), [Zielarchitektur](GNAI-003-INFRA_Architecture.md), [Zugriffskonzept](../platform/GNAI-004-SEC_Access-Control.md)
**Referenzen:** [Projektstand](../GNAI-000-DOC_Index.md), [Zielarchitektur](GNAI-003-INFRA_Architecture.md), [Modellbewertung](GNAI-008-PLAN_Llama-Model-Evaluation.md), [llama.cpp-Sollkonfiguration](GNAI-009-TECH_Llama-Serving.md), [Zugriffskonzept](../platform/GNAI-004-SEC_Access-Control.md)
> **Abgrenzung:** Dieses Dokument hält die Ergebnisse der am 19.09.2026
> begonnenen und am 20.09.2026 fortgeschriebenen Planungssession fest. Es ist
> begonnenen und bis zum 21.09.2026 fortgeschriebenen Planungssession fest. Es ist
> weder eine freigegebene technische Spezifikation noch
> eine Installationsanleitung oder ein Nachweis über bereits umgesetzte
> Komponenten. Entscheidungen, die noch geprüft oder bestätigt werden müssen,
@@ -31,6 +31,9 @@
| 2026-09-20 | 0.10 | spektr / Codex | ROCm als Backend für zwei RX 6900 XT, initialen `llama.cpp`-Modellstand und Layer-Split mit gleicher GPU-Gewichtung festgehalten |
| 2026-09-20 | 0.11 | spektr / Codex | AMD-Gerätezugriff für beide rootless KI-Konten implementiert, angewendet und idempotent geprüft |
| 2026-09-20 | 0.12 | spektr / Codex | gepinnten rootless ROCm-Probelauf für Testing implementiert; zwei `gfx1030`-Agents und zwei `llama.cpp`-ROCm-Geräte nachgewiesen |
| 2026-09-21 | 0.13 | spektr / Codex | Swift-Qwen3.8 Q6_K mit 128k und `xhigh` als Testing-Kandidat übernommen; Modellbewertung und technische Sollkonfiguration ausgelagert |
| 2026-09-21 | 0.14 | spektr / Codex | Unsloth UD-Q6_K als zweites installiertes 128k-Profil und A/B-Kandidat festgelegt |
| 2026-09-21 | 0.15 | spektr / Codex | je Modell ein festes, gegenseitig ausgeschlossenes Quadlet vorgesehen und dynamischen llama.cpp-Router zurückgestellt |
---
@@ -417,24 +420,38 @@ Abweichungen als rootless Quadlet erzeugt:
SELinux-Konfiguration dies erfordert. Für den dokumentierten Debian-Host
wird es nicht vorsorglich gesetzt.
Der erste Testing-Modellstand verwendet vorbehaltlich Artefakt- und
Checksum-Prüfung:
Die ausführliche Kandidatenbewertung steht in
[GNAI-008-PLAN](GNAI-008-PLAN_Llama-Model-Evaluation.md), die technische
Sollkonfiguration einschließlich revisionsgebundener Downloadquelle und
SHA-256 in [GNAI-009-TECH](GNAI-009-TECH_Llama-Serving.md). Der bevorzugte
erste Testing-Kandidat ist:
| Parameter | Ausgangswert |
| --- | --- |
| Modelldatei | `Qwen3.8-27B-UD-IQ4_XS.gguf` |
| API-Alias | `qwen3.8-27b` |
| Kontext | 51.200 Token |
| Modelldatei | `Swift-Qwen3.8-27B-Q6_K.gguf` |
| API-Alias | `swift-qwen3.8-27b-q6k` |
| Kontext | 131.072 Token; Inbetriebnahme zunächst mit 65.536 |
| parallele Slots | 1 |
| maximale Ausgabe | 4.096 Token |
| maximale Ausgabe | zunächst 32.768 Token; gesonderter 65.536-Token-Test |
| GPU-Layer | alle |
| Flash Attention | aktiviert |
| K-/V-KV-Cache | jeweils `q8_0` |
| Reasoning Effort | `medium` |
| Reasoning Effort | `xhigh`, ohne kurzen Reasoning-Cap |
| MTP | zunächst deaktiviert; spätere A/B-Messung mit `n-max=2` |
| Vision-Projektor | zunächst nicht geladen |
Samplingwerte und Chat-Template-Parameter gehören zum Modellprofil und nicht
zu allgemeinen Rollendefaults. Dadurch können andere Modelle später eigene
geprüfte Profile verwenden, ohne die gemeinsame `llama_cpp`-Rolle zu ändern.
Zusätzlich wird `Qwen3.8-27B-UD-Q6_K.gguf` aus dem revisionsgebundenen
Unsloth-Repository installiert. Es läuft ebenfalls mit 131.072 Token Kontext.
Ein kontrollierter A/B-Test verwendet für beide Kandidaten `xhigh`; ein
zweiter Vergleich stellt Swift `xhigh` dem vorgesehenen Unsloth-`medium`-
Praxisprofil gegenüber. Beide Dateien liegen auf dem Host, aber immer nur ein
Modell wird in den VRAM geladen. Jedes Modell erhält ein eigenes festes
Testing-Quadlet; der Wechsel stoppt die aktive Unit vollständig, bevor die
andere startet. Der im gepinnten Build vorhandene dynamische `llama.cpp`-
Router-Modus bleibt für die erste Ausbaustufe bewusst zurückgestellt.
Für die beiden gleich großen GPUs wird zunächst
`--split-mode layer --tensor-split 1,1` festgelegt. Der Layer-Split minimiert
@@ -451,7 +468,7 @@ Der rootless Container-Probelauf hat inzwischen zwei `gfx1030`-Agents sowie
Start muss ein begrenzter Modelltest noch die Device-Reihenfolge und die
tatsächliche 1:1-Verteilung in den `llama.cpp`-Startlogs bestätigen. Zusätzlich
werden Prompt-Verarbeitung, Token-Generierung, VRAM-Nutzung und Stabilität bei
51.200 Token Kontext gemessen. Der 1:1-Wert ist erst nach diesem Test ein
131.072 Token Kontext gemessen. Der 1:1-Wert ist erst nach diesem Test ein
abgenommener Betriebsparameter.
---
@@ -873,7 +890,7 @@ Store. Modellladen, Layer-Verteilung und Inferenz wurden noch nicht geprüft.
## 15. Abschlussgrenze dieses Entwurfs
Mit Version 0.12 sind der aktuelle Planungsstand, der ausdrücklich begrenzte
Mit Version 0.15 sind der aktuelle Planungsstand, der ausdrücklich begrenzte
Ansible-Preflight, der verifizierte Deployment-Account und die angewendete
minimale Host-Baseline, die Podman-/Quadlet-Grundruntime und die getrennten
Workload-Konten, deren begrenzter AMD-Gerätezugriff sowie der rootless
@@ -892,6 +909,8 @@ Insbesondere wurden noch nicht:
- die geplante Deploymentkette technisch abgenommen.
Der nächste technische Schritt ist die `llama.cpp`-Rolle für Testing. Sie soll
das gepinnte Image als rootless Quadlet betreiben, das initiale Modell mit
geprüfter Checksumme einbinden und den vorgesehenen Layer-Split sowie eine
reale Inferenz abnehmen. Darauf baut anschließend LiteLLM auf.
das gepinnte Image als rootless Quadlet betreiben, beide festgelegten Modelle
mit geprüften Checksummen bereitstellen und jeweils einzeln mit dem
vorgesehenen Layer-Split und realer Inferenz abnehmen. Dafür werden zwei feste,
gegenseitig ausgeschlossene Quadlets aus derselben Rollenlogik erzeugt. Danach
folgt die reproduzierbare A/B-Serie; darauf baut anschließend LiteLLM auf.
@@ -0,0 +1,343 @@
# Arbeitsentwurf
**Dokumenten-ID:** GNAI-008-PLAN
**Titel:** Modell- und Laufzeitbewertung für `llama.cpp`
**Stand:** 2026-09-21
**Status:** Nicht finaler Evaluierungsplan; keine Production-Freigabe
**Referenzen:** [Ansible-Deployment](GNAI-007-PLAN_Ansible-Deployment.md), [technische Sollkonfiguration](GNAI-009-TECH_Llama-Serving.md), [Zielarchitektur](GNAI-003-INFRA_Architecture.md)
> Dieses Dokument persistiert die Modellrecherche und legt fest, wie daraus
> eine belastbare Entscheidung für den KI-Server entsteht. Veröffentlichte
> Benchmarks, Community-Berichte und lokale Abnahmetests werden getrennt
> bewertet. Ein hier genannter Kandidat ist erst nach erfolgreicher lokaler
> Abnahme für Production freigegeben.
---
## Änderungsverlauf
| Datum | Version | Autor | Beschreibung |
| --- | --- | --- | --- |
| 2026-09-21 | 0.3 | spektr / Codex | feste, gegenseitig ausgeschlossene Quadlet-Unit je Modell als Umschaltverfahren festgelegt |
| 2026-09-21 | 0.2 | spektr / Codex | Unsloth Qwen3.8 UD-Q6_K als verbindlichen zweiten 128k-Kandidaten festgelegt und kontrollierten A/B-Test ergänzt |
| 2026-09-21 | 0.1 | spektr / Codex | Swift-Qwen3.8, Q6_K, Reasoning, Kontext, MTP und lokales Vergleichsverfahren als ersten Evaluierungsstand aufgenommen |
---
## 1. Ziel
Gesucht wird ein Modellprofil für Coding-, Tool- und längere agentische
Aufgaben auf zwei Radeon RX 6900 XT mit zusammen 32 GiB VRAM. Das Profil soll:
- komplexe Aufgaben mit ausreichend langem Reasoning bearbeiten können;
- unnötige Reasoning-Schleifen reduzieren;
- Tool Calls und strukturierte Ausgaben zuverlässig erzeugen;
- mindestens 128 KiToken Kontext als Zielkonfiguration unterstützen;
- vollständig über beide GPUs mit ROCm betrieben werden;
- durch unveränderliche Modell- und Containerartefakte reproduzierbar sein;
- Swift und Unsloth gleichzeitig im Modellbestand vorhalten, aber für Tests
jeweils nur ein Modell in den VRAM laden;
- ohne Modellwechsel zwischen Testing und Production übertragbar sein; und
- später gegen neue Swift-, Base- oder Dynamic-Quantisierungen austauschbar
bleiben.
Die Entscheidung wird anhand realer Aufgaben getroffen. Herstellerbenchmarks
dienen als Kandidatenauswahl, ersetzen aber nicht die lokale Abnahme.
## 2. Bewerteter Quellenstand
### 2.1 Qwen3.8-27B
Die [Qwen-Modellkarte](https://huggingface.co/Qwen/Qwen3.8-27B) nennt für das
27B-Modell 64 Blöcke, davon 16 Full-Attention-Blöcke, einen nativen Kontext von
262.144 Token und ein trainiertes Multi-Token-Prediction-Head. Thinking ist
standardmäßig aktiv. Qwen empfiehlt für Thinking `temperature=1.0`,
`top_p=0.95`, `top_k=20`, `min_p=0.0`, `presence_penalty=0.0` und
`repetition_penalty=1.0`.
Qwen unterstützt `xhigh`, `medium` und `low` als Reasoning-Stufen. Die
Modellkarte warnt ausdrücklich, dass ein niedrigeres Reasoning-Niveau bei
mehrstufigen Agentenaufgaben zu Fehlversuchen und Wiederholungen führen kann
und dadurch nicht zwingend Zeit oder Token spart. Ein harter kurzer
Reasoning-Cap wird deshalb nicht als Standardprofil vorgesehen.
### 2.2 Swift-Qwen3.8-27B
Der Herausgeber beschreibt
[Swift-Qwen3.8-27B](https://huggingface.co/ukisai/Swift-Qwen3.8-27b) als
reasoning-effiziente Ableitung des Qwen-Basismodells. Nach eigener Darstellung
wurden mit Overthinking korrelierte Reasoning-Muster im Fine-Tuning
benachteiligt und verlorene Qualität durch weitere Trainingsschritte
kompensiert.
Die veröffentlichten BF16-Vergleiche wurden mit vLLM, 262.144 Token Kontext,
`xhigh`, fünf Seeds und den Qwen-Samplingwerten durchgeführt. Für GPQA Diamond
werden nahezu gleiche Scores bei 41 Prozent weniger mittleren beziehungsweise
58,3 Prozent weniger medianen Thinking-Tokens ausgewiesen. Terminal-Bench 2.1
liegt geringfügig unter Base, LiveCodeBench v6 darüber. AIME 2026 und HMMT
zeigen hingegen einen messbaren Rückgang.
Diese Ergebnisse stammen vom Modellhersteller. Sie sind ein guter Grund für
einen lokalen Test, aber noch kein unabhängiger Nachweis für unsere Aufgaben,
für GGUF Q6_K, für llama.cpp oder für ROCm auf Navi 21. Insbesondere darf der
LiveCodeBench-Unterschied nicht ohne Kontrolle der Output-Limits als allgemeine
Qualitätssteigerung interpretiert werden.
### 2.3 GGUF-Quantisierungen
Das vom Swift-Herausgeber gepflegte
[GGUF-Repository](https://huggingface.co/ukisai/Swift-Qwen3.8-27B-GGUF)
enthält unter anderem folgende Ein-Datei-Quantisierungen:
| Quantisierung | veröffentlichte Größe | vorgesehene Rolle |
| --- | ---: | --- |
| Q4_K_M | 18,0 GB | speichersparender Vergleich und möglicher Fast-/Vision-Fallback |
| Q5_K_M | 20,2 GB | möglicher Kompromiss für MTP oder zusätzliche Reserve |
| Q6_K | 22,9 GB | bevorzugter Qualitätskandidat für Text-, Coding- und Tool-Aufgaben |
| Q6_K_L | 25,2 GB | derzeit zu geringe Reserve für 128k und Laufzeitpuffer |
| Q8_0 | 29,1 GB | für 32 GiB Gesamt-VRAM mit langem Kontext ungeeignet |
Der Herausgeber empfiehlt Q6_K oder höher für lange Agentenläufe und strikte
Tool-Formate. Die GGUFs wurden laut Modellkarte mit llama.cpp `b10896` erzeugt;
recurrent-sensitive Tensoren und das MTP-Head verwenden gezielt höhere
Präzision. Die veröffentlichten quantisierten Aufgabenbenchmarks betreffen
jedoch W4A16/AWQ und nicht direkt die Q6_K-GGUF. Die Eignung von Q6_K bleibt
daher Gegenstand unseres Tests.
### 2.4 Unsloth Qwen3.8-27B UD-Q6_K
Das zweite Testartefakt stammt aus dem
[Unsloth-GGUF-Repository](https://huggingface.co/unsloth/Qwen3.8-27B-GGUF).
Ausgewählt ist `Qwen3.8-27B-UD-Q6_K.gguf` mit einer veröffentlichten Größe von
22 GB. Das Repository steht laut Modellkarte unter Apache-2.0. Unsloth hat die
Quantisierung mit einer Importance Matrix und dem eigenen Dynamic-Verfahren
erzeugt.
Damit unterscheidet sich der Kandidat nicht nur durch das ursprüngliche
Qwen-Verhalten von Swift, sondern auch durch das Quantisierungslayout. Der
Vergleich misst deshalb die beiden konkret einsetzbaren Artefakte als Ganzes;
er isoliert nicht wissenschaftlich den Effekt des Swift-Fine-Tunings. Diese
Einschränkung wird bei der Auswertung ausdrücklich festgehalten.
### 2.5 MTP
Das MTP-Head ist in den Swift-GGUFs enthalten. Die Modellkarte nennt für
llama.cpp `--spec-type draft-mtp --spec-draft-n-max 3`. Die aktuelle
llama.cpp-Dokumentation führt MTP als unterstützte spekulative Methode.
MTP wird trotzdem nicht in das erste Abnahmeprofil aufgenommen. Es benötigt
zusätzlichen Draft-Kontext und zusätzliche Laufzeitpuffer. Der verlinkte
Community-Nachweis zeigt, dass MTP deutliche Gewinne liefern kann, verwendet
aber Strix Halo, Vulkan, ein anderes Qwen-Modell und zeitweise einen Fork. Er
ist kein Nachweis für zwei RX 6900 XT mit dem gepinnten ROCm-Image.
MTP wird erst nach einer stabilen Baseline in derselben Sitzung und mit
identischen Aufgaben ein- und ausgeschaltet. Begonnen wird mit
`--spec-draft-n-max 2`; `3` bleibt eine zweite Messstufe.
### 2.6 Swift 1.5 und Community-Quants
Ankündigungen zu Swift 1.5 und kombinierten Swift-/Unsloth-Dynamic-Quants
werden als Beobachtung festgehalten. Am 21.09.2026 wurde daraus noch kein
freigegebenes Projektartefakt ausgewählt. Weder die Ansible-Rolle noch das
Production-Profil warten auf eine angekündigte Version.
Ein neuer Checkpoint wird als neues, unveränderliches Profil mit eigener
Quelle, Revision, Prüfsumme und Lizenzprüfung aufgenommen. Er ersetzt niemals
automatisch ein bereits abgenommenes Profil.
## 3. Vorläufige Kandidaten
### 3.1 Bevorzugter Kandidat
**Swift-Qwen3.8-27B Q6_K mit `xhigh`** wird als erster Testing-Kandidat
festgelegt. Gründe sind die höhere Gewichtsqualität gegenüber Q4/Q5, die
Herstellerempfehlung für lange Agentenläufe und die Zielsetzung von Swift,
Reasoning-Effizienz ohne kurzen harten Token-Cap zu erreichen.
Das erste Profil verwendet:
| Parameter | Wert |
| --- | --- |
| Quantisierung | Q6_K |
| Kontextziel | 131.072 Token |
| K-/V-KV-Cache | `q8_0` / `q8_0` |
| Reasoning | aktiv, `xhigh`, ohne Reasoning-Budget |
| parallele Slots | 1 |
| Flash Attention | aktiv |
| GPU-Offload | alle Layer |
| GPU-Aufteilung | `layer`, `1,1` |
| MTP | zunächst deaktiviert |
| Vision-Projektor | zunächst nicht geladen |
| maximale Ausgabe | zunächst 32.768 Token; gesonderter 65.536-Token-Test |
128 KiToken sind das Zielprofil. Die Inbetriebnahme prüft dasselbe Modell
zuerst mit 64 KiToken, damit Fehler bei Modellformat, ROCm oder GPU-Aufteilung
von reinem Speicherdruck unterschieden werden können.
### 3.2 Verbindlicher Vergleichskandidat
**Unsloth Qwen3.8-27B UD-Q6_K** wird ebenfalls installiert und mit 131.072
Token Kontext abgenommen. Das Artefakt ist verbindlich festgelegt:
| Feld | Wert |
| --- | --- |
| Repository | `unsloth/Qwen3.8-27B-GGUF` |
| Revision | `4ca720788d1e01f1bff70c033e0d0028fd02e502` |
| Datei | `Qwen3.8-27B-UD-Q6_K.gguf` |
| veröffentlichte Größe | 22 GB |
| SHA-256 | `c9c206812fbe4ac7b76a729e25928b63f2ae89d37f69da7a71c20aec763cd436` |
| API-Alias | `unsloth-qwen3.8-27b-ud-q6k` |
Beide Dateien liegen gleichzeitig auf dem Host und jedes Modell besitzt eine
eigene feste Quadlet-Unit. Für einen Messlauf ist immer nur die ausgewählte
Unit aktiv; die Modelle werden nicht gleichzeitig in den VRAM geladen. Der
Wechsel stoppt den bisherigen Container vollständig, bevor der andere startet.
Der erste kontrollierte A/B-Vergleich verwendet bei beiden Modellen `xhigh`,
131.072 Token Kontext, Q8-K/V, einen Slot, dieselben Samplingwerte und kein
MTP. Danach folgt der praxisnahe Profilvergleich Swift `xhigh` gegen Unsloth
`medium`. Dadurch bleiben die Effekte der Reasoning-Einstellung sichtbar,
statt sie unbemerkt dem Modellartefakt zuzurechnen.
### 3.3 Ressourcen-Fallback
**Swift Q5_K_M mit `xhigh`** ist der erste Fallback, falls Q6_K mit 128k,
Laufzeitpuffern oder später MTP nicht stabil in 32 GiB VRAM betrieben werden
kann. Ein Wechsel auf Q5 erfolgt nur aufgrund gemessener Speicher- oder
Leistungsergebnisse, nicht vorsorglich.
## 4. Testmatrix
| Stufe | Modellprofil | Kontext | MTP | Zweck |
| --- | --- | ---: | --- | --- |
| A0 | Swift Q6_K, text-only | 65.536 | aus | Modellformat, vollständiger GPU-Offload, API und Grundstabilität |
| A1 | Swift Q6_K, text-only | 131.072 | aus | bevorzugtes Zielprofil und VRAM-Abnahme |
| A2 | Swift Q6_K mit mmproj | 131.072 | aus | optionaler Vision-Betrieb und zusätzlicher VRAM-Bedarf |
| A3 | Swift Q6_K, text-only | 131.072 | `n-max=2` | MTP-A/B gegen A1 |
| A4 | Swift Q6_K, text-only | 131.072 | `n-max=3` | nur nach erfolgreichem A3-Test |
| B1 | Swift Q5_K_M, text-only | 131.072 | aus / 2 | Ressourcen- und Geschwindigkeitsvergleich |
| U0 | Unsloth UD-Q6_K, text-only, `xhigh` | 65.536 | aus | Modellformat, GPU-Offload, API und Grundstabilität |
| U1 | Unsloth UD-Q6_K, text-only, `xhigh` | 131.072 | aus | kontrolliertes Gegenstück zu A1 |
| AB1 | Swift Q6_K gegen Unsloth UD-Q6_K, beide `xhigh` | 131.072 | aus | A/B mit identischen Laufzeitparametern |
| AB2 | Swift Q6_K `xhigh` gegen Unsloth UD-Q6_K `medium` | 131.072 | aus | Vergleich der vorgesehenen Praxisprofile |
Vision und MTP sind eigenständige Varianten. Sie werden nicht gleichzeitig
erstmals aktiviert, weil andernfalls Speicher- und Performanceeffekte nicht
zugeordnet werden können.
## 5. Aufgaben und Messwerte
Die Vergleichssuite enthält 10 bis 20 repräsentative Aufgaben aus dem späteren
Betrieb:
1. kleine, eindeutig prüfbare Codeänderung;
2. repositoryweite Änderung mit mehreren Dateien;
3. Fehlersuche anhand von Logs und Tests;
4. Tool-Aufruf mit korrektem JSON-Schema;
5. mehrstufige Aufgabe mit fehlgeschlagenem ersten Ansatz;
6. lange Kontextaufgabe mit relevanten Informationen an verschiedenen Stellen;
7. Refactoring mit unverändertem Verhalten;
8. Dokumentations- und Konfigurationsänderung;
9. mathematisch-logische Kontrollaufgabe; und
10. Negativtest, bei dem das Modell fehlende Informationen erkennen soll.
Pro Aufgabe und Profil werden soweit praktikabel mindestens drei Läufe
durchgeführt. Für Leistungsmessungen werden zusätzlich deterministische
Prompts mit festem Seed verwendet. Reale Agentenaufgaben behalten die von Qwen
empfohlenen Samplingwerte.
Für AB1 wird die Reihenfolge pro Aufgabe zwischen Swift und Unsloth gewechselt.
Nach jedem Profilwechsel wird ein definierter Warm-up-Request ausgeführt; seine
Zeit fließt nicht in den fachlichen Vergleich ein. Modellladezeit und Warm-up
werden separat erfasst. Container-Digest, Prompt, Systemnachricht, Toolschema,
Seed, Kontext, Sampling und Ausgabegrenze bleiben innerhalb einer Serie
identisch. Die automatischen Prüfungen und die manuelle Bewertungsrubrik werden
vor dem ersten gewerteten Lauf festgelegt.
Jede abgeschlossene Serie erhält im Repository einen datierten
Evaluierungsdatensatz mit Profilmanifest, Aufgabenrevision, Rohmesswerten und
Kurzbericht. Modell- oder Containerdateien sowie sensible Promptinhalte werden
nicht in Git gespeichert. Der Bericht muss erkennen lassen, welche Läufe wegen
technischer Fehler wiederholt oder aus der Wertung genommen wurden.
Zu erfassen sind:
- fachlicher Erfolg und bestandene Tests;
- Zahl der Tool-Aufrufe, Fehlversuche und Wiederholungen;
- Prompt-, Reasoning-, Antwort- und Gesamttoken;
- Time to First Token, Prompt Processing und Generationstempo;
- gesamte Laufzeit bis zum erfolgreichen Abschluss;
- Spitzen- und stabiler VRAM-Verbrauch je GPU;
- CPU- und RAM-Verbrauch;
- GPU-Aufteilung und etwaige CPU-Offloads;
- Abbruch, OOM, fehlerhafte Tool-Formate oder unvollständige Antworten.
## 6. Vorläufige Abnahmekriterien
Ein Kandidat wird zum bevorzugten Production-Profil, wenn:
- das 128k-Profil ohne OOM startet und einen einstündigen gemischten Test
ohne Containerneustart oder GPU-Fehler besteht;
- alle vorgesehenen Modell-Layer auf die GPUs ausgelagert werden;
- beide GPUs genutzt werden und keine Karte ihren verfügbaren VRAM erschöpft;
- API-Antwort, Reasoning-Trennung und Tool Calls dem erwarteten Schema
entsprechen;
- die Aufgabensuite höchstens einen Erfolg weniger als der
jeweils andere Vergleichskandidat erzielt;
- keine systematische Regression bei Mathematik- oder Tool-Aufgaben sichtbar
wird; und
- der Median der generierten Gesamttoken oder der Zeit bis zum erfolgreichen
Abschluss gegenüber dem anderen Profil praktisch relevant sinkt.
Als Zielwert für die Effizienz gilt zunächst eine Reduktion von mindestens
20 Prozent. Die vom Hersteller berichteten 30 bis 50 Prozent sind eine
Hypothese, kein lokales Abnahmekriterium.
MTP wird nur übernommen, wenn es in einer A/B-Messung derselben Sitzung den
Median der Generationsleistung oder End-to-End-Laufzeit um mindestens
10 Prozent verbessert, ohne Stabilität, Tool-Format oder Abschlussquote zu
verschlechtern. Einzelne schnelle Läufe reichen nicht als Nachweis.
## 7. Freigabe und Rollback
Jedes Modellprofil erhält einen stabilen Namen, eine unveränderliche Quelle,
eine SHA-256-Prüfsumme und einen dokumentierten Lizenzstand. Testing und
Production referenzieren dieselbe geprüfte Datei aus dem gemeinsamen
schreibgeschützten Modellbestand.
Ein Upgrade erzeugt ein neues Profil. Das bisherige Modell bleibt bis zum
abgeschlossenen Production-Test erhalten. Der Rollback ändert nur den
versionierten Profilverweis und startet die betroffene Umgebung neu. Ein
unbeaufsichtigter Download von `main`, `latest` oder einer beweglichen
Quantisierungsbezeichnung ist ausgeschlossen.
Swift und Unsloth werden als getrennte Profile installiert. Das Ergebnis kann
ein bevorzugtes Standardprofil und ein weiterhin verfügbares alternatives
Profil sein; beide dürfen nur über den kontrollierten Umgebungswechsel
aktiviert werden.
## 8. Offene Punkte
- Lizenz und tatsächlichen Verwendungsrahmen des Swift-Modells vor Production
bestätigen;
- maximal zulässige Antwortdauer und Ausgabegröße für externe Nutzer
festlegen;
- entscheiden, ob Vision Bestandteil des ersten Production-Profils wird;
- Metrikerfassung für Reasoning- und Antworttoken mit LiteLLM abstimmen;
- Aufgabenbestand und erwartete Ergebnisse der lokalen Suite versionieren; und
- nach Veröffentlichung bewerten, ob Swift 1.5 oder eine geprüfte
Swift-Dynamic-Quantisierung als neuer Kandidat aufgenommen wird.
## 9. Quellen
- [Qwen3.8-27B – Modellkarte](https://huggingface.co/Qwen/Qwen3.8-27B)
- [Swift-Qwen3.8-27B – Modellkarte und Benchmarks](https://huggingface.co/ukisai/Swift-Qwen3.8-27b)
- [Swift-Qwen3.8-27B-GGUF – Quantisierungen, KV-Angaben und MTP](https://huggingface.co/ukisai/Swift-Qwen3.8-27B-GGUF)
- [Unsloth Qwen3.8-27B-GGUF – Modellkarte und Dateien](https://huggingface.co/unsloth/Qwen3.8-27B-GGUF)
- [Unsloth UD-Q6_K – Datei und Prüfsumme](https://huggingface.co/unsloth/Qwen3.8-27B-GGUF/blob/4ca720788d1e01f1bff70c033e0d0028fd02e502/Qwen3.8-27B-UD-Q6_K.gguf)
- [llama.cpp Server – aktuelle Parameterreferenz](https://github.com/ggml-org/llama.cpp/blob/master/tools/server/README.md)
- [llama.cpp MTP-/ROCm-Communitybericht](https://github.com/ggml-org/llama.cpp/discussions/27950)
Community-Berichte dienen ausschließlich der Hypothesenbildung. Freigaben
beruhen auf reproduzierbaren Messungen des gepinnten eigenen Stacks.
+558
View File
@@ -0,0 +1,558 @@
# Technischer Arbeitsentwurf
**Dokumenten-ID:** GNAI-009-TECH
**Titel:** `llama.cpp`-Serving mit ROCm und rootless Podman
**Stand:** 2026-09-21
**Status:** Technische Sollkonfiguration für Testing; noch nicht implementiert
**Referenzen:** [Modellbewertung](GNAI-008-PLAN_Llama-Model-Evaluation.md), [Ansible-Deployment](GNAI-007-PLAN_Ansible-Deployment.md), [Zielarchitektur](GNAI-003-INFRA_Architecture.md), [Ansible-Anleitung](../../ansible/README.md)
> Dieses Dokument beschreibt den vorgesehenen technischen Sollzustand. Es ist
> keine Betriebs-SOP und kein Nachweis, dass Modell, Quadlet oder Inferenz
> bereits eingerichtet wurden. Abweichungen aus der Implementierung werden vor
> einer Production-Freigabe hier nachgeführt.
---
## Änderungsverlauf
| Datum | Version | Autor | Beschreibung |
| --- | --- | --- | --- |
| 2026-09-21 | 0.3 | spektr / Codex | je Modell ein festes Quadlet vorgesehen; Swift und Unsloth durch kontrollierten Stop/Start gegenseitig ausgeschlossen; Router-Modus zurückgestellt |
| 2026-09-21 | 0.2 | spektr / Codex | Unsloth UD-Q6_K als zweites installiertes Modellprofil und kontrollierten Profilwechsel für A/B-Tests ergänzt |
| 2026-09-21 | 0.1 | spektr / Codex | erstes technisches Profil für Swift Q6_K, 128k, Q8-KV, rootless Quadlet und gestufte MTP-Abnahme erstellt |
---
## 1. Geltungsbereich
Die Spezifikation umfasst zwei feste `llama-server`-Quadlets in der
Testing-Umgebung, von denen immer genau eines aktiv ist. Sie legt fest:
- welche Container- und Modellartefakte verwendet werden;
- wie Modell und Konfiguration gespeichert werden;
- welche Geräte und Netzwerke der Container erhält;
- welche `llama-server`-Parameter als Ausgangsprofil gelten;
- wie VRAM-Annahmen behandelt werden; und
- welche technischen Prüfungen vor der Übernahme nach Production bestehen
müssen.
LiteLLM, öffentliche Veröffentlichung, Nutzer-SOPs und die zeitliche
Umschaltung zwischen Production und Testing erhalten eigene Rollen und
Dokumente. `llama-server` wird nicht direkt für LAN, VPN oder Internet
veröffentlicht.
## 2. Bereits belegte Voraussetzungen
Am 20.09.2026 wurden auf `ghostnet-ki` folgende Grundlagen nachgewiesen:
- Debian 13.6 und Podman 5.4.2 mit cgroup v2 und `crun`;
- rootless Konto `gnai-testing` mit UID/GID 981 und persistentem
systemd-User-Manager;
- `/dev/kfd`, `/dev/dri/renderD128` und `/dev/dri/renderD129`;
- zwei RX 6900 XT als getrennte ROCm-Geräte und `gfx1030`-Agents; und
- erfolgreicher Start des offiziellen `llama.cpp`-ROCm-Images ohne
`HSA_OVERRIDE_GFX_VERSION`.
Modellladen, 128k-Kontext, Multi-GPU-Layer-Verteilung und Inferenz wurden noch
nicht nachgewiesen.
## 3. Unveränderliche Artefakte
### 3.1 Container
| Feld | Wert |
| --- | --- |
| Upstream | `ghcr.io/ggml-org/llama.cpp:server-rocm` |
| verwendete Referenz | `ghcr.io/ggml-org/llama.cpp@sha256:b429b8be10d3d0353a09c98f4ab840fe516f779858a28f9fd4e5bdf10bc63cb4` |
| Architektur | amd64 |
| Build | `b11058` |
| Revision | `f072b103714dfa1eee531f80b24512faf38e3dd2` |
| Status | ROCm-Geräteerkennung unter `gnai-testing` bestanden |
Der Dienst verwendet ausschließlich den Digest. Ein bewegliches Tag darf in
Testing zur Recherche aufgelöst, aber nicht in ein freigegebenes Profil
übernommen werden.
### 3.2 Swift-Modellprofil
| Feld | Wert |
| --- | --- |
| Repository | `ukisai/Swift-Qwen3.8-27B-GGUF` |
| Repository-Revision | `eb0e3a7dc70643c2ab920f5133750d02c20849ff` |
| Datei | `Swift-Qwen3.8-27B-Q6_K.gguf` |
| veröffentlichte Größe | 22,9 GB |
| SHA-256 | `7f4de8abd5446c08b0f975a1b38e43d02639f4ae9ecdd2ddfd5c5b0f612bda59` |
| Download | `https://huggingface.co/ukisai/Swift-Qwen3.8-27B-GGUF/resolve/eb0e3a7dc70643c2ab920f5133750d02c20849ff/Swift-Qwen3.8-27B-Q6_K.gguf` |
| API-Alias | `swift-qwen3.8-27b-q6k` |
Die Prüfsumme stammt aus der vom Herausgeber veröffentlichten
[`SHA256SUMS`](https://huggingface.co/ukisai/Swift-Qwen3.8-27B-GGUF/blob/main/SHA256SUMS)-Datei.
Ansible muss die SHA-256-Prüfsumme während des Downloads prüfen. Eine bereits
vorhandene Datei mit abweichender Prüfsumme führt zum Abbruch; sie wird nicht
stillschweigend überschrieben oder verwendet.
### 3.3 Unsloth-Vergleichsprofil
| Feld | Wert |
| --- | --- |
| Repository | `unsloth/Qwen3.8-27B-GGUF` |
| Repository-Revision | `4ca720788d1e01f1bff70c033e0d0028fd02e502` |
| Datei | `Qwen3.8-27B-UD-Q6_K.gguf` |
| veröffentlichte Größe | 22 GB |
| SHA-256 | `c9c206812fbe4ac7b76a729e25928b63f2ae89d37f69da7a71c20aec763cd436` |
| Download | `https://huggingface.co/unsloth/Qwen3.8-27B-GGUF/resolve/4ca720788d1e01f1bff70c033e0d0028fd02e502/Qwen3.8-27B-UD-Q6_K.gguf` |
| API-Alias | `unsloth-qwen3.8-27b-ud-q6k` |
Die SHA-256-Prüfsumme ist in den Xet-Dateimetadaten des Herausgebers
veröffentlicht. Für Download, vorhandene Dateien und Fehlerfälle gelten
dieselben Regeln wie beim Swift-Artefakt. Beide Modelldateien werden
bereitgestellt, bevor die A/B-Serie beginnt.
### 3.4 Optionaler Vision-Projektor
Der erste Text-/Coding-Test lädt keinen Vision-Projektor. Dadurch bleibt rund
ein weiteres GiB für KV-Cache und Laufzeitpuffer verfügbar und die
Grundabnahme erhält weniger Variablen.
Für eine spätere Vision-Stufe ist vorgesehen:
| Feld | Wert |
| --- | --- |
| Datei | `mmproj-Swift-Qwen3.8-27B-F16.gguf` |
| veröffentlichte Größe | 928 MB |
| SHA-256 | `daa1116c9422fa390cc8688495da0e91781f92841dfc3b31a378ff252571745a` |
| Download | `https://huggingface.co/ukisai/Swift-Qwen3.8-27B-GGUF/resolve/eb0e3a7dc70643c2ab920f5133750d02c20849ff/mmproj-Swift-Qwen3.8-27B-F16.gguf` |
Der Projektor wird erst heruntergeladen und mit `--mmproj` eingebunden, wenn
die Vision-Teststufe ausdrücklich aktiviert wird.
### 3.5 Lizenz und Herkunft
Das Qwen-Basismodell und das Unsloth-GGUF-Repository stehen laut ihren
Modellkarten unter Apache-2.0. Die Swift-Änderungen werden laut
Modellkarte unter der Swift Open License 1.0 angeboten. Die Modellkarte nennt
eine kostenlose persönliche, Forschungs-, Bildungs-, Evaluierungs- und
kommerzielle Nutzung bis zu einer dort definierten Umsatzgrenze; oberhalb
davon gelten zusätzliche Lizenzbedingungen.
Vor einer externen oder kommerziellen Production-Nutzung wird der dann
aktuelle Lizenztext gegen den konkreten Betreiber- und Nutzungsrahmen geprüft.
Repository-Revision, Modellkarte, Prüfsummen und Lizenzhinweis werden als
Herkunftsnachweis zum Profil dokumentiert.
## 4. Verzeichnis- und Rechtekonzept
Modelle sind große, unveränderliche und nicht geheime Artefakte. Production
und Testing sollen dieselbe geprüfte Datei lesen, ohne sie in getrennten
Podman-Stores zu duplizieren.
Vorgesehene Hostpfade:
```text
/var/lib/ghostnet-ai/shared/models/
├── swift-qwen3.8-27b/
│ ├── Swift-Qwen3.8-27B-Q6_K.gguf
│ ├── mmproj-Swift-Qwen3.8-27B-F16.gguf # erst in der Vision-Stufe
│ └── SOURCE.yml
└── unsloth-qwen3.8-27b/
├── Qwen3.8-27B-UD-Q6_K.gguf
└── SOURCE.yml
```
| Objekt | Eigentümer | Modus | Begründung |
| --- | --- | --- | --- |
| Modellverzeichnisse | `root:root` | `0755` | durch Deployment verwaltet, für beide Umgebungen lesbar |
| GGUF-Dateien | `root:root` | `0644` | unveränderlicher, nicht geheimer gemeinsamer Bestand |
| `SOURCE.yml` | `root:root` | `0644` | nachvollziehbarer Herkunftsnachweis |
Der Container bindet nur das zum aktiven Profil gehörende Modellverzeichnis
als `/models:ro` ein. Er erhält keinen Schreibzugriff auf den gemeinsamen Bestand.
Downloads erfolgen atomar in ein temporäres Ziel und werden erst nach
erfolgreicher Prüfsumme an den endgültigen Pfad verschoben.
Vor dem Download beider Modelle prüft Ansible mindestens 70 GiB freien Platz
auf dem Zieldateisystem. Das deckt rund 45 GB endgültigen Modellbestand, die
größte temporäre Downloaddatei und einen kleinen Betriebspuffer ab. Bereits
korrekt vorhandene Artefakte werden bei der Berechnung nicht erneut als
Downloadbedarf angesetzt.
## 5. Rootless Quadlet
### 5.1 Ablage und Identität
Ansible rendert für jedes Modell ein eigenes, rootverwaltetes Testing-Quadlet:
```text
/etc/containers/systemd/users/981/
├── gnai-testing-llama-swift.container
└── gnai-testing-llama-unsloth.container
```
Sie werden vom persistenten systemd-User-Manager von `gnai-testing`
ausgeführt. Die Units heißen `gnai-testing-llama-swift.service` und
`gnai-testing-llama-unsloth.service`. Beide verwenden dasselbe gepinnte Image,
aber einen eigenen Containernamen, Modellpfad, API-Alias und Parametersatz.
Podman speichert das identische Image nur einmal im rootless Image-Store.
### 5.2 Containeroptionen
Der `[Container]`-Abschnitt muss mindestens folgende Eigenschaften abbilden:
| Quadlet-Eigenschaft | Sollwert |
| --- | --- |
| `Image=` | gepinnter Digest aus Abschnitt 3.1 |
| `Pull=` | `never`; Images werden vor dem Dienststart kontrolliert importiert |
| `AddDevice=` | `/dev/kfd`, `/dev/dri/renderD128`, `/dev/dri/renderD129` |
| `GroupAdd=` | `keep-groups` |
| `Volume=` | Modellverzeichnis nach `/models:ro` |
| `Network=` | dediziertes Testing-Netz für `llama.cpp` und LiteLLM |
| `NetworkAlias=` | `llama-cpp`; wegen gegenseitigem Ausschluss immer nur einmal aktiv |
| `PublishPort=` | nicht gesetzt |
| `ReadOnly=` | nach erfolgreichem Starttest `true` |
| `SecurityLabelDisable=` | nicht gesetzt, solange SELinux auf dem Host nicht aktiv ist |
Podman dokumentiert `AddDevice=` und `GroupAdd=keep-groups` direkt als
Quadlet-Optionen. Freie `PodmanArgs=` werden für diese Funktionen nicht
benötigt. Die Render-Nodes werden weiterhin aus der Hardwareerkennung der
Ansible-Rolle übernommen und nicht unabhängig als zweite Hardwarequelle
konfiguriert.
### 5.3 systemd-Verhalten und gegenseitiger Ausschluss
Vorgesehene Servicewerte:
```ini
[Service]
Restart=on-failure
RestartSec=10
TimeoutStartSec=900
```
Der erhöhte Start-Timeout berücksichtigt Modellinitialisierung und einen
möglichen kontrollierten Erstimport. Das Image und das Modell sollen dennoch
vor dem Dienststart bereitstehen. Ein normaler administrativer Stop darf nicht
durch eine `always`-Policy sofort rückgängig gemacht werden.
Das Testing-Quadlet erhält keinen `[Install]`-Abschnitt und wird nicht für
`default.target` aktiviert. Es startet ausschließlich für ein bewusst
geöffnetes Testfenster. Die spätere Production-Unit kann nach bestandener
Umschalt- und Neustartabnahme gezielt aktiviert werden.
Die Units erhalten folgende negative Abhängigkeit und eine eindeutige
Reihenfolge:
```ini
# Swift-Unit
[Unit]
Conflicts=gnai-testing-llama-unsloth.service
Before=gnai-testing-llama-unsloth.service
# Unsloth-Unit
[Unit]
Conflicts=gnai-testing-llama-swift.service
```
`Conflicts=` sorgt dafür, dass der Start einer Unit die andere stoppt. Das
einmalig gesetzte `Before=` ergänzt die nötige Ordnungsabhängigkeit; systemd
führt dadurch den Stop vollständig vor dem neuen Start aus. Der reguläre
Profilwechsel bleibt zusätzlich eine explizite, sequenzielle Operation:
1. aktuell aktive Modell-Unit stoppen;
2. auf vollständiges Ende des Containers warten;
3. prüfen, dass kein `llama-server` mehr die GPUs belegt;
4. gewünschte Modell-Unit starten; und
5. Alias, Health, Modellrevision und GPU-Belegung prüfen.
Das Ansible-Playbook und die spätere Betriebs-SOP kapseln diese Reihenfolge.
Ein direkter Start der jeweils anderen Unit löst denselben geordneten Wechsel
aus. Der gleichzeitige Start beider Units in einer Transaktion gilt als Fehler
und ist kein unterstützter Betriebsweg.
### 5.4 Entscheidung gegen den Router-Modus in der ersten Ausbaustufe
Der gepinnte `llama.cpp`-Build unterstützt bereits einen Router-Modus mit
`--models-preset`, `--models-max`, automatischem Laden sowie den Endpunkten
`/models/load` und `/models/unload`. Technisch wäre damit ein einzelner
Router-Container für beide Modelle möglich.
Für die erste Abnahme bleibt jedes Quadlet im einfacheren Single-Model-Modus.
Damit sind Startparameter, Logs, Health, VRAM-Verbrauch und Fehlerzustand einem
Modell eindeutig zugeordnet. Außerdem benötigt der interne Dienst keine
dynamische Modellverwaltungs-API. Nach stabiler Abnahme kann der Router-Modus
separat bewertet werden; er ist keine Voraussetzung für LiteLLM.
## 6. `llama-server`-Ausgangsprofil
Das erste 128k-Zielprofil entspricht konzeptionell folgender Kommandozeile:
```text
--host 0.0.0.0
--port 8080
--model /models/Swift-Qwen3.8-27B-Q6_K.gguf
--alias swift-qwen3.8-27b-q6k
--parallel 1
--ctx-size 131072
--n-predict 32768
--n-gpu-layers all
--split-mode layer
--tensor-split 1,1
--flash-attn on
--cache-type-k q8_0
--cache-type-v q8_0
--jinja
--reasoning on
--reasoning-effort xhigh
--reasoning-budget -1
--temp 1.0
--top-p 0.95
--top-k 20
--min-p 0.0
--presence-penalty 0.0
--repeat-penalty 1.0
--no-webui
--metrics
```
Die Parameter werden als strukturierte Ansible-Variablen verwaltet und von
einem Template in `Exec=` gerendert. Eine freie, manuell gepflegte
Environment-Datei ist nicht die Konfigurationsquelle.
Vor der Implementierung wird `llama-server --help` im exakt gepinnten Image
gegen alle Optionen geprüft. Falls dieser Build `all` für
`--n-gpu-layers` nicht akzeptiert, wird der bereits bewährte numerische Wert
`999` verwendet und die Abweichung dokumentiert.
Das Unsloth-Profil verwendet dieselbe Kommandozeile mit diesen gezielten
Abweichungen:
| Parameter | kontrollierter A/B-Test | Praxisvergleich |
| --- | --- | --- |
| `--model` | `/models/Qwen3.8-27B-UD-Q6_K.gguf` | identisch |
| `--alias` | `unsloth-qwen3.8-27b-ud-q6k` | identisch |
| `--reasoning-effort` | `xhigh` | `medium` |
Alle nicht aufgeführten Parameter bleiben gegenüber dem Swift-Profil
unverändert.
### 6.1 Reasoning
`xhigh` ist der Ausgangswert für Swift. `--reasoning-budget -1` vermeidet einen
kurzen serverseitigen Thinking-Cap. `--n-predict 32768` begrenzt dagegen die
gesamte Ausgabe eines einzelnen Requests und schützt den zunächst manuell
betriebenen Testing-Dienst vor unbegrenzten Läufen.
Die Evaluierung enthält zusätzlich einen kontrollierten 65.536-Token-Lauf.
Vor Production wird entschieden, ob die allgemeine Obergrenze erhöht oder
später durch LiteLLM pro Nutzer und Modell gesteuert wird. Ein Default von
2.048 oder 4.096 Token ist für dieses Profil nicht vorgesehen.
Die API muss Reasoning getrennt von der finalen Antwort liefern. Zunächst wird
das automatische `--reasoning-format` des gepinnten Builds geprüft. Ein fester
Wert wird erst gesetzt, wenn die Kombination aus llama.cpp, LiteLLM und den
verwendeten Clients mit einem reproduzierbaren Request abgenommen wurde.
Für Unsloth werden zwei Reasoning-Varianten gerendert. `xhigh` dient dem
kontrollierten A/B-Test mit Swift. `medium` bildet das geplante Praxisprofil
ab. Alle übrigen Laufzeitparameter bleiben innerhalb der jeweiligen
Vergleichsserie gleich.
### 6.2 Sampling
Die Werte entsprechen der Qwen-Modellkarte für Thinking. Sie bleiben Teil des
Modellprofils. Ein späteres Instruct-/Non-Thinking-Profil erhält eigene Werte
und überschreibt diese nicht stillschweigend.
### 6.3 Multi-GPU
`layer` und `1,1` sind die Ausgangskonfiguration für die zwei gleich großen
Karten. Der zweite PCIe-Slot ist langsamer angebunden, weshalb experimentelle
parallele Split-Verfahren nicht vor der stabilen Layer-Baseline aktiviert
werden.
Die Startlogs müssen für beide Karten den belegten VRAM und die tatsächliche
Layer-Verteilung ausweisen. `1,1` ist eine Gewichtung, keine Garantie für exakt
gleiche Speicherbelegung. Ein abweichender Split wird ausschließlich anhand
gemessener freier Reserven und Durchsatzwerte eingeführt.
### 6.4 Vision
Der Haupttest verwendet `--model` mit einer lokalen Datei und übergibt kein
`--mmproj`. Erst die Vision-Stufe bindet den Projektor ein. Dadurch werden
Text-/Tool-Qualität, Modellformat und 128k-Speicherbedarf unabhängig vom
Vision-Encoder geprüft.
### 6.5 MTP
MTP bleibt im Ausgangsprofil aus. Die erste Variante ergänzt:
```text
--spec-type draft-mtp
--spec-draft-n-max 2
```
Erst nach bestandener A/B-Messung folgt optional `n-max=3`. Draft-Kontext,
VRAM-Zuwachs, Akzeptanzrate und tatsächlicher End-to-End-Gewinn werden
protokolliert. MTP wird nicht zusammen mit Vision erstmals aktiviert.
## 7. VRAM-Modell
Die Hardware stellt nominell 2 × 16 GiB VRAM bereit. Die Summe allein genügt
nicht als Fit-Nachweis, weil llama.cpp Gewichte, KV-Cache, Rechenpuffer und
gegebenenfalls den Vision- oder Draft-Kontext nicht zwingend gleichmäßig auf
beide Karten verteilt.
### 7.1 Gewichte
Die veröffentlichte Swift-Q6_K-Dateigröße von 22,9 GB entspricht grob
21,3 GiB. Unsloth UD-Q6_K ist mit veröffentlichten 22 GB ähnlich groß. Die
tatsächliche GPU-Belegung kann durch Metadaten, Ausrichtung, mmap und
Backend-Puffer abweichen und wird aus den Startlogs übernommen.
### 7.2 KV-Cache
Die Swift-Modellkarte berechnet für FP16-K/V 64 KiB pro Token, weil nur 16 der
64 Blöcke Full Attention verwenden:
| Kontext | FP16-K/V laut Modellkarte | Q8-K/V, rechnerische Näherung |
| ---: | ---: | ---: |
| 65.536 | 4 GiB | etwa 2 GiB |
| 131.072 | 8 GiB | etwa 4 GiB |
| 196.608 | 12 GiB | etwa 6 GiB |
| 262.144 | 16 GiB | etwa 8 GiB |
Die Q8-Spalte ist eine Halbierungsnäherung und kein gemessener Wert. Block- und
Backend-Overhead sowie die Verteilung je GPU werden beim Modellstart erfasst.
### 7.3 Grobe Zielrechnung
Für das textbasierte 128k-Profil ergibt sich vor der Messung:
```text
Q6_K-Gewichte etwa 21,3 GiB
Q8-K/V bei 128 KiToken etwa 4,0 GiB
ROCm-/Graph-/Compute-Puffer noch zu messen
──────────────────────────────────────────
Zwischensumme vor Puffern etwa 25,3 GiB
```
Mit Vision kommen rund 0,9 GB Dateigröße sowie zusätzliche Laufzeitpuffer
hinzu. MTP kann ebenfalls weiteren Draft-Kontext und Puffer belegen. Deshalb
werden beide Funktionen getrennt zugeschaltet und Q5_K_M bleibt als
Ressourcen-Fallback vorgesehen.
## 8. Netzwerk und API-Grenze
`llama-server` hört im Container auf TCP 8080. Es gibt kein `PublishPort=` und
keine Host-Portweiterleitung. LiteLLM wird später in dasselbe
umgebungsspezifische rootless Podman-Netz aufgenommen und erreicht den Dienst
über `http://llama-cpp:8080`.
Direkte Funktionsprüfungen erfolgen aus dem Container-Netz oder über einen
kurzlebigen administrativen Prüfcontainer. Externe Nutzer sprechen später nur
LiteLLM beziehungsweise die dafür vorgesehene veröffentlichte Anwendung an.
Der integrierte Webserver wird mit `--no-webui` betrieben. Metriken und Health
bleiben ausschließlich im internen Container-Netz. Vor der Health-Quadlet-
Konfiguration wird geprüft, welches HTTP-Werkzeug das gepinnte Image enthält;
die Abnahme darf nicht von einem im Image fehlenden `curl` abhängen.
## 9. Ansible-Rollenentwurf
Die spätere Rolle `llama_cpp` soll folgende Zuständigkeiten besitzen:
1. Variablen und Artefaktmanifest vollständig validieren.
2. Modellverzeichnisse mit festgelegten Rechten anlegen.
3. beide Modelle über revisionsgebundene URLs und SHA-256 atomar
bereitstellen.
4. Gepinntes Containerimage im rootless Store der Zielumgebung sicherstellen.
5. Render-Nodes aus `amd_gpu_access` übernehmen.
6. umgebungsspezifisches Podman-Netz als Quadlet rendern.
7. beide `llama.cpp`-Quadlets rendern und Generator-Dry-Run ausführen.
8. systemd-User-Manager neu laden und den ausgewählten Testing-Dienst bewusst
starten.
9. Startlog, API-Health, Modellalias und GPU-Verteilung prüfen.
10. einen kleinen Inferenztest ausführen und Ergebnis protokollieren.
Die Rollenvariablen enthalten eine Map unveränderlicher Modellprofile und
einen einzelnen Selektor wie `llama_cpp_active_profile`. Die Rolle rendert
beide Quadlets, startet aber nur die ausgewählte Unit. Ein Profilwechsel
verändert keine Unit-Datei, sondern stoppt die aktive Unit vollständig und
startet anschließend die bereits gerenderte Ziel-Unit.
Modell-Download und Dienstaktivierung erhalten getrennte Tags. Dadurch kann
ein großes Artefakt vorbereitet werden, ohne den aktiven Stack umzuschalten.
Check-Modus lädt kein Modell und startet keinen Dienst.
Production und Testing verwenden dieselbe Rollenlogik, aber getrennte
Variablen, Quadlets, Netzwerke, Podman-Stores und systemd-User-Manager. Die
Rolle darf nie beide GPU-Umgebungen gleichzeitig starten.
## 10. Technische Abnahme
### 10.1 Vor dem Start
- Modellrevision, Dateiname, Größe und SHA-256 stimmen mit dem Manifest
überein.
- Das Containerimage stimmt mit Digest und OCI-Labels überein.
- Beide Render-Nodes und `/dev/kfd` sind für `gnai-testing` zugreifbar.
- Production ist vollständig beendet und hält keine GPU-Prozesse.
- Der Quadlet-Generator meldet keine Fehler.
- Die generierte Unit enthält keinen veröffentlichten Host-Port.
### 10.2 Start mit 64k
- Container und Unit werden `active` und bleiben stabil.
- Modellformat und eingebettetes Chat-Template werden erkannt.
- alle Layer werden auf ROCm ausgelagert;
- beide GPUs erscheinen in den Startlogs;
- `/health` und `/v1/models` antworten erfolgreich;
- der API-Alias entspricht dem jeweils ausgewählten Profil;
- ein kurzer Thinking-Request liefert Reasoning und finale Antwort; und
- ein definierter Tool-Call ist syntaktisch gültig.
### 10.3 Start mit 128k
- kein OOM oder unbeabsichtigter CPU-Offload;
- freier VRAM je GPU und tatsächlicher KV-Verbrauch werden protokolliert;
- Prompt-Prefill wird stufenweise mit 8k, 32k, 64k und 128k geprüft;
- mindestens ein langer Request endet ohne Kontext- oder Parserfehler; und
- ein einstündiger gemischter Test erzeugt keinen Neustart, GPU-Reset oder
dauerhaft hängenden Slot.
Diese Abnahme wird zuerst für Swift und danach für Unsloth wiederholt. Erst
wenn beide Profile die technische Abnahme bestanden haben, beginnt die
fachliche A/B-Serie aus GNAI-008.
### 10.4 Wiederanlauf und Idempotenz
- ein zweiter identischer Ansible-Lauf meldet `changed=0`;
- ein kontrollierter Containerneustart erhält Profil und Modell;
- ein geplanter Hostneustart startet nur die freigegebene Umgebung;
- ein absichtlich gestoppter Testing-Dienst wird nicht ungewollt neu gestartet;
- ein Startversuch der zweiten Modell-Unit kann niemals beide Modelle
gleichzeitig im VRAM belassen;
- `podman ps`, systemd-Status und Health stimmen überein; und
- der Rückwechsel auf das vorherige Profil funktioniert ohne erneuten
Modelldownload.
## 11. Noch nicht festgelegte Werte
- genaue Health-Implementierung im gepinnten Containerimage;
- CPU-Thread-, Batch- und UBatch-Tuning für den i5-13600K;
- verbindliche maximale Ausgabe für Production und einzelne Nutzer;
- Aufnahme des Vision-Projektors in das erste Production-Profil;
- gemessener optimaler Split bei unterschiedlicher PCIe-Anbindung;
- Aktivierung und Parameter von MTP;
- Aufbewahrungs- und Löschregeln für abgelöste Modellartefakte.
## 12. Quellen
- [Qwen3.8-27B – Architektur, Reasoning und Sampling](https://huggingface.co/Qwen/Qwen3.8-27B)
- [Swift-Qwen3.8-27B – Training und Benchmarks](https://huggingface.co/ukisai/Swift-Qwen3.8-27b)
- [Swift-Qwen3.8-27B-GGUF – Dateien, Quantisierung und MTP](https://huggingface.co/ukisai/Swift-Qwen3.8-27B-GGUF)
- [Swift-GGUF-Prüfsummen](https://huggingface.co/ukisai/Swift-Qwen3.8-27B-GGUF/blob/main/SHA256SUMS)
- [Unsloth Qwen3.8-27B-GGUF – Modellkarte](https://huggingface.co/unsloth/Qwen3.8-27B-GGUF)
- [Unsloth UD-Q6_K – Datei und SHA-256](https://huggingface.co/unsloth/Qwen3.8-27B-GGUF/blob/4ca720788d1e01f1bff70c033e0d0028fd02e502/Qwen3.8-27B-UD-Q6_K.gguf)
- [llama.cpp Server-Parameter und Router-Modus des gepinnten Builds](https://github.com/ggml-org/llama.cpp/blob/f072b103714dfa1eee531f80b24512faf38e3dd2/tools/server/README.md)
- [Podman Quadlet](https://docs.podman.io/en/latest/markdown/podman-systemd.unit.5.html)
- [systemd-Unit-Abhängigkeiten](https://manpages.debian.org/trixie/systemd/systemd.unit.5.en.html)
+2
View File
@@ -10,6 +10,8 @@ Video-Encoding-Workload besitzt einen
| --- | --- |
| [GNAI-003](GNAI-003-INFRA_Architecture.md) | Zielarchitektur, Komponenten und Datenwege des KI-Stacks |
| [GNAI-007](GNAI-007-PLAN_Ansible-Deployment.md) | nicht finaler Arbeitsentwurf für Ansible- und Gitea-Deployment |
| [GNAI-008](GNAI-008-PLAN_Llama-Model-Evaluation.md) | nicht finaler A/B-Plan für Swift, Unsloth, Reasoning-, Kontext- und MTP-Abnahme |
| [GNAI-009](GNAI-009-TECH_Llama-Serving.md) | technische Sollkonfiguration für zwei geprüfte Modellprofile auf rootless `llama.cpp` mit ROCm |
Der übergreifende Projektstand steht im
[zentralen Dokumentationsindex](../GNAI-000-DOC_Index.md).