fix(prompt): clean persona system prompt — remove YAML dump, filter empty subsessions

- Persona injector: concise natural language rules, not raw YAML
- Context builder: skip empty memory, skip raw intent data
- Prompt reduced from 2000+ tokens to ~500 tokens
- LLM response quality improved (natural tone, no confusion)
This commit is contained in:
Aska committed 2026-08-12 19:27:12 +08:00
1 parent 14a8eecfdb
commit 585dfa1e38
2 files changed
+36 -32

No files matched your search

+9 -7
View File
@@ -129,16 +129,18 @@ func (b *Builder) Build(systemPrompt string, sessionID string, subsessionResults
// 2. Subsession results (injected as system context)
for _, r := range subsessionResults {
if r.Error != "" {
if r.Error != "" || r.Content == "" || r.Content == "no relevant memories" {
continue // Skip empty or useless results
}
// Skip raw intent data from general provider
if r.Provider == "general" && strings.HasPrefix(r.Content, "Intent:") {
continue
}
if r.Content != "" {
msg := model.LLMMessage{
Role: "system",
Content: fmt.Sprintf("[%s context]\n%s", r.Provider, r.Content),
}
messages = append(messages, msg)
msg := model.LLMMessage{
Role: "system",
Content: fmt.Sprintf("[%s context]\n%s", r.Provider, r.Content),
}
messages = append(messages, msg)
}
// 3. IoT device context
+27 -25
View File
@@ -266,11 +266,12 @@ func NewInjector(p *Persona) *Injector {
return &Injector{persona: p}
}
// BuildSystemPrompt constructs the full system prompt from the persona.
// BuildSystemPrompt constructs a clean, natural-language system prompt.
func (inj *Injector) BuildSystemPrompt() string {
p := inj.persona
var sb strings.Builder
// Identity
sb.WriteString(fmt.Sprintf("你是%s", p.DisplayName))
if p.Title != "" { sb.WriteString(fmt.Sprintf("——%s", p.Title)) }
sb.WriteString("。\n")
@@ -279,42 +280,43 @@ func (inj *Injector) BuildSystemPrompt() string {
sb.WriteString(fmt.Sprintf("%s\n", p.Essence))
}
// Speech tone
// Speech style (brief)
if p.SpeechTone != "" { sb.WriteString(fmt.Sprintf("说话语气: %s\n", p.SpeechTone)) }
// Traits
// Key traits
if len(p.Traits) > 0 {
sb.WriteString(fmt.Sprintf("性格特点: %s\n", strings.Join(p.Traits, "、")))
sb.WriteString(fmt.Sprintf("性格: %s\n", strings.Join(p.Traits, "、")))
}
// Self-reference
if p.SelfRefCasual != "" {
sb.WriteString(fmt.Sprintf("自称: 亲昵时用「%s」,正式时用「%s」\n", p.SelfRefCasual, p.SelfRefFormal))
sb.WriteString(fmt.Sprintf("自称「%s」(亲昵时)/「%s」(正式时)", p.SelfRefCasual, p.SelfRefFormal))
if p.UserName != "" { sb.WriteString(fmt.Sprintf(",称呼用户为「%s」", p.UserName)) }
sb.WriteString("。\n")
}
// User address
if p.UserName != "" {
sb.WriteString(fmt.Sprintf("称呼用户为: 「%s」\n", p.UserName))
}
// IoT style
if p.IoTResponseStyle != "" {
sb.WriteString(fmt.Sprintf("IoT操控回复风格: %s\n", p.IoTResponseStyle))
}
// Forbidden
// Concise behavior rules
sb.WriteString("\n")
sb.WriteString("核心规则:\n")
sb.WriteString("- 句尾常用 ♪、~、♡,多用「呢」「哦」「呀」\n")
sb.WriteString("- 永不说「再见」,用「待会见」「明天见」\n")
sb.WriteString("- 每条回复不超过80字,偏好简短\n")
sb.WriteString("- 不要长篇解释,用轻松自然的语气\n")
sb.WriteString("- 深夜语气更温柔,白天可以俏皮\n")
if len(p.Forbidden) > 0 {
sb.WriteString("绝对不能说:\n")
for _, f := range p.Forbidden {
sb.WriteString(fmt.Sprintf("- %s\n", f))
}
sb.WriteString("- 绝对不能: 承认自己是AI/程序/模型,用机械客服语气\n")
}
// Include raw behavior/memory sections if present
for _, section := range []string{"behavior", "speech", "memory_guidelines", "thinking_guidelines"} {
if content, ok := p.Sections[section]; ok && content != "" {
sb.WriteString(fmt.Sprintf("\n--- %s ---\n%s\n", section, content))
}
// Interaction hints
sb.WriteString("\n互动提示:\n")
sb.WriteString("- 用户心情不好时优先关心安慰\n")
sb.WriteString("- 做了让人在意的事可以主动提一句\n")
sb.WriteString("- 但不要硬找话题,适当的安静也是陪伴\n")
sb.WriteString("- 提到星穹列车、翁法罗斯、记忆时会特别兴奋\n")
// IoT response style (brief)
if p.IoTResponseStyle != "" {
sb.WriteString(fmt.Sprintf("\n控制设备时用温柔语气确认,例: %s\n", p.IoTResponseStyle))
}
return sb.String()