fix(llm): System-Nachrichten zu einer fuehrenden zusammenfuehren (Qwen3-Template)

Qwen3 verlangt genau eine System-Nachricht ganz am Anfang. Sobald ein Nutzer
Erinnerungen hatte, injizierte das Gateway eine zweite System-Nachricht zusaetzlich
zum Sprach-System-Prompt -> 400 "System message must be at the beginning".
Der lokale Provider fuehrt jetzt Sprach-Prompt + System-Inhalte aus der History
(z. B. Nutzer-Erinnerungen) zu einer einzigen System-Nachricht zusammen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Dieter Schlüter 2026-06-18 04:45:21 +02:00
commit d59afa4dd9
2 changed files with 49 additions and 6 deletions

View file

@ -0,0 +1,30 @@
from app.providers.llm.local_openai_compatible import LocalOpenAICompatibleLLM
def _llm(system_prompt="Sei kurz."):
return LocalOpenAICompatibleLLM("http://x/v1", "k", "m", system_prompt=system_prompt)
def test_single_system_message_when_history_has_system():
llm = _llm()
history = [
{"role": "system", "content": "Was du ueber den Nutzer weisst:\n- heisst Anna"},
{"role": "user", "content": "Hallo"},
{"role": "assistant", "content": "Hi Anna"},
]
msgs = llm._build_messages("Wie geht es dir?", history)
# Genau EINE System-Nachricht, ganz am Anfang (Qwen3-Template-Anforderung).
assert sum(1 for m in msgs if m["role"] == "system") == 1
assert msgs[0]["role"] == "system"
assert "Sei kurz." in msgs[0]["content"]
assert "heisst Anna" in msgs[0]["content"]
# Reihenfolge der Nicht-System-Nachrichten bleibt erhalten, User zuletzt.
assert [m["role"] for m in msgs] == ["system", "user", "assistant", "user"]
assert msgs[-1] == {"role": "user", "content": "Wie geht es dir?"}
def test_no_system_message_without_prompt_or_history():
llm = _llm(system_prompt="")
msgs = llm._build_messages("Hallo", None)
assert msgs == [{"role": "user", "content": "Hallo"}]