diff --git a/docs/platform/llm-server/ai/GNAI-010-TECH_Llama-Serving.md b/docs/platform/llm-server/ai/GNAI-010-TECH_Llama-Serving.md index 08d5ba5..29f95d6 100644 --- a/docs/platform/llm-server/ai/GNAI-010-TECH_Llama-Serving.md +++ b/docs/platform/llm-server/ai/GNAI-010-TECH_Llama-Serving.md @@ -26,6 +26,7 @@ | 2026-10-31 | 0.7 | spektr / Mistral Vibe | Protokollierungsbefund vom ersten Live-Betrieb: conmon schreibt die Container-Ausgabe mit dem Journald-Treiber ins System-Journal (`_COMM=conmon`, Syslog-Identifier = Container-Name, zum Beispiel `gnai-testing-llama-swift`); lesbar als root, `podman logs` bleibt für das Workload-Konto wegen der Journal-Dateirechte leer. Abschnitt 8.1 dokumentiert die Lesewege; die 64k-Bring-up-Startlogs sind damit protokollfähig. | | 2026-10-31 | 0.8 | spektr / Mistral Vibe | 64k-Grundabnahme des Swift-Profils in Testing bestanden und als datierter Ausführungsstand dokumentiert (Abschnitt 10.5); offen bleiben 128k (10.3), Wiederanlauf-/Profilwechsel (10.4) und die Unsloth-Wiederholung. | | 2026-11-01 | 0.9 | spektr / Mistral Vibe | 128k-Zielprofil in Testing aktiviert und technisch abgenommen (Abschnitt 10.6): kein OOM, saubere Kontextüberschreitungs-Negativtests, Prefill-Leiter 7,6k/29k/59,5k/121,9k Tokens (624/591/503/396 t/s) und 62 Minuten gemischte Stabilitätslast ohne Neustart. | +| 2026-11-01 | 0.10 | spektr / Mistral Vibe | Wiederanlauf- und Profilwechselabnahme (10.4) durchgeführt (Abschnitt 10.7): Idempotenz, kontrollierter Neustart und bewusster Stopp bestanden; Profilwechsel über die Rolle in beide Richtungen fehlerfrei und ohne erneuten Download. Befundkorrektur in 5.3: direkter Unit-Start löst keinen geordneten Wechsel aus (paralleles Laden in der Übergangsphase beobachtet); `Before=` aus den Quadlets entfernt, Rolle bleibt der alleinige geordnete Weg. Host-Reboot-Test an den Betreiber übertragen. | --- @@ -271,9 +272,20 @@ Profilwechsel bleibt zusätzlich eine explizite, sequenzielle Operation: 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. +**Korrektur vom 01.11.2026:** Ein direkter Start der jeweils anderen Unit +löst entgegen der ursprünglichen Annahme *keinen* geordneten Wechsel aus. +systemd führt den durch `Conflicts=` ausgelösten Stop der Gegeneinheit erst +nach Abschluss des Startvorgangs der neuen Unit aus; in der Übergangsphase +laden beide Modelle parallel in den VRAM (praktisch beobachtet am 01.11.2026, +beide Container `Up` gleichzeitig). `Conflicts=` sichert damit nur den +Endzustand der Exklusivität. Der geordnete Stop-vor-Start-Wechsel ist +ausschließlich die explizite Umschaltoperation der +`inference_engine`-Rolle (Zustand lesen, andere Unit stoppen, Start der +Ziel-Unit); ein manueller `systemctl start` beider Units nacheinander ist +kein unterstützter Betriebsweg. Da beide Modelle zusammen (zweimal rund +21 GiB Gewichte plus KV-Cache) die 32 GiB VRAM übersteigen, scheitert ein +unbeabsichtigter Parallelbetrieb am Ende am Speicher, statt dauerhaft mit +niedriger Geschwindigkeit zu laufen. ### 5.4 Entscheidung gegen den Router-Modus in der ersten Ausbaustufe @@ -622,6 +634,22 @@ präfixfreie Prompts verwendet, um echte Prefill-Leistung zu messen. Nicht Teil dieses Durchgangs: die Wiederanlauf- und Profilwechseltests nach 10.4 und die Wiederholung der Abnahmen für das Unsloth-Profil. +### 10.7 Belegter Ausführungsstand Wiederanlauf und Profilwechsel (01.11.2026) + +Die Tests nach 10.4 wurden am 01.11.2026 für die Testing-Umgebung gefahren: + +| Prüfpunkt (10.4) | Ergebnis | +| --- | --- | +| Zweiter identischer Ansible-Lauf | `changed=0` bei 128k-Konfiguration | +| Kontrollierter Containerneustart | `systemctl --user restart` erhält Profil und Modell: Alias `swift-qwen3.8-27b-q6k` unverändert, `/health` 200, kein erneuter Modelldownload | +| Bewusst gestoppter Dienst | nach `stop` über 90 Sekunden stabil `inactive`, keine Containerreste (`podman ps -a` leer), kein automatischer Neustart | +| Profilwechsel über die Rolle | Swift→Unsloth (`changed=1`) und Unsloth→Swift (`changed=2`): jeweils Health grün, korrekter Alias der Ziel-Unit, genau ein Modell im VRAM (13,4/14,7 GiB belegt), kein erneuter Download | +| Gegenseitiger Ausschluss bei direktem Start | **Befund:** `Conflicts=` sichert nur den Endzustand; ein direkter `systemctl --user start` der zweiten Unit während die erste läuft, lädt beide Modelle parallel in der Übergangsphase (beobachtet: beide Container `Up`). Kein supporteder Weg; Korrektur in 5.3 dokumentiert, `Before=` aus den Quadlets entfernt. Geordneter Wechsel ausschließlich über die Rolle. | +| Geplanter Hostneustart | offen; an den Betreiber übertragen (PVE-seitig `pct reboot`, danach Prüfung, dass nur die freigegebene Umgebung startet) | + +`podman ps`, systemd-Status und Health stimmten in allen Schritten überein +(10.4). Der Rückwechsel auf Swift erfolgte ohne erneuten Modelldownload. + ## 11. Noch nicht festgelegte Werte - genaue Health-Implementierung im gepinnten Containerimage; diff --git a/llm-server/llm/ansible/roles/inference_engine/templates/llama-server.container.j2 b/llm-server/llm/ansible/roles/inference_engine/templates/llama-server.container.j2 index 0ad981b..5744542 100644 --- a/llm-server/llm/ansible/roles/inference_engine/templates/llama-server.container.j2 +++ b/llm-server/llm/ansible/roles/inference_engine/templates/llama-server.container.j2 @@ -3,11 +3,14 @@ Description=LLM inference engine ({{ entry.profile_key }}) Wants={{ inference_engine_network_name }}-network.service After={{ inference_engine_network_name }}-network.service {% for other in entry.other_units %} +# Conflicts= only guarantees an exclusive END state. systemd runs the +# conflict stop of the other unit only after this unit finished starting, +# so a direct start of two engine units loads both models in parallel +# during the transition (observed 01.11.2026). The ordered +# stop-before-start switch is exclusively performed by the role's +# ai_environment_switch tasks (GNAI-010 section 5.3). Conflicts={{ other }} {% endfor %} -{% if entry.other_units | length == 1 %} -Before={{ entry.other_units | first }} -{% endif %} [Container] Image={{ inference_engine_image_ref }}