Feat: setup-bewusste ctx-Vergabe - eine Quelle der Wahrheit (services/budget.py)
Bisher rechnete nur der Hirn-Wechsel setup-bewusst; die allgemeine ctx-Auto-Groesse
nahm den Gesamt-RAM in ISOLATION (ignorierte Hirn/warmes Set/Ko-Residenz) -> ctx
konnte zu gross gewaehlt werden.
Neu: services/budget.py buendelt GTT-Budget, Modell-Footprint und reservierten Speicher
gemaess VERIFIZIERTER Box-Residenz (Hirn immer resident; fast/vision duerfen weichen,
wenn grosses on-demand-Modell laedt). setup_aware_ctx() bemisst den groessten ctx, der
NEBEN dem bestehenden Setup passt - rollen-/gruppen-bewusst aus der echten Config.
- fit.py: max_ctx_in_budget() als budget-basierter Kern; max_ctx_for() delegiert
- models.py: install nutzt setup_aware_ctx; /api/fit liefert assigned_ctx + Budget-Herleitung
- agent.py: nutzt die gemeinsamen Helfer (entfernt Duplikate _gtt_budget_gb/_foot)
- AddModel: Ampel zeigt den setup-bewussten ctx ('ctx -> Nk') inkl. Budget-Tooltip;
Rollen-Wechsel laedt die Vorschau neu (Rolle bestimmt das Budget)
Effekt: heavy-122B bekommt z.B. 16k statt 131072 (passt neben dem Hirn), waehrend
warme Kleinmodelle weiter grossen Kontext erhalten.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -25,19 +25,6 @@ def _hermes_version(name: str) -> float | None:
|
||||
return float(m.group(1)) if m else None
|
||||
|
||||
|
||||
def _gtt_budget_gb() -> float:
|
||||
"""GPU-adressierbarer Speicher (GTT) in GB — die harte Obergrenze. Liest
|
||||
amdgpu.gttsize aus /proc/cmdline, sonst RAM minus OS-Reserve."""
|
||||
try:
|
||||
with open("/proc/cmdline") as f:
|
||||
m = re.search(r"amdgpu\.gttsize=(\d+)", f.read())
|
||||
if m:
|
||||
return round(int(m.group(1)) / 1024.0, 1)
|
||||
except Exception:
|
||||
pass
|
||||
return round(psutil.virtual_memory().total / (1024 ** 3) - 6.0, 1)
|
||||
|
||||
|
||||
def hermes_brain_info() -> dict:
|
||||
"""Aktuelles Agent-Hirn (hermes-Rolle) + bestes verfügbares NousResearch-Hermes-Modell,
|
||||
das auf diese Hardware passt. Für den Modell-Manager: Brain sichtbar + updatebar,
|
||||
@@ -93,42 +80,27 @@ def hermes_brain_info() -> dict:
|
||||
# größte on-demand-Modell daneben lädt? (Brain muss immer resident sein.)
|
||||
budget = None
|
||||
try:
|
||||
from services.fit import QUANT_BYTES_PER_PARAM, estimate_memory_gb
|
||||
from services.budget import footprint_gb, gtt_budget_gb
|
||||
from services.fit import estimate_memory_gb
|
||||
groups = llamaswap.list_groups()
|
||||
persist = set()
|
||||
for g in groups.values():
|
||||
if isinstance(g, dict) and g.get("persist"):
|
||||
persist.update(g.get("members") or [])
|
||||
|
||||
def _foot(m: dict) -> float:
|
||||
"""Loaded-Footprint = Gewichte + kalibrierter KV-Anteil. Params robust aus dem
|
||||
MAXIMUM von Namens-Schätzung und Dateigröße (deckt beides ab: 'Coder-Next' ohne
|
||||
Größe im Namen → aus Datei; Split-GGUFs wie heavy → aus Namen, da size_bytes nur
|
||||
den ersten Teil zählt)."""
|
||||
caps = m.get("capabilities") or {}
|
||||
quant = m.get("quant") or "Q4_K_M"
|
||||
ctx = int(m.get("ctx") or 32768)
|
||||
bpp = QUANT_BYTES_PER_PARAM.get(quant.upper(), 0.55)
|
||||
size_gb = (m.get("size_bytes") or 0) / (1024 ** 3)
|
||||
pb_size = (size_gb / bpp) if size_gb > 1.0 else 0.0 # Split-Teil → ignoriert
|
||||
pb = max(float(caps.get("params_b") or 0), pb_size, 7.0)
|
||||
weights = max(pb * bpp, size_gb)
|
||||
kv = estimate_memory_gb(pb, quant, ctx) - pb * bpp
|
||||
return weights + max(kv, 0.0)
|
||||
|
||||
cur_name = cur["name"] if cur else None
|
||||
brain_ctx = int((cur.get("ctx") if cur else None) or 32768)
|
||||
if best:
|
||||
brain_gb = estimate_memory_gb(float(best["params_b"]), "Q4_K_M", brain_ctx)
|
||||
elif cur:
|
||||
brain_gb = _foot(cur)
|
||||
brain_gb = footprint_gb(cur)
|
||||
else:
|
||||
brain_gb = 0.0
|
||||
# voller Always-Warm-Footprint (alle persist, Brain=Empfehlung) — nur Info
|
||||
warm = brain_gb + sum(_foot(m) for m in models
|
||||
warm = brain_gb + sum(footprint_gb(m) for m in models
|
||||
if m["name"] in persist and m["name"] != cur_name)
|
||||
largest_od = max((_foot(m) for m in models if m["name"] not in persist), default=0.0)
|
||||
gtt = _gtt_budget_gb()
|
||||
largest_od = max((footprint_gb(m) for m in models if m["name"] not in persist), default=0.0)
|
||||
gtt = gtt_budget_gb()
|
||||
# Brain muss immer resident sein → passt Brain + größtes on-demand zusammen?
|
||||
# (fast/vision dürfen beim Laden eines großen Modells verdrängt werden.)
|
||||
budget = {
|
||||
|
||||
Reference in New Issue
Block a user