/** * 主动学习引擎 - 从用户交互中学习并改进 Agent 行为 * * 提供学习事件记录、模式提取和建议生成功能。 * Phase 1: 内存存储,Zustand 持久化 * Phase 2: SQLite + 向量化存储 */ import { type LearningEvent, type LearningPattern, type LearningSuggestion, type LearningEventType, type FeedbackSentiment, } from '../types/active-learning'; // === 常量 === const MAX_EVENTS = 1000; const PATTERN_CONFIDENCE_THRESHOLD = 0.7; const SUGGESTION_COOLDOWN_HOURS = 2; // === 生成 ID === function generateEventId(): string { return `le-${Date.now()}-${Math.random().toString(36).slice(2)}`; } // === 分析反馈情感 === export function analyzeSentiment(text: string): FeedbackSentiment { const positive = ['好的', '很棒', '谢谢', '完美', 'excellent', '喜欢', '爱了', 'good', 'great', 'nice', '满意']; const negative = ['不好', '差', '糟糕', '错误', 'wrong', 'bad', '不喜欢', '讨厌', '问题', '失败', 'fail', 'error']; const lowerText = text.toLowerCase(); if (positive.some(w => lowerText.includes(w.toLowerCase()))) return 'positive'; if (negative.some(w => lowerText.includes(w.toLowerCase()))) return 'negative'; return 'neutral'; } // === 分析学习类型 === export function analyzeEventType(text: string): LearningEventType { const lowerText = text.toLowerCase(); if (lowerText.includes('纠正') || lowerText.includes('不对') || lowerText.includes('修改')) { return 'correction'; } if (lowerText.includes('喜欢') || lowerText.includes('偏好') || lowerText.includes('风格')) { return 'preference'; } if (lowerText.includes('场景') || lowerText.includes('上下文') || lowerText.includes('情况')) { return 'context'; } if (lowerText.includes('总是') || lowerText.includes('经常') || lowerText.includes('习惯')) { return 'behavior'; } return 'implicit'; } // === 推断偏好 === export function inferPreference(feedback: string, sentiment: FeedbackSentiment): string { if (sentiment === 'positive') { if (feedback.includes('简洁')) return '用户偏好简洁的回复'; if (feedback.includes('详细')) return '用户偏好详细的回复'; if (feedback.includes('快速')) return '用户偏好快速响应'; return '用户对当前回复风格满意'; } if (sentiment === 'negative') { if (feedback.includes('太长')) return '用户偏好更短的回复'; if (feedback.includes('太短')) return '用户偏好更详细的回复'; if (feedback.includes('不准确')) return '用户偏好更准确的信息'; return '用户对当前回复风格不满意'; } return '用户反馈中性'; } // === 学习引擎类 === export class ActiveLearningEngine { private events: LearningEvent[] = []; private patterns: LearningPattern[] = []; // Reserved for future learning suggestions feature private suggestions: LearningSuggestion[] = []; private initialized: boolean = false; constructor() { this.initialized = true; } /** Get current suggestions (reserved for future use) */ getSuggestions(): LearningSuggestion[] { return this.suggestions; } /** Check if engine is initialized */ isInitialized(): boolean { return this.initialized; } /** * 记录学习事件 */ recordEvent( event: Omit ): LearningEvent { // 检查重复事件 const existing = this.events.find(e => e.agentId === event.agentId && e.messageId === event.messageId && e.type === event.type ); if (existing) { // 更新现有事件 existing.observation += ' | ' + event.observation; existing.confidence = (existing.confidence + event.confidence) / 2; existing.appliedCount++; return existing; } // 创建新事件 const newEvent: LearningEvent = { ...event, id: generateEventId(), timestamp: Date.now(), acknowledged: false, appliedCount: 0, }; this.events.push(newEvent); this.extractPatterns(newEvent); // 保持事件数量限制 if (this.events.length > MAX_EVENTS) { this.events = this.events.slice(-MAX_EVENTS); } return newEvent; } /** * 从反馈中学习 */ learnFromFeedback( agentId: string, messageId: string, feedback: string, context?: string ): LearningEvent { const sentiment = analyzeSentiment(feedback); const type = analyzeEventType(feedback); return this.recordEvent({ type, agentId, messageId, trigger: context || 'User feedback', observation: feedback, context, inferredPreference: inferPreference(feedback, sentiment), confidence: sentiment === 'positive' ? 0.8 : sentiment === 'negative' ? 0.5 : 0.3, }); } /** * 提取学习模式 */ private extractPatterns(event: LearningEvent): void { // 1. 正面反馈 -> 偏好正面回复 if (event.observation.includes('谢谢') || event.observation.includes('好的')) { this.addPattern({ type: 'preference', pattern: 'positive_response_preference', description: '用户偏好正面回复风格', examples: [event.observation], confidence: 0.8, agentId: event.agentId, }); } // 2. 纠正 -> 需要更精确 if (event.type === 'correction') { this.addPattern({ type: 'rule', pattern: 'precision_preference', description: '用户对精确性有更高要求', examples: [event.observation], confidence: 0.9, agentId: event.agentId, }); } // 3. 上下文相关 -> 场景偏好 if (event.context) { this.addPattern({ type: 'context', pattern: 'context_aware', description: 'Agent 需要关注上下文', examples: [event.context], confidence: 0.6, agentId: event.agentId, }); } } /** * 添加学习模式 */ private addPattern(pattern: Omit): void { const existing = this.patterns.find(p => p.type === pattern.type && p.pattern === pattern.pattern && p.agentId === pattern.agentId ); if (existing) { // 增强置信度 existing.confidence = Math.min(1, existing.confidence + pattern.confidence * 0.1); existing.examples.push(pattern.examples[0]); existing.updatedAt = Date.now(); } else { this.patterns.push({ ...pattern, updatedAt: Date.now(), }); } } /** * 生成学习建议 */ generateSuggestions(agentId: string): LearningSuggestion[] { const suggestions: LearningSuggestion[] = []; const now = Date.now(); // 获取该 Agent 的模式 const agentPatterns = this.patterns.filter(p => p.agentId === agentId); for (const pattern of agentPatterns) { // 检查冷却时间 const hoursSinceUpdate = (now - (pattern.updatedAt || now)) / (1000 * 60 * 60); if (hoursSinceUpdate < SUGGESTION_COOLDOWN_HOURS) continue; // 检查置信度阈值 if (pattern.confidence < PATTERN_CONFIDENCE_THRESHOLD) continue; // 生成建议 suggestions.push({ id: `sug-${Date.now()}-${Math.random().toString(36).slice(2)}`, agentId, type: pattern.type, pattern: pattern.pattern, suggestion: this.generateSuggestionContent(pattern), confidence: pattern.confidence, createdAt: now, expiresAt: new Date(now + 7 * 24 * 60 * 60 * 1000), dismissed: false, }); } return suggestions; } /** * 生成建议内容 */ private generateSuggestionContent(pattern: LearningPattern): string { const templates: Record = { positive_response_preference: '用户似乎偏好正面回复。建议在回复时保持积极和确认的语气。', precision_preference: '用户对精确性有更高要求。建议在提供信息时更加详细和准确。', context_aware: 'Agent 需要关注上下文。建议在回复时考虑对话的背景和历史。', }; return templates[pattern.pattern] || `观察到模式: ${pattern.pattern}`; } /** * 获取统计信息 */ getStats(agentId: string) { const agentEvents = this.events.filter(e => e.agentId === agentId); const agentPatterns = this.patterns.filter(p => p.agentId === agentId); const eventsByType: Record = { preference: 0, correction: 0, context: 0, feedback: 0, behavior: 0, implicit: 0, }; for (const event of agentEvents) { eventsByType[event.type]++; } return { totalEvents: agentEvents.length, eventsByType, totalPatterns: agentPatterns.length, avgConfidence: agentPatterns.length > 0 ? agentPatterns.reduce((sum, p) => sum + p.confidence, 0) / agentPatterns.length : 0, }; } /** * 获取所有事件 */ getEvents(agentId?: string): LearningEvent[] { if (agentId) { return this.events.filter(e => e.agentId === agentId); } return [...this.events]; } /** * 获取所有模式 */ getPatterns(agentId?: string): LearningPattern[] { if (agentId) { return this.patterns.filter(p => p.agentId === agentId); } return [...this.patterns]; } /** * 确认事件 */ acknowledgeEvent(eventId: string): void { const event = this.events.find(e => e.id === eventId); if (event) { event.acknowledged = true; } } /** * 清除事件 */ clearEvents(agentId: string): void { this.events = this.events.filter(e => e.agentId !== agentId); this.patterns = this.patterns.filter(p => p.agentId !== agentId); } } // === 单例实例 === let engineInstance: ActiveLearningEngine | null = null; export function getActiveLearningEngine(): ActiveLearningEngine { if (!engineInstance) { engineInstance = new ActiveLearningEngine(); } return engineInstance; } export function resetActiveLearningEngine(): void { engineInstance = null; }