ki Backend fix - Answer Size
CI / build-and-test (push) Canceled after 0s

This commit is contained in:
2026-09-07 12:45:50 +02:00
parent 709ea88c2a
commit 835cccadec
7 changed files with 71 additions and 3 deletions
+13
View File
@@ -188,6 +188,19 @@ deaktiviert (`AllowOverride None`), oder es läuft nginx statt Apache (dort gilt
grundsätzlich nicht) — dann hilft nur eine serverseitige Konfiguration durch den Hoster/Support
(z.B. bei nginx ein `fastcgi_param HTTP_AUTHORIZATION $http_authorization;`).
## Fehlerbehebung: KI-Antwort endet mitten im JSON
Eine im Rettungsdialog am Ende abgeschnittene Modellantwort entsteht typischerweise nicht durch
die Socketverbindung, sondern durch Anthropics `stop_reason: max_tokens`. Das Backend erkennt
diesen Fall ausdrücklich und nennt das konfigurierte Limit in der Fehlermeldung. Der empfohlene
Wert für `max_output_tokens` ist **16000**; abgerechnet werden trotzdem nur tatsächlich erzeugte
Tokens.
Für echte Zeitüberschreitungen wartet der Anthropic-cURL-Aufruf höchstens 180 Sekunden und der
Desktop-Client 210 Sekunden. Bricht eine Anfrage reproduzierbar früher ab, liegt davor noch ein
Zeitlimit des Hosters (nginx/Apache/FastCGI/Reverse Proxy), das auf mindestens 180 Sekunden gesetzt
werden muss.
## Was hiermit NICHT geprüft ist
- Ob Anthropic zuverlässig valides JSON im erwarteten Schema liefert (reine Prompt-Qualitätsfrage,
+4 -1
View File
@@ -27,7 +27,10 @@ return [
],
// Sicherheitsnetz gegen ausufernde Antworten (und damit Kosten) pro Anfrage.
'max_output_tokens' => 8000,
// 8.000 waren bei ausführlichen Einheitenplanungen nachweislich zu knapp und führten zu
// mitten im JSON abgeschnittenen Antworten. Das ist eine Obergrenze, kein vorab berechneter
// Festpreis: kürzere Antworten verbrauchen und kosten weiterhin nur ihre tatsächlichen Tokens.
'max_output_tokens' => 16000,
// USD je 1 Million Token, getrennt nach Input/Output/Prompt-Cache. Vor dem produktiven Einsatz
// gegen die aktuelle Anthropic-Preisseite gegenprüfen — Preise ändern sich.
+9
View File
@@ -161,6 +161,15 @@ $result = ai_backend_call_and_charge($pdo, $config, $user, $systemPrompt, $userC
// Erst NACH der Abrechnung validieren: die Token wurden real verbraucht, das wird auch dann
// verrechnet, wenn die KI kein valides JSON geliefert hat (siehe Planungsdokument).
if (($result['stopReason'] ?? null) === 'max_tokens') {
ai_backend_fail(502,
'Die KI-Antwort wurde am Ausgabelimit von ' . $config['max_output_tokens'] .
' Tokens abgeschnitten. Bitte den Umfang der Anfrage verkleinern oder das Serverlimit erhöhen.', [
'errorCode' => 'output_limit_reached',
'rawResponse' => $result['content'],
]);
}
$parsed = ai_backend_decode_json_response($result['content']);
if (!is_array($parsed) || !isset($parsed['lessons']) || !is_array($parsed['lessons'])) {
// Die bezahlte Modellantwort nicht wegwerfen: Der Desktop-Client kann sie in einem
+8 -1
View File
@@ -37,7 +37,11 @@ class AnthropicProvider implements ProviderInterface
],
'messages' => [['role' => 'user', 'content' => $userContent]],
]),
CURLOPT_TIMEOUT => 90,
// Umfangreiche Einheitenplanungen können bei großen Antworten länger dauern. Der
// Desktop-Client wartet etwas länger (210 s), damit immer dieser Server mit einer
// verständlichen Fehlermeldung antworten kann, statt dass zuerst der Client abbricht.
CURLOPT_CONNECTTIMEOUT => 15,
CURLOPT_TIMEOUT => 180,
]);
$raw = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
@@ -68,6 +72,9 @@ class AnthropicProvider implements ProviderInterface
return [
'content' => $text,
// Insbesondere "max_tokens" darf nicht verloren gehen: Dann ist der Text zwar eine
// technisch erfolgreiche API-Antwort, das JSON aber zwangsläufig am Ende abgeschnitten.
'stopReason' => $data['stop_reason'] ?? null,
'inputTokens' => (int) ($data['usage']['input_tokens'] ?? 0),
'outputTokens' => (int) ($data['usage']['output_tokens'] ?? 0),
'cacheCreationInputTokens' => (int) ($data['usage']['cache_creation_input_tokens'] ?? 0),