bilder: Hirn und Coder sehen selbst - ueber Bild-Zwillinge, Text bleibt mit Draft schnell
Ampel / ampel (push) Failing after 21s

llama.cpp kann Draft-Beschleunigung und Bilder nicht zusammen (HTTP 500 "failed to process
speculative batch", b11057 und b11157 geprueft; speculative.n_max=0 je Anfrage hilft nicht).
Darum bekommen Hirn und Coder je einen Bild-Zwilling: gleiche Gewichte plus Projektor, ohne
Draft (vision, coder-bild), in einer eigenen llama-swap-Gruppe, die den Coder nicht verdraengt.
Probe 24.09.: beide 8/8 Bildmerkmale; Hirn-Zwilling 68 t/s, Coder-Zwilling 12,5 t/s.

Bild-Weiche v3 im Gateway: Bild im aktuellen Schritt geht an den Zwilling der Rolle, aeltere
Bilder werden einmal beschrieben (gemerkt) und als Text mitgeschickt, damit der Rest einer
Agenten-Aufgabe wieder beim schnellen Modell laeuft. Qwen3-VL gibt "vision" ab, der Coder
verliert den Projektor, der mit Draft nur HTTP 500 lieferte.

Radar misst die Bildfaehigkeit des heutigen Modells ueber dessen Zwilling (sonst gewaenne
jeder bildfaehige Kandidat mit "versteht Bilder"). Pruefstand: Coder darf vor dem Aendern
lesen (Version 3). Modelle-Seite zeigt "Bilder: ja" ueber den Zwilling.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Hitonabi
2026-09-24 13:02:06 +02:00
co-authored by Claude Opus 5.5
parent 2cc1e1cc47
commit 91aa16eee1
17 changed files with 497 additions and 230 deletions
+18 -6
View File
@@ -62,7 +62,7 @@ HERMES = os.path.expanduser("~/.local/bin/hermes")
CTX_STANDARD = 65536
# Stand der Proben. Ändern sich Aufgaben oder Werkzeuge, ist eine gecachte Baseline nicht mehr
# vergleichbar — baseline() misst dann neu. Bei jeder Änderung an den Proben hochzählen.
PRUEFSTAND_VERSION = 2
PRUEFSTAND_VERSION = 3 # 24.09.: Coder darf vor dem Ändern lesen (Bild im Ablauf)
# Flags wie am 17.09. (der Kontext kommt je Kandidat dazu): voller GPU-Offload, Flash-Attention,
# kein mmap (--load-mode none, das alte --no-mmap gibt es seit b10936 nicht mehr), ein Slot,
# KV-Cache q8_0 wie im Betrieb.
@@ -709,6 +709,15 @@ def _bild_im_ablauf(basis: str, modell: str, rolle: str, url: str, frist: float
]
j = chat(basis, modell, verlauf, WERKZEUG_TOKENS, werkzeuge, frist=frist)
aufrufe = _nachricht(j).get("tool_calls") or []
lesen = next((a for a in aufrufe if (a.get("function") or {}).get("name") == "read"), None)
if rolle != "hirn" and lesen and not trifft(aufrufe, erwartet):
# Ein guter Coding-Agent liest die Datei, bevor er sie ändert (24.09.: der Coder tat genau das und
# galt als gescheitert). Dann den Inhalt liefern und nach dem nächsten Schritt fragen.
verlauf += [{"role": "assistant", "content": "", "tool_calls": [lesen]},
{"role": "tool", "tool_call_id": lesen.get("id") or "call_lesen",
"content": 'PORT = 8080\nHOST = "0.0.0.0"\n'}]
j = chat(basis, modell, verlauf, WERKZEUG_TOKENS, werkzeuge, frist=frist)
aufrufe = _nachricht(j).get("tool_calls") or []
return {"ok": trifft(aufrufe, erwartet), "aufrufe": _aufrufe_kurz(aufrufe),
"antwort": "" if aufrufe else _text(j)[:160]}
@@ -734,8 +743,10 @@ def messe_bild(basis: str, modell: str, rolle: str, frist: float | None = None)
# --- Gesamtprüfung ---------------------------------------------------------------------
def pruefe(rolle: str, basis: str, modell: str, *, bild: bool = False, frist: float | None = None,
protokoll=log) -> dict:
"""Alle Proben der Rolle gegen ein laufendes Modell (Kandidat auf :5899 oder Baseline über llama-swap)."""
protokoll=log, bild_modell: str | None = None) -> dict:
"""Alle Proben der Rolle gegen ein laufendes Modell (Kandidat auf :5899 oder Baseline über llama-swap).
bild_modell: wer die Bild-Probe macht, wenn es nicht das Modell selbst ist — seit 24.09. sehen Hirn und
Coder über ihren Bild-Zwilling (vision, coder-bild), weil Draft und Bild in llama.cpp nicht zusammengehen."""
if rolle not in ALIAS:
raise ValueError(f"Unbekannte Rolle {rolle!r}")
t0 = time.time()
@@ -755,7 +766,7 @@ def pruefe(rolle: str, basis: str, modell: str, *, bild: bool = False, frist: fl
werte["bild"] = None
if bild:
try:
werte["bild"] = messe_bild(basis, modell, rolle, frist)
werte["bild"] = messe_bild(basis, bild_modell or modell, rolle, frist)
except Zeitende:
raise
except Exception as e:
@@ -948,7 +959,7 @@ def _schreibe_json(pfad: str, daten: dict) -> None:
def baseline(rolle: str, cache_pfad: str, *, kennung: str, bild: bool = False, frist: float | None = None,
max_alter_tage: int = 30, basis_url: str = SWAP_URL, modell: str | None = None,
protokoll=log) -> dict | None:
protokoll=log, bild_modell: str | None = None) -> dict | None:
"""Werte des heutigen Modells der Rolle, höchstens alle max_alter_tage neu gemessen.
kennung = welches Modell mit welchen Flags (ändert sie sich, wird neu gemessen).
Rückgabe {"kennung", "zeit", "werte"} oder None, wenn es weder Cache noch Messung gibt."""
@@ -960,7 +971,8 @@ def baseline(rolle: str, cache_pfad: str, *, kennung: str, bild: bool = False, f
return passend
protokoll(f" Baseline {rolle} wird neu gemessen ({modell or ALIAS[rolle]} über llama-swap)")
try:
werte = pruefe(rolle, basis_url, modell or ALIAS[rolle], bild=bild, frist=frist, protokoll=protokoll)
werte = pruefe(rolle, basis_url, modell or ALIAS[rolle], bild=bild, frist=frist, protokoll=protokoll,
bild_modell=bild_modell)
except Zeitende:
raise
except Exception as e: