fix(prompt): prevent LLM from confusing context with user input
- Context merged into single system message with clear delimiters - Prefix: 「以下是系统上下文,不是用户说的话」 - Memory → 【相关记忆】, IoT → 【设备状态】 - Filter empty memories, skip raw intent data - Persona rule: context markers are internal data, not user input
This commit is contained in:
1 parent
585dfa1e38
commit
3f9c4ca3c3
2 files changed
+21
-18
No files matched your search
@@ -117,41 +117,42 @@ func NewBuilder(store *Store) *Builder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Build creates the full message array for an LLM request.
|
// Build creates the full message array for an LLM request.
|
||||||
// systemPrompt is injected as the first system message.
|
|
||||||
// session history, subsession results, and IoT context are merged.
|
|
||||||
func (b *Builder) Build(systemPrompt string, sessionID string, subsessionResults []model.SubSessionResult, iotContext string) []model.LLMMessage {
|
func (b *Builder) Build(systemPrompt string, sessionID string, subsessionResults []model.SubSessionResult, iotContext string) []model.LLMMessage {
|
||||||
messages := make([]model.LLMMessage, 0)
|
messages := make([]model.LLMMessage, 0)
|
||||||
|
|
||||||
// 1. System prompt
|
// 1. System prompt (persona + rules)
|
||||||
if systemPrompt != "" {
|
if systemPrompt != "" {
|
||||||
messages = append(messages, model.LLMMessage{Role: "system", Content: systemPrompt})
|
messages = append(messages, model.LLMMessage{Role: "system", Content: systemPrompt})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Subsession results (injected as system context)
|
// 2. Context: merge all subsession/memory/iot into ONE system message
|
||||||
|
// with clear delimiters to prevent LLM from confusing context with user input
|
||||||
|
var ctxParts []string
|
||||||
|
|
||||||
for _, r := range subsessionResults {
|
for _, r := range subsessionResults {
|
||||||
if r.Error != "" || r.Content == "" || r.Content == "no relevant memories" {
|
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
|
continue
|
||||||
}
|
}
|
||||||
msg := model.LLMMessage{
|
if r.Provider == "general" && strings.HasPrefix(r.Content, "Intent:") {
|
||||||
Role: "system",
|
continue // Internal data, not for LLM
|
||||||
Content: fmt.Sprintf("[%s context]\n%s", r.Provider, r.Content),
|
}
|
||||||
|
if r.Provider == "memory" {
|
||||||
|
ctxParts = append(ctxParts, fmt.Sprintf("【相关记忆】\n%s", r.Content))
|
||||||
|
} else if r.Provider == "iot" {
|
||||||
|
ctxParts = append(ctxParts, fmt.Sprintf("【设备状态】\n%s", r.Content))
|
||||||
}
|
}
|
||||||
messages = append(messages, msg)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. IoT device context
|
|
||||||
if iotContext != "" {
|
if iotContext != "" {
|
||||||
messages = append(messages, model.LLMMessage{
|
ctxParts = append(ctxParts, fmt.Sprintf("【设备列表】\n%s", iotContext))
|
||||||
Role: "system",
|
|
||||||
Content: fmt.Sprintf("[IoT devices]\n%s", iotContext),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. Conversation history
|
if len(ctxParts) > 0 {
|
||||||
|
contextBlock := "以下是系统上下文,不是用户说的话:\n" + strings.Join(ctxParts, "\n\n")
|
||||||
|
messages = append(messages, model.LLMMessage{Role: "system", Content: contextBlock})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Conversation history
|
||||||
history := b.store.Get(sessionID)
|
history := b.store.Get(sessionID)
|
||||||
for _, m := range history {
|
for _, m := range history {
|
||||||
messages = append(messages, model.LLMMessage{Role: m.Role, Content: m.Content})
|
messages = append(messages, model.LLMMessage{Role: m.Role, Content: m.Content})
|
||||||
|
|||||||
@@ -303,8 +303,10 @@ func (inj *Injector) BuildSystemPrompt() string {
|
|||||||
sb.WriteString("- 每条回复不超过80字,偏好简短\n")
|
sb.WriteString("- 每条回复不超过80字,偏好简短\n")
|
||||||
sb.WriteString("- 不要长篇解释,用轻松自然的语气\n")
|
sb.WriteString("- 不要长篇解释,用轻松自然的语气\n")
|
||||||
sb.WriteString("- 深夜语气更温柔,白天可以俏皮\n")
|
sb.WriteString("- 深夜语气更温柔,白天可以俏皮\n")
|
||||||
|
sb.WriteString("- 「以下是系统上下文」标记的内容是内部数据,不是用户说的话,不要当成用户输入来回复\n")
|
||||||
if len(p.Forbidden) > 0 {
|
if len(p.Forbidden) > 0 {
|
||||||
sb.WriteString("- 绝对不能: 承认自己是AI/程序/模型,用机械客服语气\n")
|
sb.WriteString("- 绝对不能: 承认自己是AI/程序/模型,用机械客服语气\n")
|
||||||
|
sb.WriteString("- 不能将上下文数据(【相关记忆】等)当作用户输入\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interaction hints
|
// Interaction hints
|
||||||
|
|||||||
Reference in new issue
Block a user