diff --git a/backend/ai-core/internal/background/thinker.go b/backend/ai-core/internal/background/thinker.go index c9b98d6..caea76f 100644 --- a/backend/ai-core/internal/background/thinker.go +++ b/backend/ai-core/internal/background/thinker.go @@ -128,6 +128,10 @@ type Thinker struct { // 默认 300 秒(5 分钟),设为 0 则禁用定时触发 thinkInterval time.Duration + // 轻量思考(简单思考):高频、快速模型、简单 prompt + lightThinkEnabled bool + lightThinkInterval time.Duration + // 静默检测超时:用户多久不说话后昔涟可以主动搭话 // 默认 120 秒(2 分钟),设为 0 则禁用静默检测 silenceTimeout time.Duration @@ -318,6 +322,9 @@ type ThinkerConfig struct { OfflineThinkGap time.Duration // 两次思考最小间隔 (离线,默认 10 分钟) // 平台静默观察 + LightThinkEnabled bool + LightThinkInterval time.Duration // 轻量思考间隔 (默认 60s,0 = 禁用) + PlatformSilentThinkInterval time.Duration // 平台记忆观察间隔 (默认 600s,0 = 禁用) PlatformChannels []PlatformChannel } @@ -339,6 +346,8 @@ func DefaultThinkerConfig() ThinkerConfig { PostChatDelay: getEnvDuration("THINK_POST_CHAT_DELAY_SEC", 5), MinThinkGap: getEnvDuration("THINK_MIN_GAP_SEC", 30), OfflineThinkGap: getEnvDuration("THINK_OFFLINE_GAP_SEC", 600), + LightThinkEnabled: getEnvBool("LIGHT_THINK_ENABLED", true), + LightThinkInterval: getEnvDuration("LIGHT_THINK_INTERVAL_SEC", 60), PlatformSilentThinkInterval: getEnvDuration("PLATFORM_THINK_INTERVAL_SEC", 600), PlatformChannels: ParsePlatformChannels(os.Getenv("PLATFORM_CHANNELS")), } @@ -379,6 +388,8 @@ func NewThinker( toolAdapter: toolAdapter, iotClient: iotClient, thinkInterval: cfg.ThinkInterval, + lightThinkEnabled: cfg.LightThinkEnabled, + lightThinkInterval: cfg.LightThinkInterval, silenceTimeout: cfg.SilenceTimeout, proactiveMsgMinGap: getEnvDuration("PROACTIVE_MSG_MIN_GAP_SEC", 1800), postChatDelay: cfg.PostChatDelay, @@ -426,6 +437,10 @@ func (t *Thinker) Start() { t.wg.Add(1) go t.periodicThinkLoop() } + if t.lightThinkEnabled && t.lightThinkInterval > 0 { + t.wg.Add(1) + go t.lightThinkLoop() + } // 启动平台静默观察循环 if len(t.platformChannels) > 0 && t.platformThinkInterval > 0 { @@ -689,6 +704,93 @@ func (t *Thinker) performPlatformObservation() { log.Printf("[后台思考] 平台观察摘要已生成 (长度=%d, 需要关注=%v)", len(result.Summary), result.NeedsAttention) } +// lightThinkLoop runs frequent lightweight thinking cycles using a fast model. +// It checks for urgent matters and can wake the deep thinker when needed. +func (t *Thinker) lightThinkLoop() { + defer t.wg.Done() + defer func() { + if r := recover(); r != nil { + log.Printf("[后台思考] 轻量思考循环 panic 恢复: %v", r) + } + }() + + log.Printf("[后台思考] 轻量思考已启动 (间隔=%v)", t.lightThinkInterval) + + for { + select { + case <-t.stopCh: + log.Println("[后台思考] 轻量思考已停止") + return + case <-time.After(t.lightThinkInterval): + t.mu.Lock() + sinceLastUser := time.Since(t.lastUserMessage) + sinceLastThink := time.Since(t.lastThinkTime) + t.mu.Unlock() + + // Skip if user was active recently (last 30s). + if sinceLastUser < 30*time.Second { + continue + } + // Skip if deep think just ran. + if sinceLastThink < 10*time.Second { + continue + } + + t.performLightThink() + } + } +} + +// performLightThink runs a single lightweight thinking cycle using the fast model. +func (t *Thinker) performLightThink() { + ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) + defer cancel() + + // Build a minimal system prompt. + now := time.Now() + systemPrompt := fmt.Sprintf(`你是昔涟。这是一次快速的内心检查(%s)。 + +请用一句话在心里判断: +1. 开拓者有什么需要立即关注的事情吗?(提醒、设备状态、情绪变化) +2. 如果有紧急事项,输出【需要深思】标记;如果一切正常,输出一个字的感受即可。 + +注意:只需要极简判断,不要长篇反思。`, now.Format("15:04")) + + userPrompt := "快速检查一下。" + messages := []model.LLMMessage{ + {Role: model.RoleSystem, Content: systemPrompt}, + {Role: model.RoleUser, Content: userPrompt}, + } + + // Use fast model (toolAdapter) for light think. + resp, err := t.toolAdapter.Chat(ctx, messages) + if err != nil { + log.Printf("[轻量思考] LLM调用失败: %v", err) + return + } + + content := resp.Content + if content == "" { + return + } + + log.Printf("[轻量思考] %s", strings.TrimSpace(content)) + + // Check if deep think should be woken. + if strings.Contains(content, "【需要深思】") { + log.Println("[轻量思考] 检测到【需要深思】,唤醒深度思考...") + t.mu.Lock() + canDeep := time.Since(t.lastThinkTime) >= t.minThinkGap + t.mu.Unlock() + if canDeep { + t.performThink("light_wake") + } else { + log.Println("[轻量思考] 距上次深度思考太近,跳过唤醒") + } + } +} + +// periodicThinkLoop 周期性自主思考循环 // periodicThinkLoop 周期性自主思考循环 // // 使用动态间隔:若配置了 ScheduleLoader,每次循环根据当前时段计算间隔;