Discourse AI: Strukturierte Ausgabe war kein gültiges JSON

Ich habe gestern aktualisiert[1] und jetzt gibt es viele Fehler in den Logs:

Discourse AI: structured output response was not valid JSON, falling back to best-effort parsing (311 bytes) 

Ich habe die HTTP-Antwort überprüft und sie war einwandfrei. Dann habe ich den Text in der rails console ausprobiert:

...
discourse(prod)> p = JsonCompleter.new
=>
#<JsonCompleter:0x00007f48763b0270
...
discourse(prod)> p.parse text
=>
{"spam" => false,
 "reason" =>
  "..."}
discourse(prod)> p.parse DiscourseAi::Utils::BestEffortJsonParser.escape_control_characters(text)
(discourse):14:in '<main>': unexpected token "\\" (JsonCompleter::ParseError)

Es stellte sich heraus, dass Discourse Zeilenumbruchzeichen vor dem Parsen maskiert hat[2], was den Fehler verursacht hat.


  1. ↩︎

  2. code, eingeführt in pr#41716 ↩︎

Das ist eine Warnung, kein Fehler.

Dennoch setze ich das auf das INFO-Protokollierungslevel, da sich die Leute ständig wegen dieser Dinge Sorgen machen :face_exhaling:

Nun, technisch gesehen stimmt das, aber es weist auf einen Fehler im Code hin. Der Fallback funktioniert, sodass kein Fehler ausgelöst wird, aber es wäre besser, die Ursache zu beheben, anstatt sie durch das Heruntersetzen auf INFO-Ebene zu verschleiern, oder?

JSON erlaubt Zeilenumbruchzeichen als Leerzeichen, erlaubt aber keine Escape-Sequenzen außerhalb von Strings; die Escape-Funktion kodiert sie jedoch. Um das zu beheben, kannst du so ändern, dass nur ASCII-Zeichen von 0x0 bis 0x1f (einschließlich) gemäß der JSON-Spezifikation escaped werden. (Ich weiß nicht, wie man das in Ruby schreibt, also kein PR.)

Zur Veranschaulichung: Das Folgende ist gültiges JSON:

{
  "key": "value"
}

Das Folgende ist eine maskierte Variante, die ungültig ist und das Problem verursacht:

{\u000a  "key": "value"\u000a}

Welches LLM verwenden Sie?

llama-server -hf mradermacher/Qwen3-4B-Instruct-2507-GGUF:Q4_K_M

Ein 4B-Modell wird Schwierigkeiten haben, den Anforderungen gerecht zu werden. Sie werden zwar besser, aber dies gehört definitiv zur älteren Generation.

Wenn du dich für 4B entscheidest, würde ich wahrscheinlich etwas Neueres empfehlen … versuche es mit Qwen 3.5-4B oder Gemma 4 E4B.

Ich bin der Ansicht, dass llama.cpp das Schema erzwingt, indem es nur Token auswählt, die diesem entsprechen. Ich habe außerdem eine Antwort mit tcpdump aufgezeichnet und überprüft, dass die zurückgegebene Antwort gültiges JSON ist.

Sie enthielt jedoch Leerzeichen und Zeilenumbrüche außerhalb von Strings (d. h. es handelte sich um ein formatiertes JSON), und diese Zeilenumbrüche wurden von Discourse escaped, was es ungültig machte (ich habe es in der Rails-Konsole überprüft).

Übrigens nutze ich die Spam-Erkennungsfunktion.

Klar, arbeite an einer Lösung.

Der Fix ist hier: