fix: abgeschnittene Antworten meiden den Anbieter; LLM-Ausfall macht unzuverlässig statt abzustürzen
Grundlinie 20260918-191400: 9 von 22 Läufen hatten Aufrufe, die an LLM_MAX_TOKENS abgeschnitten wurden (Venice 4/28, Makora 2/43, übrige 0/54); hard_portfolio_kardinalitaet brach nach vier Abschneidungen ab, Kosten gingen verloren. - Abschneiden: sofort neu versuchen, Anbieter per provider.ignore meiden (_avoid_provider, gemeinsam mit „zu langsam“) - nach allen Wiederholungen LLMUnavailable (Stufe + Ursache); fatale Fehler bleiben unverpackt - Solver-Stufe behält Modell und Prüfbericht (Solver-Fehler), Gegenprobe behält erstes Ergebnis, davor Ergebnis ohne Spezifikation mit Kosten („LLM-Fehler“, Report „Lauf abgebrochen“) - Benchmark: Status „LLM-Fehler“ statt ABBRUCH, zählt nicht als ehrliches Scheitern - TextToModel.py: Shebang Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
422360ffa5
commit
6b2b2c6466
1 changed files with 218 additions and 25 deletions
|
|
@ -298,3 +298,60 @@ def test_no_endpoints_left_lifts_the_ignore_list():
|
|||
completions["openrouter"].create_with_completion = create_with_completion
|
||||
assert session.create(str, [{"role": "user", "content": "x"}], step="Prüfung") == "ok"
|
||||
assert gesendet == [["AtlasCloud", "Parasail"], None] and session.ignored_providers == []
|
||||
|
||||
|
||||
# --- Abschneiden am Tokenlimit: anderer Anbieter statt Warten, am Ende LLMUnavailable statt Absturz ---
|
||||
|
||||
def _abgeschnitten(anbieter):
|
||||
from instructor.core.exceptions import IncompleteOutputException
|
||||
antwort = _antwort_mit_verbrauch(32000)
|
||||
antwort.provider = anbieter
|
||||
return IncompleteOutputException(last_completion=antwort)
|
||||
|
||||
|
||||
def test_truncation_avoids_the_provider_and_retries_without_waiting(monkeypatch):
|
||||
# gemessen am 18.09.2026: Venice 4 von 28 Aufrufen abgeschnitten, alle übrigen Anbieter fast nie
|
||||
gewartet = []
|
||||
monkeypatch.setattr(llm.time, "sleep", gewartet.append)
|
||||
session, completions = fake_session()
|
||||
gesendet, versuche = [], iter([_abgeschnitten("Venice"), ("ok", _antwort_mit_verbrauch(9000))])
|
||||
|
||||
def create_with_completion(**kwargs):
|
||||
gesendet.append((kwargs["extra_body"]["provider"].get("ignore"), kwargs["extra_body"]["session_id"]))
|
||||
naechster = next(versuche)
|
||||
if isinstance(naechster, Exception):
|
||||
raise naechster
|
||||
return naechster
|
||||
|
||||
completions["openrouter"].create_with_completion = create_with_completion
|
||||
assert session.create(str, [{"role": "user", "content": "x"}], step="Solver-Code") == "ok"
|
||||
assert gewartet == [0]
|
||||
assert gesendet[0] == (None, "lauf-1") and gesendet[1][0] == ["Venice"] and gesendet[1][1] != "lauf-1"
|
||||
|
||||
|
||||
def test_exhausted_retries_raise_llm_unavailable(monkeypatch):
|
||||
monkeypatch.setattr(llm.time, "sleep", lambda s: None)
|
||||
session, completions = fake_session()
|
||||
anbieter = iter(["Venice", "Makora", "Parasail", "Together"])
|
||||
|
||||
def create_with_completion(**kwargs):
|
||||
raise _abgeschnitten(next(anbieter))
|
||||
|
||||
completions["openrouter"].create_with_completion = create_with_completion
|
||||
with pytest.raises(llm.LLMUnavailable) as exc:
|
||||
session.create(str, [{"role": "user", "content": "x"}], step="Extraktion")
|
||||
assert exc.value.step == "Extraktion"
|
||||
assert session.usage.calls == 4 # alle vier bezahlten Antworten gezählt
|
||||
assert session.ignored_providers == ["Venice", "Makora", "Parasail"] # höchstens MAX_IGNORED_PROVIDERS
|
||||
|
||||
|
||||
def test_fatal_errors_stay_unwrapped():
|
||||
session, completions = fake_session()
|
||||
|
||||
def create_with_completion(**kwargs):
|
||||
raise RuntimeError("Error code: 402 - {'error': {'message': 'Insufficient credits'}}")
|
||||
|
||||
completions["openrouter"].create_with_completion = create_with_completion
|
||||
with pytest.raises(RuntimeError) as exc:
|
||||
session.create(str, [{"role": "user", "content": "x"}])
|
||||
assert not isinstance(exc.value, llm.LLMUnavailable)
|
||||
|
|
|
|||
Loading…
Reference in a new issue