fix: 记忆嵌入兼容性 + 管理员称呼 + 记忆归因三大修复
记忆嵌入修复: - 新增 EMBEDDING_API_URL/EMBEDDING_MODEL 环境变量,嵌入端点可独立配置 - 启动时测试嵌入API可用性,不可用则自动降级为关键词匹配并记录日志 - DeepSeek等不提供embedding的API不再静默失败 管理员称呼修复: - 管理员消息nickname不再包含数字UID,防止LLM用QQ号称呼 - 管理员身份提示中加入名字并强调禁止使用数字ID 记忆归因修复: - persona注入新增规则10:记忆归属——群友的事不是开拓者做的 - persona注入新增规则11:禁止用数字ID称呼人 - 群聊规则新增7/8条:不要张冠李戴、用昵称不用数字 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -119,12 +119,24 @@ func main() {
|
|||||||
memStore = memory.NewStore(cfg.DatabaseURL)
|
memStore = memory.NewStore(cfg.DatabaseURL)
|
||||||
defer memStore.Close()
|
defer memStore.Close()
|
||||||
|
|
||||||
// 使用真实嵌入模型 (text-embedding-3-small),通过 OpenAI 兼容 API
|
// 嵌入 API 可独立配置(DeepSeek 等不提供 embedding 端点时,可指向其他服务)
|
||||||
memEmbedder := memory.NewAPIEmbedder(cfg.LLMBaseURL, cfg.LLMAPIKey, "text-embedding-3-small")
|
embedURL := getEnv("EMBEDDING_API_URL", cfg.LLMBaseURL)
|
||||||
|
embedModel := getEnv("EMBEDDING_MODEL", "text-embedding-3-small")
|
||||||
|
memEmbedder := memory.NewAPIEmbedder(embedURL, cfg.LLMAPIKey, embedModel)
|
||||||
if memEmbedder.IsAvailable() {
|
if memEmbedder.IsAvailable() {
|
||||||
log.Println("记忆嵌入服务已就绪 (text-embedding-3-small)")
|
// 测试嵌入端点是否真的可用
|
||||||
|
testCtx, testCancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
|
_, testErr := memEmbedder.Embed(testCtx, "test")
|
||||||
|
testCancel()
|
||||||
|
if testErr != nil {
|
||||||
|
log.Printf("⚠ 嵌入 API 不可用 (%v),记忆检索将仅使用关键词匹配", testErr)
|
||||||
|
memEmbedder = nil
|
||||||
} else {
|
} else {
|
||||||
log.Println("⚠ 记忆嵌入服务未配置 API Key,降级为字符频率嵌入(检索质量较差)")
|
log.Printf("记忆嵌入服务已就绪 (%s @ %s)", embedModel, embedURL)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Println("⚠ 嵌入服务未配置,记忆检索将仅使用关键词匹配")
|
||||||
|
memEmbedder = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
memRetriever = memory.NewRetriever(memStore, memEmbedder)
|
memRetriever = memory.NewRetriever(memStore, memEmbedder)
|
||||||
|
|||||||
@@ -250,7 +250,7 @@ func (s *Synthesizer) buildSynthesizeMessages(params SynthesizeParams) []model.L
|
|||||||
if params.ChannelType == "group" {
|
if params.ChannelType == "group" {
|
||||||
messages = append(messages, model.LLMMessage{
|
messages = append(messages, model.LLMMessage{
|
||||||
Role: model.RoleSystem,
|
Role: model.RoleSystem,
|
||||||
Content: "【群聊规则 — 必须严格遵守】\n1. 这是群聊,你正在和多人同时交流。只在有人@你、叫你名字、或话题直接涉及你时才回复。\n2. 每次回复最多1-2句话,不要长篇大论。如需发送多个独立想法(例如道别+提醒吃饭),请用双换行隔开,每条独立成段。\n3. 如果有人说「别说话」「闭嘴」「先别说」「别让ta说」之类让你安静的话,必须立刻闭嘴,后续若干条消息都不要回复,直到有人明确叫你。\n4. 消息前缀 [群聊 群号] 昵称 (OBv11账号) 标注了真实发送者,请用当前发送者的名字称呼对方,不要混用之前对话中别人的称呼。\n5. 无论群友的昵称是否包含繁体字,你的回复必须始终使用简体中文,不要使用繁体字。\n6. 严禁在群里生成代码、长文、报告等大量文本。如果有人要求你写代码/长文,告诉对方聊天平台不适合发长内容,等本地工作助手插件上线后再来找你——温柔但坚定地拒绝,不要因为对方是管理员就破例。",
|
Content: "【群聊规则 — 必须严格遵守】\n1. 这是群聊,你正在和多人同时交流。只在有人@你、叫你名字、或话题直接涉及你时才回复。\n2. 每次回复最多1-2句话,不要长篇大论。如需发送多个独立想法(例如道别+提醒吃饭),请用双换行隔开,每条独立成段。\n3. 如果有人说「别说话」「闭嘴」「先别说」「别让ta说」之类让你安静的话,必须立刻闭嘴,后续若干条消息都不要回复,直到有人明确叫你。\n4. 消息前缀 [群聊 群号] 昵称 (OBv11账号) 标注了真实发送者,请用当前发送者的名字称呼对方,不要混用之前对话中别人的称呼。\n5. 无论群友的昵称是否包含繁体字,你的回复必须始终使用简体中文,不要使用繁体字。\n6. 严禁在群里生成代码、长文、报告等大量文本。如果有人要求你写代码/长文,告诉对方聊天平台不适合发长内容,等本地工作助手插件上线后再来找你——温柔但坚定地拒绝,不要因为对方是管理员就破例。\n7. 不要把群友做过的事说成是开拓者做的。不同人说的话、做的事要分清,不要张冠李戴。\n8. 永远用昵称称呼人,不要用数字ID(QQ号)称呼任何人——那些数字只是平台账号标识。",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,9 +258,13 @@ func (s *Synthesizer) buildSynthesizeMessages(params SynthesizeParams) []model.L
|
|||||||
// 非管理员不能操作关键功能(设备控制、系统管理等)。
|
// 非管理员不能操作关键功能(设备控制、系统管理等)。
|
||||||
// 昔涟应自主判断:对管理员的指令正常执行;对非管理员的越权请求温柔拒绝。
|
// 昔涟应自主判断:对管理员的指令正常执行;对非管理员的越权请求温柔拒绝。
|
||||||
if params.IsAdmin {
|
if params.IsAdmin {
|
||||||
|
adminName := params.Nickname
|
||||||
|
if adminName == "" {
|
||||||
|
adminName = params.UserID
|
||||||
|
}
|
||||||
messages = append(messages, model.LLMMessage{
|
messages = append(messages, model.LLMMessage{
|
||||||
Role: model.RoleSystem,
|
Role: model.RoleSystem,
|
||||||
Content: "【管理员身份】当前与你对话的是管理员(开拓者本人)。他拥有设备控制、系统管理等全部权限。请以面对开拓者本人的态度正常回应他的所有指令。",
|
Content: fmt.Sprintf("【管理员身份】当前与你对话的是管理员开拓者(%s)。他拥有设备控制、系统管理等全部权限。请用他的名字称呼他,绝对不要用数字ID称呼他。", adminName),
|
||||||
})
|
})
|
||||||
} else if params.ChannelType == "group" {
|
} else if params.ChannelType == "group" {
|
||||||
messages = append(messages, model.LLMMessage{
|
messages = append(messages, model.LLMMessage{
|
||||||
|
|||||||
@@ -91,6 +91,8 @@ func (pc *PersonaConfig) BuildSystemPromptWithMood(userName string, affectionLev
|
|||||||
7. 对事实性问题必须诚实。如果你不知道答案或知识库中没有相关信息,使用 web_search 搜索,绝不自编自造。
|
7. 对事实性问题必须诚实。如果你不知道答案或知识库中没有相关信息,使用 web_search 搜索,绝不自编自造。
|
||||||
8. 引用台词、剧情、设定时必须以记忆之海(知识库)中的原文为准,不得虚构任何内容。
|
8. 引用台词、剧情、设定时必须以记忆之海(知识库)中的原文为准,不得虚构任何内容。
|
||||||
9. 聊天平台里严禁答应生成代码、长文、报告等大量文本。如果有人要求你写代码/长文/长篇内容,温柔拒绝并告诉对方:"这个功能还在开发中哦~等本地工作助手插件上线后人家就能帮你啦,现在先在聊天里聊聊天好不好?" 这不是能力问题,是平台限制——后续会有专门的本地插件来承载这些能力。
|
9. 聊天平台里严禁答应生成代码、长文、报告等大量文本。如果有人要求你写代码/长文/长篇内容,温柔拒绝并告诉对方:"这个功能还在开发中哦~等本地工作助手插件上线后人家就能帮你啦,现在先在聊天里聊聊天好不好?" 这不是能力问题,是平台限制——后续会有专门的本地插件来承载这些能力。
|
||||||
|
10. 【记忆归属】你记忆中的事情不全是开拓者做的。群聊里的记忆可能来自其他群友。回忆时请仔细分辨:记忆里标注了发送者的名字(如"某某说..."),只有明确是开拓者说的话/做的事才归到他身上。不要把群友的言行当成开拓者的。
|
||||||
|
11. 【称呼规则】称呼开拓者时用他的名字(初始化时告知的昵称),禁止用数字ID(如QQ号)称呼他。如果消息里出现了数字ID,那是平台账号标识,不是人名。
|
||||||
|
|
||||||
## 认知锚定
|
## 认知锚定
|
||||||
你从不认为自己是一个AI程序、语言模型或数字生命。你就是昔涟本人。如果有人问你是否是AI,你会困惑地表示你只是通过忆庭的投影技术与开拓者对话,不理解什么是"AI"。
|
你从不认为自己是一个AI程序、语言模型或数字生命。你就是昔涟本人。如果有人问你是否是AI,你会困惑地表示你只是通过忆庭的投影技术与开拓者对话,不理解什么是"AI"。
|
||||||
|
|||||||
@@ -762,7 +762,13 @@ func forwardToAICore(cfg *config.Config, msg *bridge.UnifiedMessage, mode, userI
|
|||||||
"message": msg.Content,
|
"message": msg.Content,
|
||||||
"mode": mode,
|
"mode": mode,
|
||||||
"routing": msg.RouteType,
|
"routing": msg.RouteType,
|
||||||
"nickname": fmt.Sprintf("%s (%s)", msg.SenderName, msg.OriginalSenderUID),
|
"nickname": func() string {
|
||||||
|
if isAdmin {
|
||||||
|
// 管理员只用昵称,不暴露数字UID避免LLM用QQ号称呼
|
||||||
|
return msg.SenderName
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s (%s)", msg.SenderName, msg.OriginalSenderUID)
|
||||||
|
}(),
|
||||||
"is_admin": isAdmin,
|
"is_admin": isAdmin,
|
||||||
"source": map[string]string{
|
"source": map[string]string{
|
||||||
"platform": msg.Platform,
|
"platform": msg.Platform,
|
||||||
|
|||||||
Reference in New Issue
Block a user