feat: 自主思考分层 — 轻量思考(简单)+深度思考(复杂)双模型

- 新增轻量思考循环 lightThinkLoop (默认60s间隔,快速模型)
- 轻量思考用极简 prompt 做快速状态检查
- 检测到「需要深思」时自动唤醒深度思考 performThink("light_wake")
- 环境变量: LIGHT_THINK_ENABLED / LIGHT_THINK_INTERVAL_SEC
- 轻量思考跳过活跃用户 (30s内有消息) 和重复触发 (10s内)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-06-22 20:39:20 +08:00
parent 485d845f3e
commit a46b5f6238
@@ -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,每次循环根据当前时段计算间隔;