diff --git a/CHANGELOG.md b/CHANGELOG.md index d1fb59f..ed06a76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +# 2026-10-23 — Explizites 64K-Kontextfenster für Hermes + +- `model.context_length: 65536` passend zu beiden Hauptmodellprofilen gesetzt; + verhindert den beobachteten Alias-Fallback auf 256.000 Tokens. +- Bestehende CPU-Kompressionsschwelle von 24.000 Tokens beibehalten. +- Bereitstellung, Migration und Betriebsdokumentation aktualisiert; Regression + für alte Kontextwerte, Profilabgleich und wiederholte Konfiguration ergänzt. + # 2026-10-23 — Routineprofil und Begrenzung lokaler Inferenz - Qwen3.5-4B als Alltagsmodell, 27B als explizite Alternative und bestehendes diff --git a/README.md b/README.md index 3f6f4e6..633d8cc 100644 --- a/README.md +++ b/README.md @@ -134,6 +134,9 @@ Start des llama-Dienstes geladen, nicht bei der Konfigurationsprüfung. Die aktuellen Schutzmaßnahmen gegen endlose Modellantworten und die explizite Umschaltung zwischen Routine- und großem Modell stehen in [INFERENCE_LIMITS.md](docs/INFERENCE_LIMITS.md). +Hermes wird mit `model.context_length: 65536` auf das tatsächliche 64K-Fenster +beider Hauptmodellprofile eingestellt; die CPU-Kompression beginnt spätestens +bei 24.000 Tokens. ```bash hermes-stack-model status diff --git a/docs/INFERENCE_LIMITS.md b/docs/INFERENCE_LIMITS.md index f6d240c..3529bd0 100644 --- a/docs/INFERENCE_LIMITS.md +++ b/docs/INFERENCE_LIMITS.md @@ -20,6 +20,43 @@ Kompatibilitätsnamen für bestehende Sitzungen erreichbar. Sie bezeichnen dann ebenfalls das aktiv ausgewählte Modell; die tatsächliche Modelldatei zeigt `/props.model_path`. Neue Sitzungen und entbundene Cronjobs verwenden `hermes-local`. +## Kontextgröße und Kompression + +Beide Hauptmodellprofile starten mit `--ctx-size 65536`. Hermes muss dieselbe +Grenze kennen: `model.context_length: 65536` in `~/.hermes/config.yaml`. +Der lokale Alias `hermes-local` wurde bei der Live-Prüfung vom 23.10.2026 nicht +zuverlässig erkannt; Hermes meldete einen Fallback auf 256.000 Tokens. +Die explizite Grenze verhindert eine zu große Annahme bei Kontextverwaltung und +Platzplanung. Sie vergrößert weder das Modellfenster noch die GPU-Belegung. + +`scripts/prepare-workstation.py --configure-hermes` setzt die Grenze bei der +Einrichtung für Routine- und großes Profil. Bei einem späteren eigenen Profil +mit anderer `--ctx-size` muss `model.context_length` entsprechend mitgeändert +werden. + +Die bestehende CPU-Kompression bleibt bei `threshold: 0.5` und +`threshold_tokens: 24000`: Die absolute Obergrenze zieht die Kompression vor +die rechnerische 50-Prozent-Schwelle von 32.768 Tokens. `target_ratio: 0.2`, +Schutz der ersten drei und letzten zehn Nachrichten sowie die bestehenden +Zeitbudgets bleiben erhalten. Die Schwelle ist ein Auslöser, keine harte +Obergrenze für einzelne Nachrichten oder Werkzeugergebnisse. + +Für eine bestehende Installation genügt nach Abschluss laufender Aufträge: + +```bash +cp -p ~/.hermes/config.yaml ~/.hermes/config.yaml.before-context-64k +hermes config set model.context_length 65536 +hermes config get model.context_length +systemctl --user restart hermes-gateway.service +``` + +Den Sicherungsnamen bei wiederholter Ausführung ändern, damit die frühere +Sicherung erhalten bleibt. Der Hauptmodell- und CPU-Kompressionsdienst brauchen +für diese Hermes-Einstellung keinen Neustart. Neue Sitzungen verwenden die neue +Grenze; bereits im Agentzustand gehaltene Kontextwerte sind kein verlässlicher +Nachweis. Zur Abnahme eine neue Sitzung öffnen und die Modellantwort sowie das +Gateway-Protokoll auf erneute Kontext-Fallback-Warnungen prüfen. + ## Drei Schutzebenen - Der Runner setzt `--n-predict 2048` als Serverstandard. Das ist kein harter diff --git a/docs/NEW_WORKSTATION.md b/docs/NEW_WORKSTATION.md index e7d3115..1babb88 100644 --- a/docs/NEW_WORKSTATION.md +++ b/docs/NEW_WORKSTATION.md @@ -106,7 +106,9 @@ verzeichnis verschieben. Das gilt auch für `LLAMA_SERVER_BIN`. `--configure-hermes` aktualisiert mit Backup die lokalen Provider-, Vision- und optional Kompressionseinstellungen, das 30-Minuten-Auftragsbudget und die -600-Sekunden-/2048-Token-Limits. Fremde Provider, Terminal, Plugins und andere +600-Sekunden-/2048-Token-Limits. Dabei setzt er `model.context_length: 65536` +passend zu beiden Hauptmodellprofilen. Bei CPU-Kompression bleibt die +Kompressionsschwelle auf 24.000 Tokens begrenzt. Fremde Provider, Terminal, Plugins und andere Einstellungen bleiben bestehen. `--unpin-local-cron` löst nur bekannte lokale Modellbindungen über die Hermes-CLI; eigene Cloud-Provider bleiben gebunden. Die Option legt keine Cronjobs an. Vorhandene Cronjobs kommen aus dem privaten diff --git a/docs/VALIDATION.md b/docs/VALIDATION.md index 2c88fac..95faaec 100644 --- a/docs/VALIDATION.md +++ b/docs/VALIDATION.md @@ -1,3 +1,25 @@ +# Validierung vom 2026-10-23 — Kontextabgleich + +- `make test`: Syntax-/Secret-Musterprüfung und **52 Funktionstests bestanden** + (26 llama-, zehn Watchdog-, elf Workstation- und fünf Updater-Tests). + ShellCheck fehlt lokal und wurde nicht ausgeführt. +- Regression prüft Ersatz eines veralteten 256.000-Token-Werts, Abgleich mit + beiden 65.536-Token-Hauptmodellprofilen, Erhalt der 24.000-Token- + Kompressionsschwelle und unveränderten zweiten Konfigurationslauf. +- `git diff --check`: erfolgreich. +- Auf Archwork ausschließlich `model.context_length: 65536` ergänzt; + semantischer YAML-Vergleich bestätigt, dass keine andere Einstellung geändert + wurde. Private Sicherung unter + `~/.local/state/hermes-stack-maintenance/context-64k-20261023-144440/config.yaml`. +- Gateway kontrolliert neu gestartet; Hauptmodell und CPU-Kompression ohne + Neustart. `hermes config get model.context_length` liefert `65536`. +- Neue lokale Hermes-Sitzung über den Gateway antwortet korrekt mit + `HERMES_OK 323`. Seit der Aktivierung keine erneute Kontext-Fallback-Warnung + im Hermes-Fehlerprotokoll. Bestehende Plugin-/Docker-Warnungen bleiben sichtbar. +- Kein langer 64K-Dialog, keine erzwungene Kompression und kein Test des großen + Modells für diese Änderung; der Live-Nachweis gilt für die neue kurze Sitzung + mit dem aktiven Routineprofil. + # Validierung vom 2026-10-21 - `make test`: Syntax- und Secret-Musterprüfung sowie **31 Funktionstests diff --git a/scripts/prepare-workstation.py b/scripts/prepare-workstation.py index 0cbccde..801c9e4 100755 --- a/scripts/prepare-workstation.py +++ b/scripts/prepare-workstation.py @@ -96,7 +96,8 @@ def profile_config(name, paths, server_bin=""): def configure_hermes(config, compression=False): - config.setdefault("model", {}).update(default="hermes-local", provider="custom", base_url=LOCAL_URL) + config.setdefault("model", {}).update(default="hermes-local", provider="custom", + base_url=LOCAL_URL, context_length=65536) config.setdefault("agent", {}).update(run_budget_seconds=1800, budget_warning_ratio=0.8) config.setdefault("providers", {}).setdefault("custom", {}).update( request_timeout_seconds=600, stale_timeout_seconds=180) diff --git a/tests/test_workstation.py b/tests/test_workstation.py index 76715ae..d4fc21a 100644 --- a/tests/test_workstation.py +++ b/tests/test_workstation.py @@ -58,6 +58,22 @@ class PreparationTests(unittest.TestCase): self.assertEqual(updated["custom_providers"][1]["extra_body"]["max_tokens"], 2048) self.assertEqual(updated["auxiliary"]["compression"]["base_url"], "http://127.0.0.1:8081/v1") + def test_context_matches_both_main_profiles_and_replaces_stale_window(self): + for previous in (None, 256000): + with self.subTest(previous=previous): + config = {"model": {"context_length": previous}, + "compression": {"threshold_tokens": 24000}} + prepare.configure_hermes(config) + window = config["model"]["context_length"] + self.assertEqual(window, 65536) + for name in ("routine", "large"): + text = prepare.profile_config(name, [self.root / "weights.gguf"]) + self.assertIn(f"--ctx-size {window}", text) + self.assertEqual(config["compression"]["threshold_tokens"], 24000) + before = json.dumps(config, sort_keys=True) + prepare.configure_hermes(config) + self.assertEqual(json.dumps(config, sort_keys=True), before) + def test_existing_profiles_preserved_and_explicit_selection_backed_up(self): path = self.root / "llama.env" path.write_text("custom tuning\n")