From 48fc88d4304d7e7bfbe01315c34d5d4b55642633 Mon Sep 17 00:00:00 2001 From: duffyduck Date: Sun, 25 Oct 2026 15:04:09 +0100 Subject: [PATCH] fix(openai-wrapper): Kontext-Ueberlauf als OpenAI-400 context_length_exceeded MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bisher kam context_exceeded als 502 an — OpenAI-Clients (litellm/OpenHands) hielten das fuer einen Serverfehler statt zu kuerzen/verdichten. Jetzt 400 mit code context_length_exceeded und dem OpenAI-ueblichen Text inkl. Zahlen. Doku: Abschnitt "Den Verlauf verwaltet das Programm" (Kuerzen, Verdichten, Gedaechtnis) fuer Drittprogramme. Co-Authored-By: Claude Opus 5.5 --- docs/LLM-SCHNITTSTELLE.md | 24 +++++++++++++++++++++++- xtts/openai_rvs_wrapper/wrapper.py | 9 +++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/docs/LLM-SCHNITTSTELLE.md b/docs/LLM-SCHNITTSTELLE.md index 5f1454b..09915fa 100644 --- a/docs/LLM-SCHNITTSTELLE.md +++ b/docs/LLM-SCHNITTSTELLE.md @@ -296,7 +296,10 @@ steht und welche Modelle es gibt. Im Programm eintragen: - `POST /v1/chat/completions` — auch `stream: true` (kommt derzeit in einem Rutsch) und `tools` - Fehler als HTTP-Fehler mit OpenAI-Fehlerobjekt: nicht geladenes Modell → - 404 `model_not_found`, Cluster nicht erreichbar → 503, Zeitüberschreitung → 504 + 404 `model_not_found`, Cluster nicht erreichbar → 503, Zeitüberschreitung → 504, + Verlauf zu lang → **400 `context_length_exceeded`** mit dem OpenAI-üblichen Text + („maximum context length is N tokens …") — daran erkennen OpenAI-Clients + (litellm, OpenHands …) den Überlauf und kürzen/verdichten selbst - Antwort-Header `X-Aria-Node` / `X-Aria-Gpu` sagen, wer geantwortet hat - **Läuft das Programm selbst in Docker**, ist `127.0.0.1` dort der eigene Container. Dann das Docker-Netz `aria-llm` anhängen und @@ -333,6 +336,25 @@ Boxen den Wrapper (B) nehmen. --- +## Den Verlauf verwaltet das Programm + +Die Box merkt sich **nichts** zwischen zwei Anfragen. Jede Anfrage muss alles +mitbringen, was das Modell sehen soll (Systemprompt, Werkzeuge, Verlauf). Das +Kontextfenster (`ctx`) ist die Obergrenze für **eine** Anfrage inklusive +Antwort. Wächst der Verlauf darüber hinaus, muss das Programm ihn kleiner +machen — drei übliche Wege, auch kombiniert: + +| Weg | Was passiert | Gut für | +|---|---|---| +| **Kürzen** | älteste Nachrichten weglassen (Systemprompt behalten) | einfache Chats, Werkzeug-Schleifen | +| **Verdichten** („Compacting") | alte Teile vom Modell zusammenfassen lassen, Zusammenfassung statt Original mitsenden | lange Arbeitssitzungen | +| **Gedächtnis** (RAG) | Wichtiges als Fakten in einer Datenbank ablegen, pro Anfrage nur Passendes dazuholen | dauerhaftes Wissen über Sitzungen hinweg | + +Wichtig dabei: Systemprompt **und** Werkzeug-Definitionen zählen mit, Platz +für die Antwort (`max_tokens`) einplanen, Token grob schätzen (Deutsch/Code: +eher 2,5–3 Zeichen pro Token) — und `context_exceeded` trotzdem abfangen: +kürzen, einmal neu senden. + ## Was Programme nicht senden `llm_provision_model`, `llm_unload_model` und `llm_remove_model` sind der diff --git a/xtts/openai_rvs_wrapper/wrapper.py b/xtts/openai_rvs_wrapper/wrapper.py index 5e6056f..e41f757 100644 --- a/xtts/openai_rvs_wrapper/wrapper.py +++ b/xtts/openai_rvs_wrapper/wrapper.py @@ -228,6 +228,15 @@ async def handle(reader: asyncio.StreamReader, writer: asyncio.StreamWriter) -> return await reply(writer, 503, oai_error(_unreachable(e), "cluster_unreachable", "server_error")) if not res.get("ok"): code = res.get("errorCode") or "model_error" + if code == "context_exceeded": + # Wie OpenAI: 400 + context_length_exceeded und die Zahlen im + # Text — daran erkennen OpenAI-Clients (litellm/OpenHands & Co.) + # einen Kontext-Ueberlauf und kuerzen/verdichten selbst. + n_ctx, n_req = res.get("ctx"), res.get("promptTokens") + msg = (f"This model's maximum context length is {n_ctx} tokens. However, your " + f"messages resulted in {n_req} tokens. Please reduce the length of the messages." + if n_ctx and n_req else (res.get("error") or "context length exceeded")) + return await reply(writer, 400, oai_error(msg, "context_length_exceeded")) status = {"bad_request": 400, "model_unavailable": 404, "timeout": 504}.get(code, 502) return await reply(writer, status, oai_error( res.get("error") or "Fehler", "model_not_found" if code == "model_unavailable" else code,