oxirs_chat/rag/
mod.rs

1//! RAG (Retrieval-Augmented Generation) System for OxiRS Chat
2//!
3//! Implements multi-stage retrieval with semantic search, graph traversal,
4//! and intelligent context assembly for knowledge graph exploration.
5//!
6//! This module is organized into specialized sub-modules for different aspects
7//! of the RAG system:
8//!
9//! - **quantum_rag**: Quantum-inspired retrieval optimization
10//! - **consciousness**: Consciousness-aware processing with memory traces
11//! - **vector_search**: Vector-based semantic search and document management
12//! - **embedding_providers**: Enhanced embedding models and multiple providers
13//! - **graph_traversal**: Knowledge graph exploration and entity expansion
14//! - **entity_extraction**: LLM-powered entity and relationship extraction
15//! - **query_processing**: Query constraint processing and analysis utilities
16//!
17//! # Examples
18//!
19//! ```rust,no_run
20//! use oxirs_chat::rag::{RagEngine, RagConfig};
21//! use oxirs_core::ConcreteStore;
22//! use std::sync::Arc;
23//!
24//! # async fn example() -> anyhow::Result<()> {
25//! let config = RagConfig::default();
26//! let store = Arc::new(ConcreteStore::new()?);
27//! let mut rag_engine = RagEngine::new(config, store as Arc<dyn oxirs_core::Store>);
28//! rag_engine.initialize().await?;
29//! # Ok(())
30//! # }
31//! ```
32
33pub mod advanced_reasoning;
34pub mod advanced_retrieval; // NEW: Advanced retrieval strategies (DPR, ColBERT, BM25+, LTR)
35pub mod consciousness;
36pub mod consciousness_types;
37pub mod context;
38pub mod embedding;
39pub mod embedding_providers;
40pub mod entity_extraction;
41pub mod graph_traversal;
42pub mod knowledge_extraction;
43pub mod quantum;
44pub mod quantum_rag;
45pub mod query_processing;
46pub mod ranking; // NEW: Result ranking system
47pub mod retrieval;
48pub mod types;
49pub mod vector_search;
50
51// Re-export main types for convenience
52pub use advanced_reasoning::{
53    AdvancedReasoningEngine, ReasoningChain, ReasoningConfig, ReasoningQuality, ReasoningResult,
54    ReasoningType, UncertaintyFactor,
55};
56pub use consciousness::{
57    AdvancedConsciousInsight, AdvancedConsciousResponse, AdvancedConsciousnessMetadata,
58    AdvancedInsightType, ConsciousInsight, ConsciousnessConfig, ConsciousnessIntegration,
59    ConsciousnessModel, EmotionalState, InsightType, MemoryTrace,
60};
61pub use consciousness_types::*;
62pub use embedding_providers::{
63    EmbeddingConfig, EmbeddingProviderType, EnhancedEmbeddingModel, SimpleEmbeddingModel,
64};
65pub use entity_extraction::{EntityExtractor, LLMEntityExtraction};
66pub use graph_traversal::{EntityType, ExtractedEntity, ExtractedRelationship, GraphTraversal};
67pub use knowledge_extraction::{
68    EntityType as KnowledgeEntityType, ExtractedEntity as KnowledgeExtractedEntity,
69    ExtractedKnowledge, ExtractedRelationship as KnowledgeExtractedRelationship,
70    KnowledgeExtractionConfig, KnowledgeExtractionEngine, RelationshipType,
71};
72pub use quantum_rag::{QuantumRetrievalState, QuantumSearchResult, RagDocument};
73pub use query_processing::{ConstraintType, QueryConstraint, QueryIntent, QueryProcessor};
74pub use vector_search::{EnhancedVectorIndex, RagIndex, SearchDocument};
75
76// Additional imports from submodules
77pub use context::*;
78pub use embedding::*;
79pub use retrieval::*;
80pub use types::*;
81
82use anyhow::{anyhow, Result};
83use chrono::{DateTime, Utc};
84use oxirs_core::{
85    model::{triple::Triple, NamedNode, Object, Subject},
86    Store,
87};
88use oxirs_embed::{
89    EmbeddingModel, ModelConfig, ModelStats, TrainingStats, Triple as EmbedTriple,
90    Vector as EmbedVector,
91};
92use oxirs_vec::VectorIndex;
93use oxirs_vec::{
94    index::{
95        AdvancedVectorIndex, DistanceMetric, IndexConfig, IndexType,
96        SearchResult as VecSearchResult,
97    },
98    similarity,
99};
100use regex::Regex;
101use serde::{Deserialize, Serialize};
102use std::{
103    collections::{HashMap, HashSet},
104    sync::Arc,
105    time::Duration,
106};
107use tracing::{debug, info, warn};
108use uuid::Uuid;
109
110/// RAG search result with metadata
111#[derive(Debug, Clone)]
112pub struct RagSearchResult {
113    pub triple: Triple,
114    pub score: f32,
115    pub search_type: SearchType,
116}
117
118/// Search type for categorizing results
119#[derive(Debug, Clone, PartialEq)]
120pub enum SearchType {
121    SemanticSimilarity,
122    GraphTraversal,
123    KeywordMatch,
124    EntityExpansion,
125}
126
127/// RAG configuration
128#[derive(Debug, Clone)]
129pub struct RagConfig {
130    pub retrieval: RetrievalConfig,
131    pub quantum: QuantumConfig,
132    pub consciousness: ConsciousnessConfig,
133    pub embedding: EmbeddingConfig,
134    pub graph: GraphConfig,
135    pub max_context_length: usize,
136    pub context_overlap: usize,
137}
138
139impl Default for RagConfig {
140    fn default() -> Self {
141        Self {
142            retrieval: RetrievalConfig::default(),
143            quantum: QuantumConfig::default(),
144            consciousness: ConsciousnessConfig::default(),
145            embedding: EmbeddingConfig::default(),
146            graph: GraphConfig::default(),
147            max_context_length: 4096,
148            context_overlap: 200,
149        }
150    }
151}
152
153/// Retrieval configuration
154#[derive(Debug, Clone)]
155pub struct RetrievalConfig {
156    pub max_results: usize,
157    pub similarity_threshold: f32,
158    pub graph_traversal_depth: usize,
159    pub enable_entity_expansion: bool,
160    pub enable_quantum_enhancement: bool,
161    pub enable_consciousness_integration: bool,
162}
163
164impl Default for RetrievalConfig {
165    fn default() -> Self {
166        Self {
167            max_results: 10,
168            similarity_threshold: 0.7,
169            graph_traversal_depth: 2,
170            enable_entity_expansion: true,
171            enable_quantum_enhancement: false,
172            enable_consciousness_integration: false,
173        }
174    }
175}
176
177/// Quantum configuration
178#[derive(Debug, Clone)]
179pub struct QuantumConfig {
180    pub enabled: bool,
181    pub superposition_threshold: f64,
182    pub entanglement_factor: f64,
183    pub coherence_time: Duration,
184}
185
186impl Default for QuantumConfig {
187    fn default() -> Self {
188        Self {
189            enabled: false,
190            superposition_threshold: 0.5,
191            entanglement_factor: 0.8,
192            coherence_time: Duration::from_secs(30),
193        }
194    }
195}
196
197/// Graph configuration
198#[derive(Debug, Clone)]
199pub struct GraphConfig {
200    pub max_traversal_depth: usize,
201    pub entity_expansion_limit: usize,
202    pub relationship_weights: HashMap<String, f32>,
203}
204
205impl Default for GraphConfig {
206    fn default() -> Self {
207        Self {
208            max_traversal_depth: 3,
209            entity_expansion_limit: 50,
210            relationship_weights: HashMap::new(),
211        }
212    }
213}
214
215/// Context assembled from various retrieval stages
216#[derive(Debug, Clone)]
217pub struct AssembledContext {
218    pub retrieved_triples: Option<Vec<Triple>>,
219    pub semantic_results: Vec<RagSearchResult>,
220    pub graph_results: Vec<RagSearchResult>,
221    pub quantum_results: Option<Vec<quantum_rag::QuantumSearchResult>>,
222    pub consciousness_insights: Option<Vec<consciousness::ConsciousInsight>>,
223    pub extracted_entities: Vec<graph_traversal::ExtractedEntity>,
224    pub extracted_relationships: Vec<graph_traversal::ExtractedRelationship>,
225    pub query_constraints: Vec<query_processing::QueryConstraint>,
226    pub reasoning_results: Option<advanced_reasoning::ReasoningResult>,
227    pub extracted_knowledge: Option<knowledge_extraction::ExtractedKnowledge>,
228    pub context_score: f32,
229    pub assembly_time: Duration,
230}
231
232impl AssembledContext {
233    pub fn new() -> Self {
234        Self {
235            retrieved_triples: None,
236            semantic_results: Vec::new(),
237            graph_results: Vec::new(),
238            quantum_results: None,
239            consciousness_insights: None,
240            extracted_entities: Vec::new(),
241            extracted_relationships: Vec::new(),
242            query_constraints: Vec::new(),
243            reasoning_results: None,
244            extracted_knowledge: None,
245            context_score: 0.0,
246            assembly_time: Duration::from_secs(0),
247        }
248    }
249}
250
251impl Default for AssembledContext {
252    fn default() -> Self {
253        Self::new()
254    }
255}
256
257/// Main RAG engine that coordinates all components
258pub struct RagEngine {
259    pub config: RagConfig,
260    pub store: Arc<dyn Store>,
261    pub vector_index: Option<RagIndex>,
262    pub embedding_model: Option<EnhancedEmbeddingModel>,
263    pub quantum_state: Option<quantum_rag::QuantumRetrievalState>,
264    pub consciousness: Option<consciousness::ConsciousnessIntegration>,
265    pub graph_traversal: graph_traversal::GraphTraversal,
266    pub entity_extractor: entity_extraction::EntityExtractor,
267    pub query_processor: query_processing::QueryProcessor,
268    pub reasoning_engine: Option<advanced_reasoning::AdvancedReasoningEngine>,
269    pub knowledge_extractor: Option<knowledge_extraction::KnowledgeExtractionEngine>,
270}
271
272impl RagEngine {
273    /// Create a new RAG engine with the given configuration
274    pub fn new(config: RagConfig, store: Arc<dyn Store>) -> Self {
275        Self {
276            config: config.clone(),
277            store: store.clone(),
278            vector_index: None,
279            embedding_model: None,
280            quantum_state: None,
281            consciousness: None,
282            graph_traversal: graph_traversal::GraphTraversal::new(store.clone()),
283            entity_extractor: entity_extraction::EntityExtractor::new(),
284            query_processor: query_processing::QueryProcessor::new(),
285            reasoning_engine: None,
286            knowledge_extractor: None,
287        }
288    }
289
290    /// Create a new RAG engine with vector index configuration
291    pub async fn with_vector_index(
292        config: RagConfig,
293        store: Arc<dyn Store>,
294        _vector_dimensions: usize,
295    ) -> Result<Self> {
296        let mut engine = Self::new(config, store);
297        engine.initialize().await?;
298        Ok(engine)
299    }
300
301    /// Initialize the RAG engine with all components
302    pub async fn initialize(&mut self) -> Result<()> {
303        // Initialize embedding model
304        self.embedding_model = Some(EnhancedEmbeddingModel::new(self.config.embedding.clone())?);
305
306        // Initialize vector index
307        self.vector_index = Some(RagIndex::new().await?);
308
309        // Initialize optional components
310        if self.config.quantum.enabled {
311            self.quantum_state = Some(quantum_rag::QuantumRetrievalState::new(0.5));
312        }
313
314        if self.config.consciousness.enabled {
315            self.consciousness = Some(consciousness::ConsciousnessIntegration::new(
316                self.config.consciousness.clone(),
317            ));
318        }
319
320        // Initialize advanced reasoning engine
321        let reasoning_config = advanced_reasoning::ReasoningConfig::default();
322        self.reasoning_engine = Some(advanced_reasoning::AdvancedReasoningEngine::new(
323            reasoning_config,
324        ));
325
326        // Initialize knowledge extraction engine
327        let extraction_config = knowledge_extraction::KnowledgeExtractionConfig::default();
328        self.knowledge_extractor = Some(knowledge_extraction::KnowledgeExtractionEngine::new(
329            extraction_config,
330        )?);
331
332        info!("RAG engine initialized successfully with Version 1.2 features");
333        Ok(())
334    }
335
336    /// Perform comprehensive retrieval for a query
337    pub async fn retrieve(&mut self, query: &str) -> Result<AssembledContext> {
338        let start_time = std::time::Instant::now();
339        let mut context = AssembledContext::new();
340
341        // Extract entities and constraints
342        let (entities, relationships) = self
343            .entity_extractor
344            .extract_entities_and_relationships(query)
345            .await?;
346        let constraints = self
347            .query_processor
348            .extract_constraints(query, &entities)
349            .await?;
350
351        context.extracted_entities = entities;
352        context.extracted_relationships = relationships;
353        context.query_constraints = constraints;
354
355        // Semantic search
356        if let Some(ref mut vector_index) = self.vector_index {
357            let semantic_docs = vector_index
358                .search(query, self.config.retrieval.max_results)
359                .await?;
360            context.semantic_results = semantic_docs
361                .into_iter()
362                .map(|doc| RagSearchResult {
363                    triple: doc.document,
364                    score: doc.score,
365                    search_type: SearchType::SemanticSimilarity,
366                })
367                .collect();
368        }
369
370        // Graph traversal
371        let graph_results = self
372            .graph_traversal
373            .perform_graph_search(
374                query,
375                &context.extracted_entities,
376                self.config.retrieval.graph_traversal_depth,
377            )
378            .await?;
379        context.graph_results = graph_results;
380
381        // Quantum enhancement (if enabled)
382        if let Some(ref quantum_state) = self.quantum_state {
383            if self.config.retrieval.enable_quantum_enhancement {
384                let quantum_docs: Vec<RagDocument> = context
385                    .semantic_results
386                    .iter()
387                    .map(|result| RagDocument {
388                        id: uuid::Uuid::new_v4().to_string(),
389                        content: result.triple.object().to_string(),
390                        triple: Some(result.triple.clone()),
391                        metadata: HashMap::new(),
392                        embedding: None,
393                    })
394                    .collect();
395
396                context.quantum_results = Some(quantum_state.superposition_search(&quantum_docs)?);
397            }
398        }
399
400        // Consciousness integration (if enabled)
401        if let Some(ref mut consciousness) = self.consciousness {
402            if self.config.retrieval.enable_consciousness_integration {
403                context.consciousness_insights = Some(
404                    consciousness
405                        .process_query_with_consciousness(query, &context)
406                        .await?,
407                );
408            }
409        }
410
411        // Advanced reasoning (if enabled)
412        if let Some(ref mut reasoning_engine) = self.reasoning_engine {
413            debug!("Applying advanced reasoning to assembled context");
414            match reasoning_engine.reason(query, &context).await {
415                Ok(reasoning_result) => {
416                    context.reasoning_results = Some(reasoning_result);
417                    debug!("Advanced reasoning completed successfully");
418                }
419                Err(e) => {
420                    warn!("Advanced reasoning failed: {}", e);
421                    // Continue without reasoning results
422                }
423            }
424        }
425
426        // Knowledge extraction (if enabled)
427        if let Some(ref mut knowledge_extractor) = self.knowledge_extractor {
428            debug!("Extracting structured knowledge from query and context");
429            // Create text for knowledge extraction from query and semantic results
430            let mut extraction_text = query.to_string();
431            for result in &context.semantic_results {
432                extraction_text.push_str(&format!(" {}", result.triple.object()));
433            }
434
435            match knowledge_extractor
436                .extract_knowledge(&extraction_text)
437                .await
438            {
439                Ok(extracted_knowledge) => {
440                    context.extracted_knowledge = Some(extracted_knowledge);
441                    debug!("Knowledge extraction completed successfully");
442                }
443                Err(e) => {
444                    warn!("Knowledge extraction failed: {}", e);
445                    // Continue without extracted knowledge
446                }
447            }
448        }
449
450        // Calculate context score
451        context.context_score = self.calculate_context_score(&context);
452        context.assembly_time = start_time.elapsed();
453
454        Ok(context)
455    }
456
457    /// Calculate overall context quality score
458    fn calculate_context_score(&self, context: &AssembledContext) -> f32 {
459        let mut score = 0.0;
460        let mut components = 0;
461
462        // Semantic results score
463        if !context.semantic_results.is_empty() {
464            let avg_semantic_score = context
465                .semantic_results
466                .iter()
467                .map(|r| r.score)
468                .sum::<f32>()
469                / context.semantic_results.len() as f32;
470            score += avg_semantic_score;
471            components += 1;
472        }
473
474        // Graph results score
475        if !context.graph_results.is_empty() {
476            let avg_graph_score = context.graph_results.iter().map(|r| r.score).sum::<f32>()
477                / context.graph_results.len() as f32;
478            score += avg_graph_score;
479            components += 1;
480        }
481
482        // Entity extraction score
483        if !context.extracted_entities.is_empty() {
484            let avg_entity_confidence = context
485                .extracted_entities
486                .iter()
487                .map(|e| e.confidence)
488                .sum::<f32>()
489                / context.extracted_entities.len() as f32;
490            score += avg_entity_confidence;
491            components += 1;
492        }
493
494        // Advanced reasoning score
495        if let Some(ref reasoning_results) = context.reasoning_results {
496            let reasoning_score = reasoning_results.reasoning_quality.overall_quality as f32;
497            score += reasoning_score;
498            components += 1;
499        }
500
501        // Knowledge extraction score
502        if let Some(ref extracted_knowledge) = context.extracted_knowledge {
503            let knowledge_score = extracted_knowledge.confidence_score as f32;
504            score += knowledge_score;
505            components += 1;
506        }
507
508        // Quantum results score (if available)
509        if let Some(ref quantum_results) = context.quantum_results {
510            if !quantum_results.is_empty() {
511                let avg_quantum_score = quantum_results
512                    .iter()
513                    .map(|r| r.quantum_probability as f32)
514                    .sum::<f32>()
515                    / quantum_results.len() as f32;
516                score += avg_quantum_score;
517                components += 1;
518            }
519        }
520
521        // Consciousness insights score (if available)
522        if let Some(ref consciousness_insights) = context.consciousness_insights {
523            if !consciousness_insights.is_empty() {
524                let avg_consciousness_score = consciousness_insights
525                    .iter()
526                    .map(|insight| insight.confidence)
527                    .sum::<f64>()
528                    / consciousness_insights.len() as f64;
529                score += avg_consciousness_score as f32;
530                components += 1;
531            }
532        }
533
534        if components > 0 {
535            score / components as f32
536        } else {
537            0.0
538        }
539    }
540
541    /// Get current configuration
542    pub fn config(&self) -> &RagConfig {
543        &self.config
544    }
545
546    /// Update configuration
547    pub fn set_config(&mut self, config: RagConfig) {
548        self.config = config;
549    }
550}
551
552// Type aliases for compatibility with lib.rs
553pub type RAGSystem = RagEngine;
554pub type RAGConfig = RagConfig;
555
556#[cfg(test)]
557mod tests {
558    use super::*;
559
560    #[test]
561    fn test_rag_config_default() {
562        let config = RagConfig::default();
563        assert_eq!(config.retrieval.max_results, 10);
564        assert_eq!(config.retrieval.similarity_threshold, 0.7);
565        assert_eq!(config.retrieval.graph_traversal_depth, 2);
566        assert!(config.retrieval.enable_entity_expansion);
567    }
568
569    #[test]
570    fn test_assembled_context_creation() {
571        let context = AssembledContext::new();
572        assert!(context.semantic_results.is_empty());
573        assert!(context.graph_results.is_empty());
574        assert!(context.extracted_entities.is_empty());
575        assert_eq!(context.context_score, 0.0);
576    }
577}