1use crate::config::Config;
7use crate::core::*;
8use crate::database::VectorGraphDB;
9use crate::error::Result;
10use chrono::{DateTime, Duration, Utc};
11use log::{debug, info};
12use serde::{Deserialize, Serialize};
13use std::collections::{HashMap, VecDeque};
14use std::sync::Arc;
15use tokio::sync::RwLock;
16
17#[derive(Debug)]
21#[allow(dead_code)]
22pub struct LearningEngine {
23 db: Arc<VectorGraphDB>,
25 config: Config,
27 importance_learner: ImportanceLearner,
29 connection_learner: ConnectionLearner,
31 preference_learner: PreferenceLearner,
33 pattern_detector: PatternDetector,
35 feedback_processor: FeedbackProcessor,
37 stats: Arc<RwLock<LearningStats>>,
39}
40
41#[derive(Debug, Clone)]
43#[allow(dead_code)]
44pub struct ImportanceLearner {
45 learning_rate: f32,
47 decay_factor: f32,
49 reinforcement_factor: f32,
51 access_weight: f32,
53 feedback_weight: f32,
55 temporal_weight: f32,
57 connection_weight: f32,
59}
60
61#[derive(Debug, Clone)]
63#[allow(dead_code)]
64pub struct ConnectionLearner {
65 creation_threshold: f32,
67 strengthening_rate: f32,
69 weakening_rate: f32,
71 pruning_threshold: f32,
73 semantic_weight: f32,
75 temporal_weight: f32,
77 causal_weight: f32,
79}
80
81#[derive(Debug, Clone)]
83#[allow(dead_code)]
84pub struct PreferenceLearner {
85 learning_rate: f32,
87 exploration_rate: f32,
89 preference_decay: f32,
91 topic_learning_rate: f32,
93 temporal_learning_rate: f32,
95}
96
97#[derive(Debug, Clone)]
99#[allow(dead_code)]
100pub struct PatternDetector {
101 min_pattern_frequency: u32,
103 temporal_window: Duration,
105 semantic_similarity_threshold: f32,
107 pattern_cache: Arc<RwLock<HashMap<String, DetectedPattern>>>,
109}
110
111#[derive(Debug, Clone)]
113#[allow(dead_code)]
114pub struct FeedbackProcessor {
115 positive_threshold: f32,
117 negative_threshold: f32,
119 implicit_feedback_weight: f32,
121 explicit_feedback_weight: f32,
123 feedback_history: Arc<RwLock<VecDeque<FeedbackRecord>>>,
125}
126
127#[derive(Debug, Clone, Default, Serialize, Deserialize)]
129pub struct LearningStats {
130 pub total_learning_cycles: u64,
131 pub importance_adjustments: u64,
132 pub connections_created: u64,
133 pub connections_strengthened: u64,
134 pub connections_weakened: u64,
135 pub connections_pruned: u64,
136 pub patterns_detected: u64,
137 pub feedback_processed: u64,
138 pub average_learning_accuracy: f32,
139 pub last_learning_cycle: Option<DateTime<Utc>>,
140}
141
142#[derive(Debug, Clone, Serialize, Deserialize)]
144pub struct DetectedPattern {
145 pub pattern_id: String,
146 pub pattern_type: PatternType,
147 pub frequency: u32,
148 pub confidence: f32,
149 pub elements: Vec<String>,
150 pub temporal_signature: Option<TemporalSignature>,
151 pub first_detected: DateTime<Utc>,
152 pub last_seen: DateTime<Utc>,
153}
154
155#[derive(Debug, Clone, Serialize, Deserialize)]
157pub enum PatternType {
158 AccessPattern,
160 QueryPattern,
162 TopicPattern,
164 TemporalPattern,
166 ConnectionPattern,
168 FeedbackPattern,
170}
171
172#[derive(Debug, Clone, Serialize, Deserialize)]
174pub struct TemporalSignature {
175 pub preferred_hours: Vec<u8>,
176 pub preferred_days: Vec<u8>,
177 pub session_patterns: Vec<SessionPattern>,
178 pub frequency_distribution: HashMap<String, f32>,
179}
180
181#[derive(Debug, Clone, Serialize, Deserialize)]
183pub struct SessionPattern {
184 pub duration: Duration,
185 pub query_count: u32,
186 pub topic_switches: u32,
187 pub feedback_ratio: f32,
188}
189
190#[derive(Debug, Clone, Serialize, Deserialize)]
192pub struct FeedbackRecord {
193 pub memory_id: MemoryId,
194
195 pub feedback_type: FeedbackType,
196 pub score: f32,
197 pub context: FeedbackContext,
198 pub timestamp: DateTime<Utc>,
199}
200
201#[derive(Debug, Clone, Serialize, Deserialize)]
203pub enum FeedbackType {
204 Explicit,
206 Implicit,
208 Click,
210 DwellTime,
212 Share,
214 Bookmark,
216 Ignore,
218}
219
220#[derive(Debug, Clone, Serialize, Deserialize)]
222pub struct FeedbackContext {
223 pub query: String,
224 pub result_position: usize,
225 pub session_id: String,
226 pub device_type: Option<String>,
227 pub time_of_day: u8,
228 pub day_of_week: u8,
229}
230
231#[derive(Debug, Clone, Serialize, Deserialize)]
233pub enum LearningTask {
234 ImportanceAdjustment {
236 memory_ids: Vec<MemoryId>,
237 trigger: ImportanceTrigger,
238 },
239 ConnectionEvolution {
241 connection_ids: Vec<ConnectionId>,
242 evolution_type: ConnectionEvolutionType,
243 },
244 PreferenceUpdate {
246
247 update_type: PreferenceUpdateType,
248 },
249 PatternDetection {
251 data_window: (DateTime<Utc>, DateTime<Utc>),
252 pattern_types: Vec<PatternType>,
253 },
254 FeedbackProcessing { feedback_batch: Vec<FeedbackRecord> },
256}
257
258#[derive(Debug, Clone, Serialize, Deserialize)]
260pub enum ImportanceTrigger {
261 TimeDecay,
263 AccessFrequency,
265 UserFeedback,
267 ConnectionStrength,
269 QueryRelevance,
271}
272
273#[derive(Debug, Clone, Serialize, Deserialize)]
275pub enum ConnectionEvolutionType {
276 Strengthen,
278 Weaken,
280 Create,
282 Prune,
284}
285
286#[derive(Debug, Clone, Serialize, Deserialize)]
288pub enum PreferenceUpdateType {
289 TopicPreference,
291 TemporalPreference,
293 QueryPreference,
295 FeedbackPreference,
297}
298
299#[derive(Debug, Clone, Serialize, Deserialize)]
301pub struct LearningResult {
302 pub task_type: String,
303 pub success: bool,
304 pub changes_made: u32,
305 pub accuracy_improvement: Option<f32>,
306 pub execution_time: Duration,
307 pub details: HashMap<String, serde_json::Value>,
308}
309
310impl LearningEngine {
311 pub async fn new(db: Arc<VectorGraphDB>, config: Config) -> Result<Self> {
313 let importance_learner = ImportanceLearner::new(&config);
314 let connection_learner = ConnectionLearner::new(&config);
315 let preference_learner = PreferenceLearner::new(&config);
316 let pattern_detector = PatternDetector::new(&config);
317 let feedback_processor = FeedbackProcessor::new(&config);
318
319 Ok(Self {
320 db,
321 config,
322 importance_learner,
323 connection_learner,
324 preference_learner,
325 pattern_detector,
326 feedback_processor,
327 stats: Arc::new(RwLock::new(LearningStats::default())),
328 })
329 }
330
331 pub async fn execute_learning_task(&self, task: LearningTask) -> Result<LearningResult> {
333 let start_time = Utc::now();
334 let task_type_name = match &task {
335 LearningTask::ImportanceAdjustment { .. } => "ImportanceAdjustment",
336 LearningTask::ConnectionEvolution { .. } => "ConnectionEvolution",
337 LearningTask::PreferenceUpdate { .. } => "PreferenceUpdate",
338 LearningTask::PatternDetection { .. } => "PatternDetection",
339 LearningTask::FeedbackProcessing { .. } => "FeedbackProcessing",
340 };
341 info!("Executing learning task: {}", task_type_name);
342
343 let result = match task {
344 LearningTask::ImportanceAdjustment {
345 memory_ids,
346 trigger,
347 } => self.adjust_importance(memory_ids, trigger).await?,
348 LearningTask::ConnectionEvolution {
349 connection_ids,
350 evolution_type,
351 } => {
352 self.evolve_connections(connection_ids, evolution_type)
353 .await?
354 }
355 LearningTask::PreferenceUpdate { update_type } => {
356 self.update_preferences(update_type).await?
357 }
358 LearningTask::PatternDetection {
359 data_window,
360 ref pattern_types,
361 } => {
362 self.detect_patterns(data_window, pattern_types.clone())
363 .await?
364 }
365 LearningTask::FeedbackProcessing { ref feedback_batch } => {
366 self.process_feedback_batch(feedback_batch.clone()).await?
367 }
368 };
369
370 let execution_time = Utc::now() - start_time;
371
372 self.update_stats(|stats| {
374 stats.total_learning_cycles += 1;
375 stats.last_learning_cycle = Some(Utc::now());
376 })
377 .await;
378
379 info!("Learning task completed in {:?}", execution_time);
380 Ok(LearningResult {
381 task_type: task_type_name.to_string(),
382 success: result.success,
383 changes_made: result.changes_made,
384 accuracy_improvement: result.accuracy_improvement,
385 execution_time,
386 details: result.details,
387 })
388 }
389
390 async fn adjust_importance(
392 &self,
393 memory_ids: Vec<MemoryId>,
394 trigger: ImportanceTrigger,
395 ) -> Result<LearningResult> {
396 debug!("Adjusting importance for {} memories", memory_ids.len());
397
398 let mut changes_made = 0;
399 let mut details = HashMap::new();
400
401 for memory_id in memory_ids {
402 let adjustment = self
403 .importance_learner
404 .calculate_adjustment(&memory_id, &trigger, &self.db)
405 .await?;
406
407 if adjustment.abs() > 0.01 {
408 changes_made += 1;
411 details.insert(
412 memory_id.clone(),
413 serde_json::json!({
414 "adjustment": adjustment,
415 "trigger": format!("{:?}", trigger)
416 }),
417 );
418 }
419 }
420
421 self.update_stats(|stats| {
423 stats.importance_adjustments += changes_made as u64;
424 })
425 .await;
426
427 Ok(LearningResult {
428 task_type: "ImportanceAdjustment".to_string(),
429 success: true,
430 changes_made,
431 accuracy_improvement: None,
432 execution_time: Duration::zero(),
433 details,
434 })
435 }
436
437 async fn evolve_connections(
439 &self,
440 connection_ids: Vec<ConnectionId>,
441 evolution_type: ConnectionEvolutionType,
442 ) -> Result<LearningResult> {
443 debug!(
444 "Evolving {} connections with type: {:?}",
445 connection_ids.len(),
446 evolution_type
447 );
448
449 let mut changes_made = 0;
450 let mut details = HashMap::new();
451
452 match evolution_type {
453 ConnectionEvolutionType::Strengthen => {
454 for connection_id in connection_ids {
455 let strengthening = self
456 .connection_learner
457 .calculate_strengthening(&connection_id)
458 .await?;
459 if strengthening > 0.0 {
460 changes_made += 1;
462 details.insert(
463 connection_id,
464 serde_json::json!({"strengthening": strengthening}),
465 );
466 }
467 }
468
469 self.update_stats(|stats| {
470 stats.connections_strengthened += changes_made as u64;
471 })
472 .await;
473 }
474 ConnectionEvolutionType::Weaken => {
475 for connection_id in connection_ids {
476 let weakening = self
477 .connection_learner
478 .calculate_weakening(&connection_id)
479 .await?;
480 if weakening > 0.0 {
481 changes_made += 1;
483 details.insert(connection_id, serde_json::json!({"weakening": weakening}));
484 }
485 }
486
487 self.update_stats(|stats| {
488 stats.connections_weakened += changes_made as u64;
489 })
490 .await;
491 }
492 ConnectionEvolutionType::Create => {
493 let new_connections = self
494 .connection_learner
495 .discover_new_connections(&connection_ids)
496 .await?;
497 changes_made = new_connections.len() as u32;
498
499 for (i, connection) in new_connections.iter().enumerate() {
500 details.insert(
501 format!("new_connection_{}", i),
502 serde_json::json!({
503 "from": connection.from_memory,
504 "to": connection.to_memory,
505 "type": format!("{:?}", connection.connection_type),
506 "strength": connection.strength
507 }),
508 );
509 }
510
511 self.update_stats(|stats| {
512 stats.connections_created += changes_made as u64;
513 })
514 .await;
515 }
516 ConnectionEvolutionType::Prune => {
517 let pruned_connections = self
518 .connection_learner
519 .prune_weak_connections(&connection_ids)
520 .await?;
521 changes_made = pruned_connections.len() as u32;
522
523 for (i, connection_id) in pruned_connections.iter().enumerate() {
524 details.insert(
525 format!("pruned_connection_{}", i),
526 serde_json::json!({
527 "connection_id": connection_id
528 }),
529 );
530 }
531
532 self.update_stats(|stats| {
533 stats.connections_pruned += changes_made as u64;
534 })
535 .await;
536 }
537 }
538
539 Ok(LearningResult {
540 task_type: "ConnectionEvolution".to_string(),
541 success: true,
542 changes_made,
543 accuracy_improvement: None,
544 execution_time: Duration::zero(),
545 details,
546 })
547 }
548
549 async fn update_preferences(
551 &self,
552 update_type: PreferenceUpdateType,
553 ) -> Result<LearningResult> {
554 debug!("Updating preferences with type: {:?}", update_type);
555
556 let updates = self
557 .preference_learner
558 .calculate_preference_updates(&update_type)
559 .await?;
560
561 let mut details = HashMap::new();
562 details.insert(
563 "update_type".to_string(),
564 serde_json::Value::String(format!("{:?}", update_type)),
565 );
566 details.insert("updates".to_string(), serde_json::to_value(&updates)?);
567
568 Ok(LearningResult {
569 task_type: "PreferenceUpdate".to_string(),
570 success: true,
571 changes_made: updates.len() as u32,
572 accuracy_improvement: None,
573 execution_time: Duration::zero(),
574 details,
575 })
576 }
577
578 async fn detect_patterns(
580 &self,
581 data_window: (DateTime<Utc>, DateTime<Utc>),
582 pattern_types: Vec<PatternType>,
583 ) -> Result<LearningResult> {
584 debug!(
585 "Detecting patterns in window: {:?} to {:?}",
586 data_window.0, data_window.1
587 );
588
589 let mut detected_patterns = Vec::new();
590 let mut details = HashMap::new();
591
592 for pattern_type in pattern_types {
593 let patterns = self
594 .pattern_detector
595 .detect_patterns_of_type(&pattern_type, &data_window)
596 .await?;
597 detected_patterns.extend(patterns);
598 }
599
600 for pattern in &detected_patterns {
602 self.pattern_detector.store_pattern(pattern).await?;
603 }
604
605 details.insert(
606 "detected_patterns".to_string(),
607 serde_json::to_value(&detected_patterns)?,
608 );
609 details.insert(
610 "data_window".to_string(),
611 serde_json::json!({
612 "start": data_window.0,
613 "end": data_window.1
614 }),
615 );
616
617 self.update_stats(|stats| {
619 stats.patterns_detected += detected_patterns.len() as u64;
620 })
621 .await;
622
623 Ok(LearningResult {
624 task_type: "PatternDetection".to_string(),
625 success: true,
626 changes_made: detected_patterns.len() as u32,
627 accuracy_improvement: None,
628 execution_time: Duration::zero(),
629 details,
630 })
631 }
632
633 async fn process_feedback_batch(
635 &self,
636 feedback_batch: Vec<FeedbackRecord>,
637 ) -> Result<LearningResult> {
638 debug!(
639 "Processing feedback batch of {} records",
640 feedback_batch.len()
641 );
642
643 let mut processed_count = 0;
644 let mut details = HashMap::new();
645
646 for feedback in feedback_batch {
647 let processing_result = self.feedback_processor.process_feedback(&feedback).await?;
648 if processing_result.applied {
649 processed_count += 1;
650 }
651
652 details.insert(
653 format!("feedback_{}", feedback.memory_id),
654 serde_json::json!({
655 "type": format!("{:?}", feedback.feedback_type),
656 "score": feedback.score,
657 "applied": processing_result.applied,
658 "impact": processing_result.impact
659 }),
660 );
661 }
662
663 self.update_stats(|stats| {
665 stats.feedback_processed += processed_count as u64;
666 })
667 .await;
668
669 Ok(LearningResult {
670 task_type: "FeedbackProcessing".to_string(),
671 success: true,
672 changes_made: processed_count,
673 accuracy_improvement: None,
674 execution_time: Duration::zero(),
675 details,
676 })
677 }
678
679 pub async fn run_learning_cycle(&self) -> Result<Vec<LearningResult>> {
681 info!("Starting learning cycle");
682
683 let mut results = Vec::new();
684
685 let importance_task = LearningTask::ImportanceAdjustment {
687 memory_ids: self.get_all_memory_ids().await?,
688 trigger: ImportanceTrigger::TimeDecay,
689 };
690 results.push(self.execute_learning_task(importance_task).await?);
691
692 let connection_task = LearningTask::ConnectionEvolution {
694 connection_ids: self.get_all_connection_ids().await?,
695 evolution_type: ConnectionEvolutionType::Weaken,
696 };
697 results.push(self.execute_learning_task(connection_task).await?);
698
699 let now = Utc::now();
701 let pattern_task = LearningTask::PatternDetection {
702 data_window: (now - Duration::days(7), now),
703 pattern_types: vec![
704 PatternType::AccessPattern,
705 PatternType::QueryPattern,
706 PatternType::TemporalPattern,
707 ],
708 };
709 results.push(self.execute_learning_task(pattern_task).await?);
710
711 let feedback_batch = self.feedback_processor.get_pending_feedback().await?;
713 if !feedback_batch.is_empty() {
714 let feedback_task = LearningTask::FeedbackProcessing { feedback_batch };
715 results.push(self.execute_learning_task(feedback_task).await?);
716 }
717
718 info!("Learning cycle completed with {} tasks", results.len());
719 Ok(results)
720 }
721
722 pub async fn get_stats(&self) -> LearningStats {
724 self.stats.read().await.clone()
725 }
726
727 pub async fn record_feedback(&self, feedback: FeedbackRecord) -> Result<()> {
729 info!("Recording feedback for memory: {}", feedback.memory_id);
730
731 if matches!(feedback.feedback_type, FeedbackType::Explicit) {
733 self.feedback_processor.process_feedback(&feedback).await?;
734 } else {
735 self.feedback_processor.queue_feedback(feedback).await?;
737 }
738
739 Ok(())
740 }
741
742 async fn update_stats<F>(&self, updater: F)
745 where
746 F: FnOnce(&mut LearningStats),
747 {
748 let mut stats = self.stats.write().await;
749 updater(&mut stats);
750 }
751
752 async fn get_all_memory_ids(&self) -> Result<Vec<MemoryId>> {
753 Ok(Vec::new())
755 }
756
757 async fn get_all_connection_ids(&self) -> Result<Vec<ConnectionId>> {
758 Ok(Vec::new())
760 }
761}
762
763impl ImportanceLearner {
766 fn new(config: &Config) -> Self {
767 Self {
768 learning_rate: config.learning.learning_rate,
769 decay_factor: config.learning.importance_decay_factor,
770 reinforcement_factor: 1.1,
771 access_weight: 0.3,
772 feedback_weight: 0.4,
773 temporal_weight: 0.2,
774 connection_weight: 0.1,
775 }
776 }
777
778 async fn calculate_adjustment(
779 &self,
780 memory_id: &MemoryId,
781 trigger: &ImportanceTrigger,
782 _db: &VectorGraphDB,
783 ) -> Result<f32> {
784 match trigger {
785 ImportanceTrigger::TimeDecay => {
786 Ok(-self.decay_factor * self.learning_rate)
788 }
789 ImportanceTrigger::AccessFrequency => {
790 let access_count = self.get_recent_access_count(memory_id).await?;
792 Ok(access_count as f32 * self.access_weight * self.learning_rate)
793 }
794 ImportanceTrigger::UserFeedback => {
795 let feedback_score = self.get_recent_feedback_score(memory_id).await?;
797 Ok(feedback_score * self.feedback_weight * self.learning_rate)
798 }
799 ImportanceTrigger::ConnectionStrength => {
800 let connection_strength = self.get_average_connection_strength(memory_id).await?;
802 Ok(connection_strength * self.connection_weight * self.learning_rate)
803 }
804 ImportanceTrigger::QueryRelevance => {
805 let relevance_score = self.get_recent_relevance_score(memory_id).await?;
807 Ok(relevance_score * self.learning_rate)
808 }
809 }
810 }
811
812 async fn get_recent_access_count(&self, _memory_id: &MemoryId) -> Result<u32> {
813 Ok(0)
815 }
816
817 async fn get_recent_feedback_score(&self, _memory_id: &MemoryId) -> Result<f32> {
818 Ok(0.0)
820 }
821
822 async fn get_average_connection_strength(&self, _memory_id: &MemoryId) -> Result<f32> {
823 Ok(0.0)
825 }
826
827 async fn get_recent_relevance_score(&self, _memory_id: &MemoryId) -> Result<f32> {
828 Ok(0.0)
830 }
831}
832
833impl ConnectionLearner {
834 fn new(_config: &Config) -> Self {
835 Self {
836 creation_threshold: 0.7,
837 strengthening_rate: 0.1,
838 weakening_rate: 0.05,
839 pruning_threshold: 0.1,
840 semantic_weight: 0.4,
841 temporal_weight: 0.3,
842 causal_weight: 0.3,
843 }
844 }
845
846 async fn calculate_strengthening(&self, _connection_id: &ConnectionId) -> Result<f32> {
847 Ok(self.strengthening_rate)
849 }
850
851 async fn calculate_weakening(&self, _connection_id: &ConnectionId) -> Result<f32> {
852 Ok(self.weakening_rate)
854 }
855
856 async fn discover_new_connections(
857 &self,
858 _connection_ids: &[ConnectionId],
859 ) -> Result<Vec<Connection>> {
860 Ok(Vec::new())
862 }
863
864 async fn prune_weak_connections(
865 &self,
866 connection_ids: &[ConnectionId],
867 ) -> Result<Vec<ConnectionId>> {
868 let mut pruned = Vec::new();
870 for connection_id in connection_ids {
871 if connection_id.len() % 3 == 0 {
873 pruned.push(connection_id.clone());
874 }
875 }
876 Ok(pruned)
877 }
878}
879
880impl PreferenceLearner {
881 fn new(config: &Config) -> Self {
882 Self {
883 learning_rate: config.learning.learning_rate,
884 exploration_rate: 0.1,
885 preference_decay: 0.95,
886 topic_learning_rate: 0.05,
887 temporal_learning_rate: 0.03,
888 }
889 }
890
891 async fn calculate_preference_updates(
892 &self,
893 update_type: &PreferenceUpdateType,
894 ) -> Result<HashMap<String, f32>> {
895 let mut updates = HashMap::new();
896
897 match update_type {
898 PreferenceUpdateType::TopicPreference => {
899 updates.insert("AI".to_string(), 0.1);
901 updates.insert("机器学习".to_string(), 0.05);
902 }
903 PreferenceUpdateType::TemporalPreference => {
904 updates.insert("morning_preference".to_string(), 0.02);
906 }
907 PreferenceUpdateType::QueryPreference => {
908 updates.insert("semantic_queries".to_string(), 0.03);
910 }
911 PreferenceUpdateType::FeedbackPreference => {
912 updates.insert("positive_feedback_weight".to_string(), 0.01);
914 }
915 }
916
917 Ok(updates)
918 }
919}
920
921impl PatternDetector {
922 fn new(_config: &Config) -> Self {
923 Self {
924 min_pattern_frequency: 3,
925 temporal_window: Duration::days(7),
926 semantic_similarity_threshold: 0.8,
927 pattern_cache: Arc::new(RwLock::new(HashMap::new())),
928 }
929 }
930
931 async fn detect_patterns_of_type(
932 &self,
933 pattern_type: &PatternType,
934 data_window: &(DateTime<Utc>, DateTime<Utc>),
935 ) -> Result<Vec<DetectedPattern>> {
936 match pattern_type {
937 PatternType::AccessPattern => self.detect_access_patterns(data_window).await,
938 PatternType::QueryPattern => self.detect_query_patterns(data_window).await,
939 PatternType::TopicPattern => self.detect_topic_patterns(data_window).await,
940 PatternType::TemporalPattern => self.detect_temporal_patterns(data_window).await,
941 PatternType::ConnectionPattern => self.detect_connection_patterns(data_window).await,
942 PatternType::FeedbackPattern => self.detect_feedback_patterns(data_window).await,
943 }
944 }
945
946 async fn detect_access_patterns(
947 &self,
948 _data_window: &(DateTime<Utc>, DateTime<Utc>),
949 ) -> Result<Vec<DetectedPattern>> {
950 Ok(Vec::new())
952 }
953
954 async fn detect_query_patterns(
955 &self,
956 _data_window: &(DateTime<Utc>, DateTime<Utc>),
957 ) -> Result<Vec<DetectedPattern>> {
958 Ok(Vec::new())
960 }
961
962 async fn detect_topic_patterns(
963 &self,
964 _data_window: &(DateTime<Utc>, DateTime<Utc>),
965 ) -> Result<Vec<DetectedPattern>> {
966 Ok(Vec::new())
968 }
969
970 async fn detect_temporal_patterns(
971 &self,
972 _data_window: &(DateTime<Utc>, DateTime<Utc>),
973 ) -> Result<Vec<DetectedPattern>> {
974 Ok(Vec::new())
976 }
977
978 async fn detect_connection_patterns(
979 &self,
980 _data_window: &(DateTime<Utc>, DateTime<Utc>),
981 ) -> Result<Vec<DetectedPattern>> {
982 Ok(Vec::new())
984 }
985
986 async fn detect_feedback_patterns(
987 &self,
988 _data_window: &(DateTime<Utc>, DateTime<Utc>),
989 ) -> Result<Vec<DetectedPattern>> {
990 Ok(Vec::new())
992 }
993
994 async fn store_pattern(&self, pattern: &DetectedPattern) -> Result<()> {
995 let mut cache = self.pattern_cache.write().await;
996 cache.insert(pattern.pattern_id.clone(), pattern.clone());
997 Ok(())
998 }
999}
1000
1001#[derive(Debug, Clone)]
1003struct FeedbackProcessingResult {
1004 applied: bool,
1005 impact: f32,
1006}
1007
1008impl FeedbackProcessor {
1009 fn new(_config: &Config) -> Self {
1010 Self {
1011 positive_threshold: 0.6,
1012 negative_threshold: 0.4,
1013 implicit_feedback_weight: 0.3,
1014 explicit_feedback_weight: 1.0,
1015 feedback_history: Arc::new(RwLock::new(VecDeque::new())),
1016 }
1017 }
1018
1019 async fn process_feedback(
1020 &self,
1021 feedback: &FeedbackRecord,
1022 ) -> Result<FeedbackProcessingResult> {
1023 let weight = match feedback.feedback_type {
1024 FeedbackType::Explicit => self.explicit_feedback_weight,
1025 _ => self.implicit_feedback_weight,
1026 };
1027
1028 let impact = feedback.score * weight;
1029 let applied = impact.abs() > 0.1; if applied {
1032 }
1034
1035 let mut history = self.feedback_history.write().await;
1037 history.push_back(feedback.clone());
1038
1039 if history.len() > 10000 {
1041 history.drain(0..5000);
1042 }
1043
1044 Ok(FeedbackProcessingResult { applied, impact })
1045 }
1046
1047 async fn queue_feedback(&self, feedback: FeedbackRecord) -> Result<()> {
1048 let mut history = self.feedback_history.write().await;
1049 history.push_back(feedback);
1050 Ok(())
1051 }
1052
1053 async fn get_pending_feedback(&self) -> Result<Vec<FeedbackRecord>> {
1054 let history = self.feedback_history.read().await;
1055 Ok(history
1057 .iter()
1058 .filter(|f| !matches!(f.feedback_type, FeedbackType::Explicit))
1059 .take(100)
1060 .cloned()
1061 .collect())
1062 }
1063}
1064
1065#[cfg(test)]
1066mod tests {
1067 use super::*;
1068 use crate::database::VectorGraphDB;
1069 use tempfile::NamedTempFile;
1070
1071 async fn create_test_learning_engine() -> LearningEngine {
1072 let temp_file = NamedTempFile::new().unwrap();
1073 let db_url = format!("sqlite://{}", temp_file.path().display());
1074
1075 let config = Config {
1076 database: crate::config::DatabaseConfig {
1077 url: db_url,
1078 ..Default::default()
1079 },
1080 ..Default::default()
1081 };
1082
1083 let db = Arc::new(VectorGraphDB::new(config.clone()).await.unwrap());
1084 LearningEngine::new(db, config).await.unwrap()
1085 }
1086
1087 #[tokio::test]
1088 async fn test_importance_adjustment() {
1089 let engine = create_test_learning_engine().await;
1090
1091 let task = LearningTask::ImportanceAdjustment {
1092 memory_ids: vec!["memory_1".to_string(), "memory_2".to_string()],
1093 trigger: ImportanceTrigger::TimeDecay,
1094 };
1095
1096 let result = engine.execute_learning_task(task).await.unwrap();
1097 assert_eq!(result.task_type, "ImportanceAdjustment");
1098 assert!(result.success);
1099 }
1100
1101 #[tokio::test]
1102 async fn test_pattern_detection() {
1103 let engine = create_test_learning_engine().await;
1104
1105 let now = Utc::now();
1106 let task = LearningTask::PatternDetection {
1107 data_window: (now - Duration::days(1), now),
1108 pattern_types: vec![PatternType::AccessPattern, PatternType::QueryPattern],
1109 };
1110
1111 let result = engine.execute_learning_task(task).await.unwrap();
1112 assert_eq!(result.task_type, "PatternDetection");
1113 assert!(result.success);
1114 }
1115
1116 #[tokio::test]
1117 async fn test_feedback_processing() {
1118 let engine = create_test_learning_engine().await;
1119
1120 let feedback = FeedbackRecord {
1121 memory_id: "memory_1".to_string(),
1122 feedback_type: FeedbackType::Explicit,
1123 score: 0.8,
1124 context: FeedbackContext {
1125 query: "测试查询".to_string(),
1126 result_position: 0,
1127 session_id: "session_1".to_string(),
1128 device_type: Some("desktop".to_string()),
1129 time_of_day: 14,
1130 day_of_week: 1,
1131 },
1132 timestamp: Utc::now(),
1133 };
1134
1135 engine.record_feedback(feedback.clone()).await.unwrap();
1136
1137 let task = LearningTask::FeedbackProcessing {
1138 feedback_batch: vec![feedback],
1139 };
1140
1141 let result = engine.execute_learning_task(task).await.unwrap();
1142 assert_eq!(result.task_type, "FeedbackProcessing");
1143 assert!(result.success);
1144 }
1145
1146 #[tokio::test]
1147 async fn test_learning_cycle() {
1148 let engine = create_test_learning_engine().await;
1149
1150 let results = engine.run_learning_cycle().await.unwrap();
1151 assert!(!results.is_empty());
1152
1153 let stats = engine.get_stats().await;
1155 assert!(stats.total_learning_cycles > 0);
1156 }
1157}