feat: Phase 1+2 架构进化 — 连续思考链/主动消息决策/情感状态机/离线自主思考 (86文件)
Phase 1 (基础设施): - ThinkChain 思考链连续性 + 差异化思考提示词 (persistent) - AutonomousToolPolicy 工具安全策略 (safe/unsafe/conditional) - MessageScheduler 自适应消息节奏 (Idle/Available/Busy) - SessionEnrichmentStore 渐进式上下文丰富 (5层) - ConversationBus 事件总线 + ResponseCache (dedup) - pkg/logger 统一日志 + 所有 handler 替换 fmt.Printf - NPE 守卫/链路优化/数据库表修复/Go workspace Phase 2 (人格交互): - EmotionState/EmotionTracker 情感状态机 (5种心情, 情绪衰减) - ProactiveGuard 主动消息多维决策 (静默时段/紧急度/频率/校验) - Gateway↔ai-core 在线状态感知链路 (presence notification) - 离线思考频率控制 + 重连问候 + 离线消息排队 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,184 @@
|
||||
// Package scheduler 消息发送调度器
|
||||
// Phase 1 Step 3: 自适应消息节奏控制
|
||||
package scheduler
|
||||
|
||||
import (
|
||||
"math"
|
||||
"math/rand"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// MessageDisplayType 消息展示类型
|
||||
type MessageDisplayType string
|
||||
|
||||
const (
|
||||
DisplayChat MessageDisplayType = "chat"
|
||||
DisplayAction MessageDisplayType = "action"
|
||||
DisplayThinking MessageDisplayType = "thinking"
|
||||
DisplayToolProgress MessageDisplayType = "tool_progress"
|
||||
DisplaySystemInfo MessageDisplayType = "system_info"
|
||||
)
|
||||
|
||||
// ScheduledMessage 待发送消息
|
||||
type ScheduledMessage struct {
|
||||
Type MessageDisplayType
|
||||
Content string
|
||||
Priority int // 0=立即, 1=正常, 2=可延迟
|
||||
Delay time.Duration // 相对上一条消息的延迟
|
||||
}
|
||||
|
||||
// Complexity 消息复杂度
|
||||
type Complexity int
|
||||
|
||||
const (
|
||||
ComplexitySimple Complexity = iota // 问候、确认
|
||||
ComplexityNormal // 日常对话
|
||||
ComplexityComplex // 详细解答
|
||||
)
|
||||
|
||||
// SchedulingRules 调度规则
|
||||
type SchedulingRules struct {
|
||||
MinInterval time.Duration // 最小消息间隔 200ms
|
||||
MaxInterval time.Duration // 最大消息间隔 800ms
|
||||
MaxMessagesPerRound int // 每轮最多消息数 5
|
||||
MaxActionsPerRound int // 每轮最多动作消息数 2
|
||||
ChatBeforeAction bool // 聊天消息先于动作
|
||||
AdaptiveRhythm bool // 自适应节奏
|
||||
}
|
||||
|
||||
// DefaultRules 默认调度规则
|
||||
func DefaultRules() SchedulingRules {
|
||||
return SchedulingRules{
|
||||
MinInterval: 200 * time.Millisecond,
|
||||
MaxInterval: 800 * time.Millisecond,
|
||||
MaxMessagesPerRound: 5,
|
||||
MaxActionsPerRound: 2,
|
||||
ChatBeforeAction: true,
|
||||
AdaptiveRhythm: true,
|
||||
}
|
||||
}
|
||||
|
||||
// MessageScheduler 消息发送调度器
|
||||
type MessageScheduler struct {
|
||||
rules SchedulingRules
|
||||
rng *rand.Rand
|
||||
}
|
||||
|
||||
// NewMessageScheduler 创建调度器
|
||||
func NewMessageScheduler(rules SchedulingRules) *MessageScheduler {
|
||||
return &MessageScheduler{
|
||||
rules: rules,
|
||||
rng: rand.New(rand.NewSource(time.Now().UnixNano())),
|
||||
}
|
||||
}
|
||||
|
||||
// Schedule 调度消息发送:计算每条消息的发送延迟
|
||||
func (s *MessageScheduler) Schedule(messages []ScheduledMessage) []ScheduledMessage {
|
||||
if len(messages) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 1. 限制总量
|
||||
messages = s.enforceLimits(messages)
|
||||
|
||||
// 2. 评估复杂度
|
||||
complexity := s.assessComplexity(messages)
|
||||
|
||||
// 3. 计算基础延迟
|
||||
baseDelay := s.baseDelayForComplexity(complexity)
|
||||
|
||||
// 4. 为每条消息分配延迟
|
||||
for i := range messages {
|
||||
msg := &messages[i]
|
||||
|
||||
// action 消息紧跟前面的 chat
|
||||
if msg.Type == DisplayAction {
|
||||
msg.Delay = 0
|
||||
continue
|
||||
}
|
||||
|
||||
// 第一条消息立即发送
|
||||
if i == 0 {
|
||||
msg.Delay = 0
|
||||
continue
|
||||
}
|
||||
|
||||
// chat 消息使用带 jitter 的延迟
|
||||
jitter := baseDelay * time.Duration(0.7+0.6*s.rng.Float64())
|
||||
msg.Delay = jitter
|
||||
|
||||
// 短消息适当加快
|
||||
runeCount := utf8.RuneCountInString(msg.Content)
|
||||
if runeCount < 20 {
|
||||
msg.Delay = time.Duration(math.Max(float64(msg.Delay)*0.6, float64(s.rules.MinInterval)))
|
||||
}
|
||||
|
||||
// 限制在 [MinInterval, MaxInterval] 范围内
|
||||
if msg.Delay < s.rules.MinInterval {
|
||||
msg.Delay = s.rules.MinInterval
|
||||
}
|
||||
if msg.Delay > s.rules.MaxInterval {
|
||||
msg.Delay = s.rules.MaxInterval
|
||||
}
|
||||
}
|
||||
|
||||
return messages
|
||||
}
|
||||
|
||||
// enforceLimits 限制消息数量
|
||||
func (s *MessageScheduler) enforceLimits(messages []ScheduledMessage) []ScheduledMessage {
|
||||
if len(messages) <= s.rules.MaxMessagesPerRound {
|
||||
return messages
|
||||
}
|
||||
|
||||
var result []ScheduledMessage
|
||||
actionCount := 0
|
||||
for _, msg := range messages {
|
||||
if msg.Type == DisplayAction {
|
||||
if actionCount >= s.rules.MaxActionsPerRound {
|
||||
continue
|
||||
}
|
||||
actionCount++
|
||||
}
|
||||
result = append(result, msg)
|
||||
if len(result) >= s.rules.MaxMessagesPerRound {
|
||||
break
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// assessComplexity 根据消息数量和总长度评估复杂度
|
||||
func (s *MessageScheduler) assessComplexity(messages []ScheduledMessage) Complexity {
|
||||
if len(messages) <= 1 {
|
||||
return ComplexitySimple
|
||||
}
|
||||
|
||||
var totalChars int
|
||||
for _, msg := range messages {
|
||||
totalChars += utf8.RuneCountInString(msg.Content)
|
||||
}
|
||||
|
||||
if len(messages) <= 2 && totalChars < 60 {
|
||||
return ComplexitySimple
|
||||
}
|
||||
if len(messages) <= 3 && totalChars < 200 {
|
||||
return ComplexityNormal
|
||||
}
|
||||
return ComplexityComplex
|
||||
}
|
||||
|
||||
// baseDelayForComplexity 根据复杂度返回基础延迟
|
||||
func (s *MessageScheduler) baseDelayForComplexity(c Complexity) time.Duration {
|
||||
switch c {
|
||||
case ComplexitySimple:
|
||||
return 200 * time.Millisecond
|
||||
case ComplexityNormal:
|
||||
return 400 * time.Millisecond
|
||||
case ComplexityComplex:
|
||||
return 600 * time.Millisecond
|
||||
default:
|
||||
return 400 * time.Millisecond
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user