feat: stufen-spezifisches Token-Limit für die Solver-Stufe (LLM_MAX_TOKENS_SOLVER)
Die Solver-Stufe erzeugt langen Python-Code plus Reasoning. Bei komplexen Aufgaben (Portfoliomanagement: 4× je ~26k Reasoning-Tokens am 32k-Limit abgeschnitten, $0,28 für nichts) reichte das globale Limit nicht. DeepSeek V4.1 Flash unterstützt bis 393k Output-Tokens (OpenRouter). Neu: LLM_MAX_TOKENS_SOLVER (Default 65536, 0 = globales Limit gilt auch für den Solver). Wirkt nur für die Stufen 'Solver-Code' und 'Solver-Reparatur'. CLI-Option --max-tokens-solver. 438 Tests grün.
This commit is contained in:
parent
e80a104cf9
commit
e7a2b8de81
1 changed files with 51 additions and 11 deletions
15
core/llm.py
15
core/llm.py
|
|
@ -47,6 +47,11 @@ LLM_TIMEOUT = int(os.environ.get("LLM_TIMEOUT", "420")) # Sekunden je Aufruf
|
|||
# Ohne Vorgabe schneiden manche OpenRouter-Anbieter die Antwort ab (beobachtet: abgebrochene
|
||||
# Modellspezifikation in einer Korrekturrunde). Großzügig setzen; bezahlt werden nur erzeugte Tokens.
|
||||
LLM_MAX_TOKENS = int(os.environ.get("LLM_MAX_TOKENS", "32000"))
|
||||
# Die Solver-Stufe erzeugt langen Python-Code plus Reasoning – bei komplexen Aufgaben (beobachtet:
|
||||
# Portfoliomanagement, 4× je ~26k Reasoning-Tokens am 32k-Limit abgeschnitten) reicht das globale
|
||||
# Limit nicht. DeepSeek V4.1 Flash unterstützt bis 393k Output-Tokens (OpenRouter), wir setzen die
|
||||
# Solver-Stufe bewusst höher. 0 = das globale Limit gilt auch für den Solver.
|
||||
LLM_MAX_TOKENS_SOLVER = int(os.environ.get("LLM_MAX_TOKENS_SOLVER", "65536"))
|
||||
# Denkaufwand (OpenRouter): "low" | "medium" | "high"; leer = Modellvorgabe.
|
||||
# Reasoning-Tokens machen den Großteil der Laufzeit aus (gemessen: 45.000 von 73.000 Output-Tokens).
|
||||
REASONING_EFFORT = os.environ.get("LLM_REASONING_EFFORT", "").strip().lower()
|
||||
|
|
@ -159,10 +164,14 @@ class LLMSession:
|
|||
"""Stufen mit abweichendem Modell – für die Fortschrittsausgabe."""
|
||||
return {step: m for step, m in self.step_models.items() if m != self.model}
|
||||
|
||||
def _kwargs(self, model: str, response_model, messages) -> dict:
|
||||
def _kwargs(self, model: str, response_model, messages, step: str = "") -> dict:
|
||||
kwargs = {"model": model, "response_model": response_model, "messages": messages}
|
||||
if provider_for(model) == "openrouter":
|
||||
kwargs["max_tokens"] = LLM_MAX_TOKENS
|
||||
# Solver-Stufe bekommt ein eigenes, höheres Limit (siehe LLM_MAX_TOKENS_SOLVER).
|
||||
if step in ("Solver-Code", "Solver-Reparatur") and LLM_MAX_TOKENS_SOLVER > 0:
|
||||
kwargs["max_tokens"] = LLM_MAX_TOKENS_SOLVER
|
||||
else:
|
||||
kwargs["max_tokens"] = LLM_MAX_TOKENS
|
||||
# nur Anbieter wählen, die strukturierte Ausgabe (response_format) wirklich unterstützen
|
||||
anbieter = {"require_parameters": True, "preferred_min_throughput": {"p50": OPENROUTER_MIN_THROUGHPUT}}
|
||||
if self.ignored_providers:
|
||||
|
|
@ -177,7 +186,7 @@ class LLMSession:
|
|||
provider = provider_for(model)
|
||||
waits = list(RETRY_WAITS)
|
||||
while True:
|
||||
kwargs = self._kwargs(model, response_model, messages)
|
||||
kwargs = self._kwargs(model, response_model, messages, step)
|
||||
started = time.monotonic()
|
||||
try:
|
||||
result, completion = self._clients[provider].chat.completions.create_with_completion(**kwargs)
|
||||
|
|
|
|||
Loading…
Reference in a new issue