refactor: improve prompt construction by enforcing explicit newline boundaries between role markers and message content

This commit is contained in:
CJACK
2026-04-05 04:44:46 +08:00
parent b94a16eca9
commit 47dc121690
3 changed files with 27 additions and 17 deletions

View File

@@ -157,7 +157,7 @@ func (h *Handler) testAccount(ctx context.Context, acc config.Account, model, me
result["message"] = "获取 PoW 失败: " + err.Error()
return result
}
payload := map[string]any{"chat_session_id": sessionID, "prompt": "<User>" + message, "ref_file_ids": []any{}, "thinking_enabled": thinking, "search_enabled": search}
payload := map[string]any{"chat_session_id": sessionID, "prompt": "<User>\n" + message, "ref_file_ids": []any{}, "thinking_enabled": thinking, "search_enabled": search}
resp, err := h.DS.CallCompletion(ctx, authCtx, payload, pow, 1)
if err != nil {
result["message"] = "请求失败: " + err.Error()

View File

@@ -32,30 +32,31 @@ func MessagesPrepare(messages []map[string]any) string {
merged = append(merged, msg)
}
parts := make([]string, 0, len(merged))
for i, m := range merged {
for _, m := range merged {
switch m.Role {
case "assistant":
parts = append(parts, "<Assistant>"+m.Text+"<end▁of▁sentence>")
// Keep assistant turns on their own block so the model sees a clear
// boundary between prior answer text and the EOS marker.
parts = append(parts, "<Assistant>\n"+m.Text+"\n<end▁of▁sentence>")
case "tool":
if i > 0 {
parts = append(parts, "<Tool>"+m.Text)
} else {
parts = append(parts, m.Text)
if strings.TrimSpace(m.Text) != "" {
parts = append(parts, "<Tool>\n"+m.Text)
}
case "system":
// Clear system boundary improves R1 and V3 context understanding significantly
if strings.TrimSpace(m.Text) != "" {
parts = append(parts, "<system_instructions>\n"+strings.TrimSpace(m.Text)+"\n</system_instructions>\n\n")
// Clear system boundary improves R1 and V3 context understanding significantly.
if text := strings.TrimSpace(m.Text); text != "" {
parts = append(parts, "<system_instructions>\n"+text+"\n</system_instructions>")
}
case "user":
// Always prepend <User> to user messages. DeepSeek R1 reasoning triggers best
// and aligns context perfectly when the user turn is explicitly marked.
parts = append(parts, "<User>"+m.Text)
// Put user turns on their own line so the role transition is explicit.
parts = append(parts, "<User>\n"+m.Text)
default:
parts = append(parts, m.Text)
if strings.TrimSpace(m.Text) != "" {
parts = append(parts, m.Text)
}
}
}
out := strings.Join(parts, "")
out := strings.Join(parts, "\n\n")
return markdownImagePattern.ReplaceAllString(out, `[${1}](${2})`)
}

View File

@@ -12,7 +12,7 @@ func TestMessagesPrepareBasic(t *testing.T) {
if got == "" {
t.Fatal("expected non-empty prompt")
}
if got != "<User>Hello" {
if got != "<User>\nHello" {
t.Fatalf("unexpected prompt: %q", got)
}
}
@@ -25,6 +25,15 @@ func TestMessagesPrepareRoles(t *testing.T) {
{"role": "user", "content": "How are you"},
}
got := MessagesPrepare(messages)
if !contains(got, "<system_instructions>\nYou are helper\n</system_instructions>\n\n<User>\nHi") {
t.Fatalf("expected system/user separation in %q", got)
}
if !contains(got, "<User>\nHi\n\n<Assistant>\nHello") {
t.Fatalf("expected user/assistant separation in %q", got)
}
if !contains(got, "<Assistant>\nHello\n<end▁of▁sentence>\n\n<User>\nHow are you") {
t.Fatalf("expected assistant/user separation in %q", got)
}
if !contains(got, "<Assistant>") {
t.Fatalf("expected assistant marker in %q", got)
}
@@ -55,7 +64,7 @@ func TestMessagesPrepareArrayTextVariants(t *testing.T) {
},
}
got := MessagesPrepare(messages)
if got != "<User>line1\nline2" {
if got != "<User>\nline1\nline2" {
t.Fatalf("unexpected content from text variants: %q", got)
}
}