Kontext-Limit sichtbar machen: Gateway-Warnung bei finish_reason=length + Etappen-Regel
User-Wunsch 15.07. ('es sollte eine Warnung geben - Kontext ist nicht
unendlich'): 4 P3-Worker starben still an finish_reason=length.
- Gateway erkennt abgerissene Antworten (Stream-Chunk + Non-Stream) und
meldet je Modell max. alle 10 min in den Briefkasten (silent -> Chronik),
Zustellung per MC_ANNOUNCE_HTTP ans Steuerpult (Store bleibt Ein-Schreiber).
- Steckbrief-Hook: KONTEXT-BUDGET & ETAPPEN-REGEL - gezielt lesen, grosse
Aufgaben in Etappen schneiden (kanban_create/complete mit Plan) statt
am Limit zu sterben.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -7,11 +7,38 @@ verstreute, still scheiternde String-Suche durch einen testbaren SSE-Zeilenparse
|
||||
|
||||
import json
|
||||
import logging
|
||||
import time
|
||||
|
||||
from services.token_stats import increment_tokens
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
# Kontext-Limit-Warnung (User-Wunsch 15.07.: „es sollte eine Warnung geben — Kontext ist
|
||||
# nicht unendlich"): finish_reason=length heißt, eine Antwort ist am Token-/Kontext-Budget
|
||||
# ABGERISSEN — bei Nacht-Workern stirbt damit still die halbe Arbeit (4 Worker am 15.07.).
|
||||
# Statt still: Eintrag in den Briefkasten (silent → Chronik/Panel, kein Sprach-Spam),
|
||||
# je Modell höchstens alle 10 min. Läuft im mc2-gateway-Prozess → announce liefert per
|
||||
# MC_ANNOUNCE_HTTP beim Steuerpult ab (Unit-Env), nie direkt in die Store-Datei.
|
||||
_trunc_last: dict[str, float] = {}
|
||||
_TRUNC_EVERY = 600.0 # s
|
||||
|
||||
|
||||
def warn_truncation(model: str) -> None:
|
||||
now = time.time()
|
||||
if now - _trunc_last.get(model, 0.0) < _TRUNC_EVERY:
|
||||
return
|
||||
_trunc_last[model] = now
|
||||
log.warning("gateway: finish_reason=length bei %s — Antwort am Kontext-/Token-Limit abgerissen", model)
|
||||
try:
|
||||
from services import announce
|
||||
announce.add(
|
||||
f"Eine Antwort von „{model}“ ist am Token-/Kontext-Limit abgerissen "
|
||||
f"(finish_reason=length). War das ein Nacht-Worker, ist seine Aufgabe zu groß "
|
||||
f"geschnitten — besser in Etappen teilen (eine Etappe = ein Worker-Lauf).",
|
||||
"[Kontext-Limit]", "gateway", "silent")
|
||||
except Exception:
|
||||
log.warning("gateway: Kontext-Limit-Warnung nicht zustellbar", exc_info=True)
|
||||
|
||||
|
||||
def record_usage(usage: dict | None, model: str) -> None:
|
||||
"""Ein usage-Objekt verbuchen (no-op bei None/leer)."""
|
||||
@@ -26,6 +53,8 @@ def record_usage(usage: dict | None, model: str) -> None:
|
||||
def record_stream_chunk(chunk: bytes, model: str) -> None:
|
||||
"""Rohen SSE-Chunk auf `usage` prüfen und Tokens verbuchen. Fehler werden
|
||||
geloggt (debug) statt verschluckt — ein defekter Chunk bricht den Stream nicht."""
|
||||
if b'"finish_reason":"length"' in chunk or b'"finish_reason": "length"' in chunk:
|
||||
warn_truncation(model)
|
||||
if b'"usage"' not in chunk:
|
||||
return
|
||||
text = chunk.decode("utf-8", errors="ignore")
|
||||
|
||||
Reference in New Issue
Block a user