Skip to main content
Glama

MCP Agent Tracker

by Big0290
adaptive_context_learner.py•17 kB
#!/usr/bin/env python3 """ 🧠 Adaptive Context Learning System - Phase 2 Implementation Learns from user interactions to continuously improve context selection effectiveness. """ import json import sqlite3 from typing import Dict, List, Any, Tuple, Optional from dataclasses import dataclass, asdict from datetime import datetime, timezone from enum import Enum import hashlib class LearningEventType(Enum): """Types of learning events""" CONTEXT_SELECTION = "context_selection" USER_FEEDBACK = "user_feedback" RESPONSE_QUALITY = "response_quality" THRESHOLD_ADJUSTMENT = "threshold_adjustment" @dataclass class ContextLearningEvent: """A learning event for context selection improvement""" event_id: str event_type: LearningEventType user_message: str selected_context: Dict[str, Any] excluded_context: List[str] user_satisfaction: Optional[float] = None ai_response_quality: Optional[float] = None learning_insights: Optional[Dict] = None timestamp: datetime = None session_id: Optional[str] = None def __post_init__(self): if self.timestamp is None: self.timestamp = datetime.now(timezone.utc) if self.event_id is None: self.event_id = self._generate_event_id() def _generate_event_id(self) -> str: """Generate unique event ID""" content = f"{self.event_type.value}_{self.user_message}_{self.timestamp.isoformat()}" return hashlib.md5(content.encode()).hexdigest()[:12] @dataclass class UserContextProfile: """User's context selection preferences and patterns""" user_id: str preferred_context_sections: List[str] preferred_context_depth: str # "concise", "detailed", "comprehensive" relevance_threshold: float learning_patterns: Dict[str, Any] last_updated: datetime success_rate: float total_interactions: int class ContextLearningDatabase: """Database for storing learning events and user profiles""" def __init__(self, db_path: str = "data/context_learning.db"): self.db_path = db_path self._init_database() def _init_database(self): """Initialize the learning database""" conn = sqlite3.connect(self.db_path) cursor = conn.cursor() # Learning events table cursor.execute(""" CREATE TABLE IF NOT EXISTS context_learning_events ( event_id TEXT PRIMARY KEY, event_type TEXT NOT NULL, user_message TEXT NOT NULL, selected_context TEXT NOT NULL, excluded_context TEXT NOT NULL, user_satisfaction REAL, ai_response_quality REAL, learning_insights TEXT, timestamp TEXT NOT NULL, session_id TEXT ) """) # User context profiles table cursor.execute(""" CREATE TABLE IF NOT EXISTS user_context_profiles ( user_id TEXT PRIMARY KEY, preferred_context_sections TEXT NOT NULL, preferred_context_depth TEXT NOT NULL, relevance_threshold REAL NOT NULL, learning_patterns TEXT NOT NULL, last_updated TEXT NOT NULL, success_rate REAL NOT NULL, total_interactions INTEGER NOT NULL ) """) # Learning patterns table cursor.execute(""" CREATE TABLE IF NOT EXISTS learning_patterns ( pattern_id TEXT PRIMARY KEY, pattern_type TEXT NOT NULL, pattern_data TEXT NOT NULL, success_rate REAL NOT NULL, usage_count INTEGER NOT NULL, last_used TEXT NOT NULL, created_at TEXT NOT NULL ) """) conn.commit() conn.close() def store_learning_event(self, event: ContextLearningEvent): """Store a learning event in the database""" conn = sqlite3.connect(self.db_path) cursor = conn.cursor() cursor.execute(""" INSERT OR REPLACE INTO context_learning_events VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) """, ( event.event_id, event.event_type.value, event.user_message, json.dumps(event.selected_context), json.dumps(event.excluded_context), event.user_satisfaction, event.ai_response_quality, json.dumps(event.learning_insights) if event.learning_insights else None, event.timestamp.isoformat(), event.session_id )) conn.commit() conn.close() def get_user_profile(self, user_id: str) -> Optional[UserContextProfile]: """Get user's context profile""" conn = sqlite3.connect(self.db_path) cursor = conn.cursor() cursor.execute(""" SELECT * FROM user_context_profiles WHERE user_id = ? """, (user_id,)) row = cursor.fetchone() conn.close() if row: return UserContextProfile( user_id=row[0], preferred_context_sections=json.loads(row[1]), preferred_context_depth=row[2], relevance_threshold=row[3], learning_patterns=json.loads(row[4]), last_updated=datetime.fromisoformat(row[5]), success_rate=row[6], total_interactions=row[7] ) return None def update_user_profile(self, profile: UserContextProfile): """Update user's context profile""" conn = sqlite3.connect(self.db_path) cursor = conn.cursor() cursor.execute(""" INSERT OR REPLACE INTO user_context_profiles VALUES (?, ?, ?, ?, ?, ?, ?, ?) """, ( profile.user_id, json.dumps(profile.preferred_context_sections), profile.preferred_context_depth, profile.relevance_threshold, json.dumps(profile.learning_patterns), profile.last_updated.isoformat(), profile.success_rate, profile.total_interactions )) conn.commit() conn.close() class ContextLearningAnalyzer: """Analyzes learning events to extract insights""" def __init__(self, learning_db: ContextLearningDatabase): self.learning_db = learning_db def analyze_context_effectiveness(self, user_id: str, limit: int = 100) -> Dict[str, Any]: """Analyze which context sections are most effective for a user""" conn = sqlite3.connect(self.learning_db.db_path) cursor = conn.cursor() cursor.execute(""" SELECT selected_context, user_satisfaction, ai_response_quality FROM context_learning_events WHERE session_id = ? AND user_satisfaction IS NOT NULL ORDER BY timestamp DESC LIMIT ? """, (user_id, limit)) rows = cursor.fetchall() conn.close() if not rows: return {"insights": "No learning data available", "recommendations": []} # Analyze context section effectiveness section_scores = {} total_events = len(rows) for row in rows: selected_context = json.loads(row[0]) satisfaction = row[1] or 0.5 quality = row[2] or 0.5 combined_score = (satisfaction + quality) / 2 for section_name, section_data in selected_context.items(): if section_name not in section_scores: section_scores[section_name] = {"total_score": 0, "count": 0} section_scores[section_name]["total_score"] += combined_score section_scores[section_name]["count"] += 1 # Calculate average scores and generate recommendations insights = {} recommendations = [] for section_name, scores in section_scores.items(): avg_score = scores["total_score"] / scores["count"] insights[section_name] = { "average_score": avg_score, "usage_count": scores["count"], "effectiveness": "high" if avg_score > 0.7 else "medium" if avg_score > 0.5 else "low" } if avg_score < 0.5: recommendations.append(f"Consider excluding {section_name} (low effectiveness: {avg_score:.2f})") elif avg_score > 0.8: recommendations.append(f"Prioritize {section_name} (high effectiveness: {avg_score:.2f})") return { "insights": insights, "recommendations": recommendations, "total_events_analyzed": total_events } def detect_learning_patterns(self, user_id: str) -> Dict[str, Any]: """Detect patterns in user's context preferences""" conn = sqlite3.connect(self.learning_db.db_path) cursor = conn.cursor() cursor.execute(""" SELECT user_message, selected_context, excluded_context, timestamp FROM context_learning_events WHERE session_id = ? ORDER BY timestamp DESC LIMIT 50 """, (user_id,)) rows = cursor.fetchall() conn.close() if not rows: return {"patterns": "No pattern data available"} # Analyze patterns patterns = { "message_types": {}, "context_preferences": {}, "temporal_patterns": {}, "exclusion_patterns": {} } for row in rows: message = row[0].lower() selected = json.loads(row[1]) excluded = json.loads(row[2]) timestamp = datetime.fromisoformat(row[3]) # Message type patterns if "how" in message or "implement" in message: patterns["message_types"]["how_to"] = patterns["message_types"].get("how_to", 0) + 1 elif "what" in message or "explain" in message: patterns["message_types"]["explanation"] = patterns["message_types"].get("explanation", 0) + 1 elif "debug" in message or "error" in message: patterns["message_types"]["debugging"] = patterns["message_types"].get("debugging", 0) + 1 # Context preference patterns for section in selected: patterns["context_preferences"][section] = patterns["context_preferences"].get(section, 0) + 1 # Exclusion patterns for section in excluded: patterns["exclusion_patterns"][section] = patterns["exclusion_patterns"].get(section, 0) + 1 return {"patterns": patterns, "total_events": len(rows)} class AdaptiveContextLearner: """Main class for adaptive context learning""" def __init__(self, db_path: str = "data/context_learning.db"): self.learning_db = ContextLearningDatabase(db_path) self.analyzer = ContextLearningAnalyzer(self.learning_db) def _generate_event_id(self) -> str: """Generate unique event ID""" import hashlib content = f"context_learning_{datetime.now(timezone.utc).isoformat()}" return hashlib.md5(content.encode()).hexdigest()[:12] def learn_from_interaction(self, user_message: str, selected_context: Dict, excluded_context: List[str], user_satisfaction: Optional[float] = None, ai_response_quality: Optional[float] = None, session_id: str = "default") -> str: """Learn from a user interaction to improve future context selection""" # Create learning event event = ContextLearningEvent( event_id=self._generate_event_id(), event_type=LearningEventType.CONTEXT_SELECTION, user_message=user_message, selected_context=selected_context, excluded_context=excluded_context, user_satisfaction=user_satisfaction, ai_response_quality=ai_response_quality, session_id=session_id ) # Store the learning event self.learning_db.store_learning_event(event) # Analyze for insights insights = self._extract_learning_insights(event) event.learning_insights = insights # Update the event with insights self.learning_db.store_learning_event(event) return f"Learned from interaction: {insights.get('summary', 'No insights available')}" def get_user_optimization_recommendations(self, user_id: str = "default") -> Dict[str, Any]: """Get personalized optimization recommendations for a user""" # Analyze context effectiveness effectiveness_analysis = self.analyzer.analyze_context_effectiveness(user_id) # Detect learning patterns pattern_analysis = self.analyzer.detect_learning_patterns(user_id) # Generate recommendations recommendations = { "context_optimization": effectiveness_analysis.get("recommendations", []), "pattern_insights": pattern_analysis.get("patterns", {}), "personalization_suggestions": self._generate_personalization_suggestions(effectiveness_analysis, pattern_analysis) } return recommendations def _extract_learning_insights(self, event: ContextLearningEvent) -> Dict[str, Any]: """Extract learning insights from an event""" insights = { "summary": "", "context_effectiveness": {}, "improvement_opportunities": [] } # Analyze selected context effectiveness if event.user_satisfaction is not None and event.ai_response_quality is not None: combined_score = (event.user_satisfaction + event.ai_response_quality) / 2 if combined_score < 0.5: insights["summary"] = "Low satisfaction detected - context selection needs improvement" insights["improvement_opportunities"].append("Review context relevance criteria") elif combined_score > 0.8: insights["summary"] = "High satisfaction - context selection working well" else: insights["summary"] = "Moderate satisfaction - some room for improvement" # Analyze context section usage for section_name, section_data in event.selected_context.items(): insights["context_effectiveness"][section_name] = { "included": True, "data_quality": len(str(section_data)) if section_data else 0 } for section_name in event.excluded_context: insights["context_effectiveness"][section_name] = { "included": False, "reason": "Below relevance threshold" } return insights def _generate_personalization_suggestions(self, effectiveness_analysis: Dict, pattern_analysis: Dict) -> List[str]: """Generate personalization suggestions based on analysis""" suggestions = [] # Context effectiveness suggestions if "insights" in effectiveness_analysis: for section_name, data in effectiveness_analysis["insights"].items(): if data.get("effectiveness") == "low": suggestions.append(f"Consider reducing frequency of {section_name} context") elif data.get("effectiveness") == "high": suggestions.append(f"Prioritize {section_name} context for better results") # Pattern-based suggestions if "patterns" in pattern_analysis: patterns = pattern_analysis["patterns"] if patterns.get("message_types", {}).get("how_to", 0) > 10: suggestions.append("User frequently asks how-to questions - prioritize technical context") if patterns.get("message_types", {}).get("debugging", 0) > 5: suggestions.append("User often needs debugging help - include error context and best practices") return suggestions # Example usage and testing if __name__ == "__main__": learner = AdaptiveContextLearner() # Test learning from interaction test_context = { "user_preferences": "Technical, concise responses", "tech_stack": "Python, SQLite, MCP" } excluded = ["conversation_summary", "action_history"] result = learner.learn_from_interaction( user_message="How do I implement a database connection?", selected_context=test_context, excluded_context=excluded, user_satisfaction=0.8, ai_response_quality=0.9 ) print(f"🧠 Learning Result: {result}") # Test getting recommendations recommendations = learner.get_user_optimization_recommendations("test_user") print(f"šŸ“Š Recommendations: {json.dumps(recommendations, indent=2)}")

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Big0290/MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server