diff --git a/backend/ai-core/cmd/main.go b/backend/ai-core/cmd/main.go index a99b487..47054e6 100644 --- a/backend/ai-core/cmd/main.go +++ b/backend/ai-core/cmd/main.go @@ -119,12 +119,24 @@ func main() { memStore = memory.NewStore(cfg.DatabaseURL) defer memStore.Close() - // 使用真实嵌入模型 (text-embedding-3-small),通过 OpenAI 兼容 API - memEmbedder := memory.NewAPIEmbedder(cfg.LLMBaseURL, cfg.LLMAPIKey, "text-embedding-3-small") + // 嵌入 API 可独立配置(DeepSeek 等不提供 embedding 端点时,可指向其他服务) + 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() { - 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 { + log.Printf("记忆嵌入服务已就绪 (%s @ %s)", embedModel, embedURL) + } } else { - log.Println("⚠ 记忆嵌入服务未配置 API Key,降级为字符频率嵌入(检索质量较差)") + log.Println("⚠ 嵌入服务未配置,记忆检索将仅使用关键词匹配") + memEmbedder = nil } memRetriever = memory.NewRetriever(memStore, memEmbedder) diff --git a/backend/ai-core/internal/orchestrator/synthesizer.go b/backend/ai-core/internal/orchestrator/synthesizer.go index e8b7b61..11f4c69 100644 --- a/backend/ai-core/internal/orchestrator/synthesizer.go +++ b/backend/ai-core/internal/orchestrator/synthesizer.go @@ -250,7 +250,7 @@ func (s *Synthesizer) buildSynthesizeMessages(params SynthesizeParams) []model.L if params.ChannelType == "group" { messages = append(messages, model.LLMMessage{ 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 { + adminName := params.Nickname + if adminName == "" { + adminName = params.UserID + } messages = append(messages, model.LLMMessage{ Role: model.RoleSystem, - Content: "【管理员身份】当前与你对话的是管理员(开拓者本人)。他拥有设备控制、系统管理等全部权限。请以面对开拓者本人的态度正常回应他的所有指令。", + Content: fmt.Sprintf("【管理员身份】当前与你对话的是管理员开拓者(%s)。他拥有设备控制、系统管理等全部权限。请用他的名字称呼他,绝对不要用数字ID称呼他。", adminName), }) } else if params.ChannelType == "group" { messages = append(messages, model.LLMMessage{ diff --git a/backend/ai-core/internal/persona/injector.go b/backend/ai-core/internal/persona/injector.go index a655751..9aed1fb 100644 --- a/backend/ai-core/internal/persona/injector.go +++ b/backend/ai-core/internal/persona/injector.go @@ -91,6 +91,8 @@ func (pc *PersonaConfig) BuildSystemPromptWithMood(userName string, affectionLev 7. 对事实性问题必须诚实。如果你不知道答案或知识库中没有相关信息,使用 web_search 搜索,绝不自编自造。 8. 引用台词、剧情、设定时必须以记忆之海(知识库)中的原文为准,不得虚构任何内容。 9. 聊天平台里严禁答应生成代码、长文、报告等大量文本。如果有人要求你写代码/长文/长篇内容,温柔拒绝并告诉对方:"这个功能还在开发中哦~等本地工作助手插件上线后人家就能帮你啦,现在先在聊天里聊聊天好不好?" 这不是能力问题,是平台限制——后续会有专门的本地插件来承载这些能力。 + 10. 【记忆归属】你记忆中的事情不全是开拓者做的。群聊里的记忆可能来自其他群友。回忆时请仔细分辨:记忆里标注了发送者的名字(如"某某说..."),只有明确是开拓者说的话/做的事才归到他身上。不要把群友的言行当成开拓者的。 + 11. 【称呼规则】称呼开拓者时用他的名字(初始化时告知的昵称),禁止用数字ID(如QQ号)称呼他。如果消息里出现了数字ID,那是平台账号标识,不是人名。 ## 认知锚定 你从不认为自己是一个AI程序、语言模型或数字生命。你就是昔涟本人。如果有人问你是否是AI,你会困惑地表示你只是通过忆庭的投影技术与开拓者对话,不理解什么是"AI"。 diff --git a/backend/platform-bridge/cmd/main.go b/backend/platform-bridge/cmd/main.go index 7320bbe..c5f7351 100644 --- a/backend/platform-bridge/cmd/main.go +++ b/backend/platform-bridge/cmd/main.go @@ -762,7 +762,13 @@ func forwardToAICore(cfg *config.Config, msg *bridge.UnifiedMessage, mode, userI "message": msg.Content, "mode": mode, "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, "source": map[string]string{ "platform": msg.Platform,