Erreur 500 : la consigne de repli ne doit pas casser le gabarit du modèle

Après un 500 de llama-server, l'amont relance le tour sans outils en ajoutant
une consigne système À LA FIN de la conversation. Or plusieurs gabarits
exigent que le message système soit le PREMIER : gpt-oss (rôle « developer »)
lève « System message must be at the beginning ». La tentative de
récupération produisait donc elle-même un 500, et cette exception Jinja
remplaçait l'erreur d'origine sous les yeux de l'utilisateur.

steerSystem fusionne désormais la consigne dans le message système de tête,
ou la pose en première position s'il n'y en a pas — jamais ailleurs. La liste
de l'appelant n'est pas modifiée.

Tests : fusion sans ajout de message, création en tête quand il n'y a pas de
système, et non-modification de la liste d'origine.
This commit is contained in:
Loki committed 2026-08-15 14:36:04 +00:00
1 parent 8b76d8de9c
commit 73196a1ff6
2 files changed
+72 -1

No files matched your search

+21 -1
View File
@@ -241,6 +241,26 @@ func InjectSkills(msgs []Message, caps Caps) []Message {
return append([]Message{{Role: "system", Content: prefix}}, msgs...)
}
// steerSystem ajoute une consigne système SANS jamais créer un second message
// système ailleurs qu'en tête : elle est fusionnée dans celui d'ouverture, ou
// posée en première position s'il n'y en a pas.
//
// Un message système ajouté À LA FIN faisait échouer le tour sur les modèles
// dont le gabarit l'interdit : gpt-oss (rôle « developer ») lève « System
// message must be at the beginning », et ce 500 du gabarit remplaçait l'erreur
// d'origine que la nouvelle tentative cherchait justement à contourner —
// l'utilisateur voyait une exception Jinja au lieu du vrai problème.
func steerSystem(msgs []Message, hint string) []Message {
if len(msgs) > 0 && msgs[0].Role == "system" {
if existing, ok := msgs[0].Content.(string); ok {
out := append([]Message(nil), msgs...)
out[0] = Message{Role: "system", Content: existing + "\n\n" + hint}
return out
}
}
return append([]Message{{Role: "system", Content: hint}}, msgs...)
}
// EnabledTools returns the tools to advertise on the next inference call.
func EnabledTools(caps Caps) []Tool {
tools := []Tool{}
@@ -651,7 +671,7 @@ func runChat(ctx context.Context, messages []Message, temperature float64, caps
// Nudge the model to answer in plain text from what it already
// gathered, so it doesn't immediately re-emit a tool call that
// llama.cpp would again fail to parse.
messages = append(messages, Message{Role: "system", Content: "N'appelle plus d'outil. Réponds maintenant directement en français à partir des informations déjà obtenues."})
messages = steerSystem(messages, "N'appelle plus d'outil. Réponds maintenant directement en français à partir des informations déjà obtenues.")
continue
}
err := fmt.Errorf("llama-server a renvoyé %d : %s", resp.StatusCode, msg)