Fix: Re-Warm-Waechter + Startup-Warmup folgen dem aktiven Hirn (nicht mehr fix "hermes")
Nach dem Hirn-Wechsel auf fast (Qwen3.6) zeigte der Wächter noch auf "hermes" (Hermes-4-14B) -> er haette das aus dem Warm-Set entfernte Modell wieder geladen. warmer._brain_model() liest jetzt Hermes' model.default (Fallback fast); Startup-Warmup BRAINS default "fast". Passt sich kuenftigen Hirn-Wechseln automatisch an. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+1
-1
@@ -34,7 +34,7 @@ async def lifespan(app: FastAPI):
|
|||||||
"""Hintergrund-Tasks an den App-Lebenszyklus binden: Re-Warm-Wächter fürs Agent-Hirn."""
|
"""Hintergrund-Tasks an den App-Lebenszyklus binden: Re-Warm-Wächter fürs Agent-Hirn."""
|
||||||
task = asyncio.create_task(warmer.rewarm_loop()) if warmer.ENABLED else None
|
task = asyncio.create_task(warmer.rewarm_loop()) if warmer.ENABLED else None
|
||||||
if task:
|
if task:
|
||||||
log.info("Hirn-Re-Warm-Wächter aktiv (Intervall %ss, Modell '%s')", warmer.INTERVAL, warmer.MODEL)
|
log.info("Hirn-Re-Warm-Wächter aktiv (Intervall %ss, Hirn dynamisch aus Hermes-Config)", warmer.INTERVAL)
|
||||||
try:
|
try:
|
||||||
yield
|
yield
|
||||||
finally:
|
finally:
|
||||||
|
|||||||
@@ -23,10 +23,31 @@ log = logging.getLogger(__name__)
|
|||||||
|
|
||||||
ENABLED = os.environ.get("MC_REWARM_ENABLED", "1") != "0"
|
ENABLED = os.environ.get("MC_REWARM_ENABLED", "1") != "0"
|
||||||
INTERVAL = int(os.environ.get("MC_REWARM_INTERVAL", "90")) # Sekunden zwischen Checks
|
INTERVAL = int(os.environ.get("MC_REWARM_INTERVAL", "90")) # Sekunden zwischen Checks
|
||||||
MODEL = os.environ.get("MC_REWARM_MODEL", "hermes") # Alias der Rolle
|
|
||||||
START_DELAY = int(os.environ.get("MC_REWARM_START_DELAY", "25"))
|
START_DELAY = int(os.environ.get("MC_REWARM_START_DELAY", "25"))
|
||||||
|
|
||||||
|
|
||||||
|
def _brain_model() -> str:
|
||||||
|
"""Aktives Agent-Hirn = Hermes' model.default (sonst model.model). So wärmt der Wächter
|
||||||
|
immer das WIRKLICH genutzte Hirn (passt sich Hirn-Wechseln an). Override: MC_REWARM_MODEL."""
|
||||||
|
forced = os.environ.get("MC_REWARM_MODEL")
|
||||||
|
if forced:
|
||||||
|
return forced
|
||||||
|
try:
|
||||||
|
from ruamel.yaml import YAML
|
||||||
|
from config import HERMES_HOME
|
||||||
|
p = HERMES_HOME / "config.yaml"
|
||||||
|
if p.exists():
|
||||||
|
with p.open(encoding="utf-8") as f:
|
||||||
|
cfg = YAML().load(f) or {}
|
||||||
|
m = (cfg.get("model") or {}) if isinstance(cfg, dict) else {}
|
||||||
|
v = m.get("default") or m.get("model")
|
||||||
|
if v:
|
||||||
|
return str(v)
|
||||||
|
except Exception:
|
||||||
|
log.debug("rewarm: Hirn-Lookup fehlgeschlagen", exc_info=True)
|
||||||
|
return "fast"
|
||||||
|
|
||||||
|
|
||||||
async def _running_empty() -> bool:
|
async def _running_empty() -> bool:
|
||||||
async with httpx.AsyncClient(timeout=8.0) as c:
|
async with httpx.AsyncClient(timeout=8.0) as c:
|
||||||
r = await c.get(f"{LLAMA_SWAP_URL}/running")
|
r = await c.get(f"{LLAMA_SWAP_URL}/running")
|
||||||
@@ -34,10 +55,10 @@ async def _running_empty() -> bool:
|
|||||||
return not (data.get("running") or [])
|
return not (data.get("running") or [])
|
||||||
|
|
||||||
|
|
||||||
async def _warm() -> None:
|
async def _warm(model: str) -> None:
|
||||||
async with httpx.AsyncClient(timeout=180.0) as c:
|
async with httpx.AsyncClient(timeout=180.0) as c:
|
||||||
await c.post(f"{LLAMA_SWAP_URL}/v1/chat/completions", json={
|
await c.post(f"{LLAMA_SWAP_URL}/v1/chat/completions", json={
|
||||||
"model": MODEL, "max_tokens": 1,
|
"model": model, "max_tokens": 1,
|
||||||
"messages": [{"role": "user", "content": "ping"}],
|
"messages": [{"role": "user", "content": "ping"}],
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -48,8 +69,9 @@ async def rewarm_loop() -> None:
|
|||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
if await _running_empty():
|
if await _running_empty():
|
||||||
log.info("rewarm: Box idle → Hirn '%s' wird vorgewärmt", MODEL)
|
model = _brain_model()
|
||||||
await _warm()
|
log.info("rewarm: Box idle → Hirn '%s' wird vorgewärmt", model)
|
||||||
|
await _warm(model)
|
||||||
except Exception:
|
except Exception:
|
||||||
log.debug("rewarm: Tick fehlgeschlagen", exc_info=True)
|
log.debug("rewarm: Tick fehlgeschlagen", exc_info=True)
|
||||||
await asyncio.sleep(INTERVAL)
|
await asyncio.sleep(INTERVAL)
|
||||||
|
|||||||
+5
-5
@@ -1,13 +1,13 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# Lädt die "brains" (hermes/fast/vision) nach einem llama-swap-(Re)Start vor,
|
# Lädt das warme "brains"-Set nach einem llama-swap-(Re)Start vor, damit die ERSTE
|
||||||
# damit die ERSTE Anfrage nicht kalt ist (llama-swap lädt sonst lazy bei Bedarf).
|
# Anfrage nicht kalt ist (llama-swap lädt sonst lazy bei Bedarf).
|
||||||
# Eingehängt als ExecStartPost=-/usr/local/bin/llama-swap-warmup.sh in llama-swap.
|
# Eingehängt als ExecStartPost=-/usr/local/bin/llama-swap-warmup.sh in llama-swap.
|
||||||
#
|
#
|
||||||
# Selbst-detachend: der ExecStartPost-Aufruf kehrt sofort zurück (blockiert den
|
# `fast` = das Agent-Hirn (Qwen3.6-35B-A3B); Pingen eines brains-Gruppen-Mitglieds lädt die
|
||||||
# Service-Start NICHT); die eigentliche Aufwärmung läuft entkoppelt im Hintergrund.
|
# ganze (ko-residente) Gruppe. Selbst-detachend: blockiert den Service-Start nicht.
|
||||||
set -u
|
set -u
|
||||||
URL="${MC_LLAMA_SWAP_URL:-http://127.0.0.1:8080}"
|
URL="${MC_LLAMA_SWAP_URL:-http://127.0.0.1:8080}"
|
||||||
BRAINS="${MC_WARMUP_MODELS:-hermes fast vision}"
|
BRAINS="${MC_WARMUP_MODELS:-fast}"
|
||||||
|
|
||||||
if [ "${1:-}" != "--inner" ]; then
|
if [ "${1:-}" != "--inner" ]; then
|
||||||
setsid "$0" --inner >/dev/null 2>&1 &
|
setsid "$0" --inner >/dev/null 2>&1 &
|
||||||
|
|||||||
Reference in New Issue
Block a user