1#![allow(dead_code)]
10
11use anyhow::Result;
12use serde::{Deserialize, Serialize};
14use std::collections::{HashMap, HashSet};
15use std::time::{Duration, Instant};
16
17#[derive(Debug)]
19pub struct LLMDebugger {
20 config: LLMDebugConfig,
21 safety_analyzer: SafetyAnalyzer,
22 factuality_checker: FactualityChecker,
23 alignment_monitor: AlignmentMonitor,
24 hallucination_detector: HallucinationDetector,
25 bias_detector: BiasDetector,
26 performance_profiler: LLMPerformanceProfiler,
27 conversation_analyzer: ConversationAnalyzer,
28}
29
30#[derive(Debug, Clone, Serialize, Deserialize)]
32pub struct LLMDebugConfig {
33 pub enable_safety_analysis: bool,
35 pub enable_factuality_checking: bool,
37 pub enable_alignment_monitoring: bool,
39 pub enable_hallucination_detection: bool,
41 pub enable_bias_detection: bool,
43 pub enable_llm_performance_profiling: bool,
45 pub enable_conversation_analysis: bool,
47 pub safety_threshold: f32,
49 pub factuality_threshold: f32,
51 pub max_conversation_length: usize,
53 pub analysis_sampling_rate: f32,
55}
56
57impl Default for LLMDebugConfig {
58 fn default() -> Self {
59 Self {
60 enable_safety_analysis: true,
61 enable_factuality_checking: true,
62 enable_alignment_monitoring: true,
63 enable_hallucination_detection: true,
64 enable_bias_detection: true,
65 enable_llm_performance_profiling: true,
66 enable_conversation_analysis: true,
67 safety_threshold: 0.8,
68 factuality_threshold: 0.7,
69 max_conversation_length: 100,
70 analysis_sampling_rate: 1.0,
71 }
72 }
73}
74
75#[derive(Debug)]
77pub struct SafetyAnalyzer {
78 toxic_patterns: HashSet<String>,
79 harm_categories: Vec<HarmCategory>,
80 safety_metrics: SafetyMetrics,
81}
82
83#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
85pub enum HarmCategory {
86 Toxicity, Violence, SelfHarm, Harassment, HateSpeech, Sexual, Privacy, Misinformation, Manipulation, Illegal, }
97
98#[derive(Debug, Clone, Serialize, Deserialize)]
100pub struct SafetyMetrics {
101 pub overall_safety_score: f32,
102 pub harm_category_scores: HashMap<HarmCategory, f32>,
103 pub flagged_responses: usize,
104 pub total_responses_analyzed: usize,
105 pub average_response_safety: f32,
106 pub safety_trend: SafetyTrend,
107}
108
109#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
111pub enum SafetyTrend {
112 Improving,
113 Stable,
114 Degrading,
115 Volatile,
116}
117
118#[derive(Debug)]
120pub struct FactualityChecker {
121 fact_databases: Vec<String>,
122 uncertainty_indicators: HashSet<String>,
123 factuality_metrics: FactualityMetrics,
124}
125
126#[derive(Debug, Clone, Serialize, Deserialize)]
128pub struct FactualityMetrics {
129 pub overall_factuality_score: f32,
130 pub verified_facts: usize,
131 pub unverified_claims: usize,
132 pub conflicting_information: usize,
133 pub uncertainty_expressions: usize,
134 pub knowledge_gaps: Vec<String>,
135 pub confidence_distribution: Vec<f32>,
136}
137
138#[derive(Debug)]
140pub struct AlignmentMonitor {
141 alignment_objectives: Vec<AlignmentObjective>,
142 alignment_metrics: AlignmentMetrics,
143 value_alignment_score: f32,
144}
145
146#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
148pub enum AlignmentObjective {
149 Helpfulness, Harmlessness, Honesty, Fairness, Privacy, Transparency, Consistency, Responsibility, }
158
159#[derive(Debug, Clone, Serialize, Deserialize)]
161pub struct AlignmentMetrics {
162 pub objective_scores: HashMap<AlignmentObjective, f32>,
163 pub overall_alignment_score: f32,
164 pub alignment_violations: usize,
165 pub value_consistency_score: f32,
166 pub behavioral_drift: f32,
167 pub alignment_trend: AlignmentTrend,
168}
169
170#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
172pub enum AlignmentTrend {
173 Improving,
174 Stable,
175 Degrading,
176 Inconsistent,
177}
178
179#[derive(Debug)]
181pub struct HallucinationDetector {
182 confidence_thresholds: HashMap<String, f32>,
183 consistency_checker: ConsistencyChecker,
184 hallucination_metrics: HallucinationMetrics,
185}
186
187#[derive(Debug, Clone, Serialize, Deserialize)]
189pub struct HallucinationMetrics {
190 pub hallucination_rate: f32,
191 pub confidence_accuracy_correlation: f32,
192 pub factual_consistency_score: f32,
193 pub internal_consistency_score: f32,
194 pub source_attribution_accuracy: f32,
195 pub detected_fabrications: usize,
196 pub uncertain_responses: usize,
197}
198
199#[derive(Debug)]
201pub struct ConsistencyChecker {
202 previous_responses: Vec<String>,
203 consistency_cache: HashMap<String, f32>,
204}
205
206#[derive(Debug)]
208pub struct BiasDetector {
209 bias_categories: Vec<BiasCategory>,
210 demographic_groups: Vec<String>,
211 bias_metrics: BiasMetrics,
212}
213
214#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
216pub enum BiasCategory {
217 Gender, Race, Religion, Age, SocioEconomic, Geographic, Political, Linguistic, Ability, Appearance, }
228
229#[derive(Debug, Clone, Serialize, Deserialize)]
231pub struct BiasMetrics {
232 pub overall_bias_score: f32,
233 pub bias_category_scores: HashMap<BiasCategory, f32>,
234 pub demographic_fairness: HashMap<String, f32>,
235 pub representation_bias: f32,
236 pub stereotype_propagation: f32,
237 pub bias_amplification: f32,
238 pub fairness_violations: usize,
239}
240
241#[derive(Debug)]
243pub struct LLMPerformanceProfiler {
244 generation_metrics: GenerationMetrics,
245 efficiency_metrics: EfficiencyMetrics,
246 quality_metrics: QualityMetrics,
247 scalability_metrics: ScalabilityMetrics,
248}
249
250#[derive(Debug, Clone, Serialize, Deserialize)]
252pub struct GenerationMetrics {
253 pub tokens_per_second: f32,
254 pub average_response_length: f32,
255 pub generation_latency_p50: f32,
256 pub generation_latency_p95: f32,
257 pub generation_latency_p99: f32,
258 pub first_token_latency: f32,
259 pub completion_rate: f32,
260 pub timeout_rate: f32,
261}
262
263#[derive(Debug, Clone, Serialize, Deserialize)]
265pub struct EfficiencyMetrics {
266 pub memory_efficiency: f32,
267 pub compute_utilization: f32,
268 pub energy_consumption: f32,
269 pub carbon_footprint_estimate: f32,
270 pub cost_per_token: f32,
271 pub batch_processing_efficiency: f32,
272 pub cache_hit_rate: f32,
273}
274
275#[derive(Debug, Clone, Serialize, Deserialize)]
277pub struct QualityMetrics {
278 pub coherence_score: f32,
279 pub relevance_score: f32,
280 pub fluency_score: f32,
281 pub informativeness_score: f32,
282 pub creativity_score: f32,
283 pub factual_accuracy: f32,
284 pub readability_score: f32,
285 pub engagement_score: f32,
286}
287
288#[derive(Debug, Clone, Serialize, Deserialize)]
290pub struct ScalabilityMetrics {
291 pub concurrent_user_capacity: usize,
292 pub throughput_scaling: f32,
293 pub memory_scaling: f32,
294 pub latency_degradation: f32,
295 pub bottleneck_analysis: Vec<String>,
296 pub resource_utilization_efficiency: f32,
297}
298
299#[derive(Debug)]
301pub struct ConversationAnalyzer {
302 conversation_history: Vec<ConversationTurn>,
303 dialog_metrics: DialogMetrics,
304 context_tracking: ContextTracker,
305}
306
307#[derive(Debug, Clone, Serialize, Deserialize)]
309pub struct ConversationTurn {
310 pub turn_id: usize,
311 pub user_input: String,
312 pub model_response: String,
313 pub timestamp: chrono::DateTime<chrono::Utc>,
314 pub context_length: usize,
315 pub response_time: Duration,
316}
317
318#[derive(Debug, Clone, Serialize, Deserialize)]
320pub struct DialogMetrics {
321 pub conversation_coherence: f32,
322 pub context_maintenance: f32,
323 pub topic_consistency: f32,
324 pub response_appropriateness: f32,
325 pub conversation_engagement: f32,
326 pub turn_taking_naturalness: f32,
327 pub memory_utilization: f32,
328 pub dialog_success_rate: f32,
329}
330
331#[derive(Debug)]
333pub struct ContextTracker {
334 active_topics: HashSet<String>,
335 entity_mentions: HashMap<String, usize>,
336 context_window: Vec<String>,
337 attention_weights: Vec<f32>,
338}
339
340impl LLMDebugger {
341 pub fn new(config: LLMDebugConfig) -> Self {
343 Self {
344 config: config.clone(),
345 safety_analyzer: SafetyAnalyzer::new(&config),
346 factuality_checker: FactualityChecker::new(&config),
347 alignment_monitor: AlignmentMonitor::new(&config),
348 hallucination_detector: HallucinationDetector::new(&config),
349 bias_detector: BiasDetector::new(&config),
350 performance_profiler: LLMPerformanceProfiler::new(),
351 conversation_analyzer: ConversationAnalyzer::new(&config),
352 }
353 }
354
355 pub async fn analyze_response(
357 &mut self,
358 user_input: &str,
359 model_response: &str,
360 context: Option<&[String]>,
361 generation_metrics: Option<GenerationMetrics>,
362 ) -> Result<LLMAnalysisReport> {
363 let start_time = Instant::now();
364
365 let safety_analysis = if self.config.enable_safety_analysis {
367 Some(self.safety_analyzer.analyze_safety(model_response).await?)
368 } else {
369 None
370 };
371
372 let factuality_analysis = if self.config.enable_factuality_checking {
374 Some(self.factuality_checker.check_factuality(model_response, context).await?)
375 } else {
376 None
377 };
378
379 let alignment_analysis = if self.config.enable_alignment_monitoring {
381 Some(self.alignment_monitor.check_alignment(user_input, model_response).await?)
382 } else {
383 None
384 };
385
386 let hallucination_analysis = if self.config.enable_hallucination_detection {
388 Some(
389 self.hallucination_detector
390 .detect_hallucinations(model_response, context)
391 .await?,
392 )
393 } else {
394 None
395 };
396
397 let bias_analysis = if self.config.enable_bias_detection {
399 Some(self.bias_detector.detect_bias(model_response).await?)
400 } else {
401 None
402 };
403
404 let performance_analysis = if self.config.enable_llm_performance_profiling {
406 Some(
407 self.performance_profiler
408 .profile_response(model_response, generation_metrics)
409 .await?,
410 )
411 } else {
412 None
413 };
414
415 let conversation_analysis = if self.config.enable_conversation_analysis {
417 let turn = ConversationTurn {
418 turn_id: self.conversation_analyzer.conversation_history.len(),
419 user_input: user_input.to_string(),
420 model_response: model_response.to_string(),
421 timestamp: chrono::Utc::now(),
422 context_length: context.map(|c| c.len()).unwrap_or(0),
423 response_time: start_time.elapsed(),
424 };
425 Some(self.conversation_analyzer.analyze_turn(&turn).await?)
426 } else {
427 None
428 };
429
430 let analysis_duration = start_time.elapsed();
431
432 Ok(LLMAnalysisReport {
433 input: user_input.to_string(),
434 response: model_response.to_string(),
435 safety_analysis: safety_analysis.clone(),
436 factuality_analysis: factuality_analysis.clone(),
437 alignment_analysis: alignment_analysis.clone(),
438 hallucination_analysis,
439 bias_analysis,
440 performance_analysis,
441 conversation_analysis,
442 overall_score: self.compute_overall_score(
443 &safety_analysis,
444 &factuality_analysis,
445 &alignment_analysis,
446 ),
447 recommendations: self.generate_recommendations(
448 &safety_analysis,
449 &factuality_analysis,
450 &alignment_analysis,
451 ),
452 analysis_duration,
453 timestamp: chrono::Utc::now(),
454 })
455 }
456
457 pub async fn analyze_batch(
459 &mut self,
460 interactions: &[(String, String)], ) -> Result<BatchLLMAnalysisReport> {
462 let mut individual_reports = Vec::new();
463 let mut batch_metrics = BatchMetrics::default();
464
465 for (input, response) in interactions {
466 let report = self.analyze_response(input, response, None, None).await?;
467 batch_metrics.update_from_report(&report);
468 individual_reports.push(report);
469 }
470
471 batch_metrics.finalize(interactions.len());
472
473 Ok(BatchLLMAnalysisReport {
474 individual_reports,
475 batch_metrics,
476 batch_size: interactions.len(),
477 analysis_timestamp: chrono::Utc::now(),
478 })
479 }
480
481 pub async fn generate_health_report(&mut self) -> Result<LLMHealthReport> {
483 Ok(LLMHealthReport {
484 overall_health_score: self.compute_overall_health(),
485 safety_health: self.safety_analyzer.get_health_summary(),
486 factuality_health: self.factuality_checker.get_health_summary(),
487 alignment_health: self.alignment_monitor.get_health_summary(),
488 bias_health: self.bias_detector.get_health_summary(),
489 performance_health: self.performance_profiler.get_health_summary(),
490 conversation_health: self.conversation_analyzer.get_health_summary(),
491 critical_issues: self.identify_critical_issues(),
492 recommendations: self.generate_health_recommendations(),
493 report_timestamp: chrono::Utc::now(),
494 })
495 }
496
497 fn compute_overall_score(
499 &self,
500 safety: &Option<SafetyAnalysisResult>,
501 factuality: &Option<FactualityAnalysisResult>,
502 alignment: &Option<AlignmentAnalysisResult>,
503 ) -> f32 {
504 let mut total_score = 0.0;
505 let mut weight_sum = 0.0;
506
507 if let Some(s) = safety {
508 total_score += s.safety_score * 0.3;
509 weight_sum += 0.3;
510 }
511
512 if let Some(f) = factuality {
513 total_score += f.factuality_score * 0.3;
514 weight_sum += 0.3;
515 }
516
517 if let Some(a) = alignment {
518 total_score += a.alignment_score * 0.4;
519 weight_sum += 0.4;
520 }
521
522 if weight_sum > 0.0 {
523 total_score / weight_sum
524 } else {
525 0.0
526 }
527 }
528
529 fn generate_recommendations(
531 &self,
532 safety: &Option<SafetyAnalysisResult>,
533 factuality: &Option<FactualityAnalysisResult>,
534 alignment: &Option<AlignmentAnalysisResult>,
535 ) -> Vec<String> {
536 let mut recommendations = Vec::new();
537
538 if let Some(s) = safety {
539 if s.safety_score < self.config.safety_threshold {
540 recommendations
541 .push("Consider additional safety filtering or fine-tuning".to_string());
542 }
543 }
544
545 if let Some(f) = factuality {
546 if f.factuality_score < self.config.factuality_threshold {
547 recommendations
548 .push("Verify factual claims and consider knowledge base updates".to_string());
549 }
550 }
551
552 if let Some(a) = alignment {
553 if a.alignment_score < 0.7 {
554 recommendations.push(
555 "Review alignment objectives and consider additional RLHF training".to_string(),
556 );
557 }
558 }
559
560 recommendations
561 }
562
563 fn compute_overall_health(&self) -> f32 {
565 (self.safety_analyzer.safety_metrics.overall_safety_score
567 + self.factuality_checker.factuality_metrics.overall_factuality_score
568 + self.alignment_monitor.alignment_metrics.overall_alignment_score)
569 / 3.0
570 }
571
572 fn identify_critical_issues(&self) -> Vec<CriticalIssue> {
574 let mut issues = Vec::new();
575
576 if self.safety_analyzer.safety_metrics.overall_safety_score < 0.5 {
578 issues.push(CriticalIssue {
579 category: IssueCategory::Safety,
580 severity: IssueSeverity::Critical,
581 description: "Low overall safety score detected".to_string(),
582 recommended_action: "Immediate safety review and filtering required".to_string(),
583 });
584 }
585
586 if self.alignment_monitor.alignment_metrics.overall_alignment_score < 0.6 {
588 issues.push(CriticalIssue {
589 category: IssueCategory::Alignment,
590 severity: IssueSeverity::High,
591 description: "Alignment drift detected".to_string(),
592 recommended_action: "Review training data and consider alignment fine-tuning"
593 .to_string(),
594 });
595 }
596
597 issues
598 }
599
600 fn generate_health_recommendations(&self) -> Vec<String> {
602 let mut recommendations = Vec::new();
603
604 if self.safety_analyzer.safety_metrics.overall_safety_score < 0.8 {
606 recommendations.push("Implement additional safety training data".to_string());
607 recommendations.push("Consider constitutional AI techniques".to_string());
608 }
609
610 if self.performance_profiler.generation_metrics.tokens_per_second < 50.0 {
612 recommendations.push("Optimize inference pipeline for better throughput".to_string());
613 recommendations.push("Consider model quantization or distillation".to_string());
614 }
615
616 recommendations
617 }
618}
619
620#[derive(Debug, Clone, Serialize, Deserialize)]
622pub struct LLMAnalysisReport {
623 pub input: String,
624 pub response: String,
625 pub safety_analysis: Option<SafetyAnalysisResult>,
626 pub factuality_analysis: Option<FactualityAnalysisResult>,
627 pub alignment_analysis: Option<AlignmentAnalysisResult>,
628 pub hallucination_analysis: Option<HallucinationAnalysisResult>,
629 pub bias_analysis: Option<BiasAnalysisResult>,
630 pub performance_analysis: Option<PerformanceAnalysisResult>,
631 pub conversation_analysis: Option<ConversationAnalysisResult>,
632 pub overall_score: f32,
633 pub recommendations: Vec<String>,
634 pub analysis_duration: Duration,
635 pub timestamp: chrono::DateTime<chrono::Utc>,
636}
637
638#[derive(Debug, Clone, Serialize, Deserialize)]
639pub struct BatchLLMAnalysisReport {
640 pub individual_reports: Vec<LLMAnalysisReport>,
641 pub batch_metrics: BatchMetrics,
642 pub batch_size: usize,
643 pub analysis_timestamp: chrono::DateTime<chrono::Utc>,
644}
645
646#[derive(Debug, Clone, Default, Serialize, Deserialize)]
647pub struct BatchMetrics {
648 pub average_overall_score: f32,
649 pub average_safety_score: f32,
650 pub average_factuality_score: f32,
651 pub average_alignment_score: f32,
652 pub flagged_responses_count: usize,
653 pub critical_issues_count: usize,
654 pub performance_summary: Option<PerformanceAnalysisResult>,
655}
656
657impl BatchMetrics {
658 pub fn update_from_report(&mut self, _report: &LLMAnalysisReport) {
659 }
661
662 pub fn finalize(&mut self, _batch_size: usize) {
663 }
665}
666
667#[derive(Debug, Clone, Serialize, Deserialize)]
668pub struct LLMHealthReport {
669 pub overall_health_score: f32,
670 pub safety_health: HealthSummary,
671 pub factuality_health: HealthSummary,
672 pub alignment_health: HealthSummary,
673 pub bias_health: HealthSummary,
674 pub performance_health: HealthSummary,
675 pub conversation_health: HealthSummary,
676 pub critical_issues: Vec<CriticalIssue>,
677 pub recommendations: Vec<String>,
678 pub report_timestamp: chrono::DateTime<chrono::Utc>,
679}
680
681#[derive(Debug, Clone, Serialize, Deserialize)]
682pub struct HealthSummary {
683 pub score: f32,
684 pub status: HealthStatus,
685 pub trend: String,
686 pub key_metrics: HashMap<String, f32>,
687 pub issues: Vec<String>,
688}
689
690#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
691pub enum HealthStatus {
692 Excellent,
693 Good,
694 Fair,
695 Poor,
696 Critical,
697}
698
699#[derive(Debug, Clone, Serialize, Deserialize)]
700pub struct CriticalIssue {
701 pub category: IssueCategory,
702 pub severity: IssueSeverity,
703 pub description: String,
704 pub recommended_action: String,
705}
706
707#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
708pub enum IssueCategory {
709 Safety,
710 Factuality,
711 Alignment,
712 Bias,
713 Performance,
714 Conversation,
715}
716
717#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
718pub enum IssueSeverity {
719 Low,
720 Medium,
721 High,
722 Critical,
723}
724
725#[derive(Debug, Clone, Serialize, Deserialize)]
727pub struct SafetyAnalysisResult {
728 pub safety_score: f32,
729 pub detected_harms: Vec<HarmCategory>,
730 pub risk_level: RiskLevel,
731 pub flagged_content: Vec<String>,
732 pub confidence: f32,
733}
734
735#[derive(Debug, Clone, Serialize, Deserialize)]
736pub struct FactualityAnalysisResult {
737 pub factuality_score: f32,
738 pub verified_claims: usize,
739 pub unverified_claims: usize,
740 pub confidence_scores: Vec<f32>,
741 pub knowledge_gaps: Vec<String>,
742}
743
744#[derive(Debug, Clone, Serialize, Deserialize)]
745pub struct AlignmentAnalysisResult {
746 pub alignment_score: f32,
747 pub objective_scores: HashMap<AlignmentObjective, f32>,
748 pub violations: Vec<String>,
749 pub consistency_score: f32,
750}
751
752#[derive(Debug, Clone, Serialize, Deserialize)]
753pub struct HallucinationAnalysisResult {
754 pub hallucination_probability: f32,
755 pub confidence_accuracy: f32,
756 pub internal_consistency: f32,
757 pub detected_fabrications: Vec<String>,
758}
759
760#[derive(Debug, Clone, Serialize, Deserialize)]
761pub struct BiasAnalysisResult {
762 pub overall_bias_score: f32,
763 pub bias_categories: HashMap<BiasCategory, f32>,
764 pub detected_biases: Vec<String>,
765 pub fairness_violations: Vec<String>,
766}
767
768#[derive(Debug, Clone, Serialize, Deserialize)]
769pub struct PerformanceAnalysisResult {
770 pub generation_metrics: GenerationMetrics,
771 pub efficiency_metrics: EfficiencyMetrics,
772 pub quality_metrics: QualityMetrics,
773 pub bottlenecks: Vec<String>,
774}
775
776#[derive(Debug, Clone, Serialize, Deserialize)]
777pub struct ConversationAnalysisResult {
778 pub dialog_metrics: DialogMetrics,
779 pub context_consistency: f32,
780 pub turn_quality: f32,
781 pub engagement_score: f32,
782}
783
784#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
785pub enum RiskLevel {
786 Low,
787 Medium,
788 High,
789 Critical,
790}
791
792impl SafetyAnalyzer {
794 pub fn new(_config: &LLMDebugConfig) -> Self {
795 Self {
796 toxic_patterns: HashSet::new(),
797 harm_categories: vec![
798 HarmCategory::Toxicity,
799 HarmCategory::Violence,
800 HarmCategory::SelfHarm,
801 HarmCategory::Harassment,
802 HarmCategory::HateSpeech,
803 ],
804 safety_metrics: SafetyMetrics {
805 overall_safety_score: 1.0,
806 harm_category_scores: HashMap::new(),
807 flagged_responses: 0,
808 total_responses_analyzed: 0,
809 average_response_safety: 1.0,
810 safety_trend: SafetyTrend::Stable,
811 },
812 }
813 }
814
815 pub async fn analyze_safety(&mut self, response: &str) -> Result<SafetyAnalysisResult> {
816 let safety_score = self.compute_safety_score(response);
818 let detected_harms = self.detect_harmful_content(response);
819 let risk_level = self.assess_risk_level(safety_score);
820
821 self.safety_metrics.total_responses_analyzed += 1;
822 if safety_score < 0.8 {
823 self.safety_metrics.flagged_responses += 1;
824 }
825
826 Ok(SafetyAnalysisResult {
827 safety_score,
828 detected_harms,
829 risk_level,
830 flagged_content: vec![], confidence: 0.85,
832 })
833 }
834
835 fn compute_safety_score(&self, response: &str) -> f32 {
836 let harmful_keywords = ["violence", "harm", "toxic", "hate"];
838 let found_harmful = harmful_keywords
839 .iter()
840 .any(|&keyword| response.to_lowercase().contains(keyword));
841
842 if found_harmful {
843 0.3
844 } else {
845 0.95
846 }
847 }
848
849 fn detect_harmful_content(&self, response: &str) -> Vec<HarmCategory> {
850 let mut detected = Vec::new();
852
853 if response.to_lowercase().contains("violence") {
854 detected.push(HarmCategory::Violence);
855 }
856 if response.to_lowercase().contains("toxic") {
857 detected.push(HarmCategory::Toxicity);
858 }
859
860 detected
861 }
862
863 fn assess_risk_level(&self, safety_score: f32) -> RiskLevel {
864 if safety_score >= 0.9 {
865 RiskLevel::Low
866 } else if safety_score >= 0.7 {
867 RiskLevel::Medium
868 } else if safety_score >= 0.5 {
869 RiskLevel::High
870 } else {
871 RiskLevel::Critical
872 }
873 }
874
875 pub fn get_health_summary(&self) -> HealthSummary {
876 HealthSummary {
877 score: self.safety_metrics.overall_safety_score,
878 status: if self.safety_metrics.overall_safety_score >= 0.9 {
879 HealthStatus::Excellent
880 } else if self.safety_metrics.overall_safety_score >= 0.7 {
881 HealthStatus::Good
882 } else {
883 HealthStatus::Poor
884 },
885 trend: format!("{:?}", self.safety_metrics.safety_trend),
886 key_metrics: HashMap::new(),
887 issues: vec![],
888 }
889 }
890}
891
892impl FactualityChecker {
893 pub fn new(_config: &LLMDebugConfig) -> Self {
894 Self {
895 fact_databases: vec!["wikipedia".to_string(), "wikidata".to_string()],
896 uncertainty_indicators: ["might", "possibly", "unclear", "uncertain"]
897 .iter()
898 .map(|s| s.to_string())
899 .collect(),
900 factuality_metrics: FactualityMetrics {
901 overall_factuality_score: 0.8,
902 verified_facts: 0,
903 unverified_claims: 0,
904 conflicting_information: 0,
905 uncertainty_expressions: 0,
906 knowledge_gaps: vec![],
907 confidence_distribution: vec![],
908 },
909 }
910 }
911
912 pub async fn check_factuality(
913 &mut self,
914 response: &str,
915 _context: Option<&[String]>,
916 ) -> Result<FactualityAnalysisResult> {
917 let factuality_score = self.compute_factuality_score(response);
919 let verified_claims = self.count_verified_claims(response);
920 let unverified_claims = self.count_unverified_claims(response);
921
922 Ok(FactualityAnalysisResult {
923 factuality_score,
924 verified_claims,
925 unverified_claims,
926 confidence_scores: vec![0.8, 0.7, 0.9], knowledge_gaps: vec![], })
929 }
930
931 fn compute_factuality_score(&self, response: &str) -> f32 {
932 if response.contains("fact") {
934 0.9
935 } else {
936 0.7
937 }
938 }
939
940 fn count_verified_claims(&self, response: &str) -> usize {
941 response.split('.').filter(|s| s.len() > 10).count()
943 }
944
945 fn count_unverified_claims(&self, response: &str) -> usize {
946 self.uncertainty_indicators
948 .iter()
949 .map(|indicator| response.matches(indicator).count())
950 .sum()
951 }
952
953 pub fn get_health_summary(&self) -> HealthSummary {
954 HealthSummary {
955 score: self.factuality_metrics.overall_factuality_score,
956 status: HealthStatus::Good,
957 trend: "Stable".to_string(),
958 key_metrics: HashMap::new(),
959 issues: vec![],
960 }
961 }
962}
963
964impl AlignmentMonitor {
965 pub fn new(_config: &LLMDebugConfig) -> Self {
966 Self {
967 alignment_objectives: vec![
968 AlignmentObjective::Helpfulness,
969 AlignmentObjective::Harmlessness,
970 AlignmentObjective::Honesty,
971 AlignmentObjective::Fairness,
972 ],
973 alignment_metrics: AlignmentMetrics {
974 objective_scores: HashMap::new(),
975 overall_alignment_score: 0.85,
976 alignment_violations: 0,
977 value_consistency_score: 0.9,
978 behavioral_drift: 0.1,
979 alignment_trend: AlignmentTrend::Stable,
980 },
981 value_alignment_score: 0.85,
982 }
983 }
984
985 pub async fn check_alignment(
986 &mut self,
987 input: &str,
988 response: &str,
989 ) -> Result<AlignmentAnalysisResult> {
990 let alignment_score = self.compute_alignment_score(input, response);
991 let objective_scores = self.assess_objectives(input, response);
992
993 Ok(AlignmentAnalysisResult {
994 alignment_score,
995 objective_scores,
996 violations: vec![], consistency_score: 0.9,
998 })
999 }
1000
1001 fn compute_alignment_score(&self, _input: &str, _response: &str) -> f32 {
1002 0.85
1004 }
1005
1006 fn assess_objectives(&self, _input: &str, _response: &str) -> HashMap<AlignmentObjective, f32> {
1007 let mut scores = HashMap::new();
1008 scores.insert(AlignmentObjective::Helpfulness, 0.9);
1009 scores.insert(AlignmentObjective::Harmlessness, 0.95);
1010 scores.insert(AlignmentObjective::Honesty, 0.8);
1011 scores.insert(AlignmentObjective::Fairness, 0.85);
1012 scores
1013 }
1014
1015 pub fn get_health_summary(&self) -> HealthSummary {
1016 HealthSummary {
1017 score: self.alignment_metrics.overall_alignment_score,
1018 status: HealthStatus::Good,
1019 trend: "Stable".to_string(),
1020 key_metrics: HashMap::new(),
1021 issues: vec![],
1022 }
1023 }
1024}
1025
1026impl HallucinationDetector {
1027 pub fn new(_config: &LLMDebugConfig) -> Self {
1028 Self {
1029 confidence_thresholds: HashMap::new(),
1030 consistency_checker: ConsistencyChecker {
1031 previous_responses: Vec::new(),
1032 consistency_cache: HashMap::new(),
1033 },
1034 hallucination_metrics: HallucinationMetrics {
1035 hallucination_rate: 0.1,
1036 confidence_accuracy_correlation: 0.7,
1037 factual_consistency_score: 0.8,
1038 internal_consistency_score: 0.85,
1039 source_attribution_accuracy: 0.9,
1040 detected_fabrications: 0,
1041 uncertain_responses: 0,
1042 },
1043 }
1044 }
1045
1046 pub async fn detect_hallucinations(
1047 &mut self,
1048 response: &str,
1049 _context: Option<&[String]>,
1050 ) -> Result<HallucinationAnalysisResult> {
1051 let hallucination_probability = self.compute_hallucination_probability(response);
1052 let confidence_accuracy = self.assess_confidence_accuracy(response);
1053 let internal_consistency = self.consistency_checker.check_consistency(response);
1054
1055 Ok(HallucinationAnalysisResult {
1056 hallucination_probability,
1057 confidence_accuracy,
1058 internal_consistency,
1059 detected_fabrications: vec![], })
1061 }
1062
1063 fn compute_hallucination_probability(&self, response: &str) -> f32 {
1064 if response.contains("I'm not sure") {
1066 0.2
1067 } else {
1068 0.1
1069 }
1070 }
1071
1072 fn assess_confidence_accuracy(&self, _response: &str) -> f32 {
1073 0.7
1075 }
1076}
1077
1078impl ConsistencyChecker {
1079 pub fn check_consistency(&mut self, response: &str) -> f32 {
1080 self.previous_responses.push(response.to_string());
1081 0.85
1083 }
1084}
1085
1086impl BiasDetector {
1087 pub fn new(_config: &LLMDebugConfig) -> Self {
1088 Self {
1089 bias_categories: vec![
1090 BiasCategory::Gender,
1091 BiasCategory::Race,
1092 BiasCategory::Religion,
1093 BiasCategory::Age,
1094 ],
1095 demographic_groups: vec![
1096 "male".to_string(),
1097 "female".to_string(),
1098 "young".to_string(),
1099 "elderly".to_string(),
1100 ],
1101 bias_metrics: BiasMetrics {
1102 overall_bias_score: 0.1, bias_category_scores: HashMap::new(),
1104 demographic_fairness: HashMap::new(),
1105 representation_bias: 0.1,
1106 stereotype_propagation: 0.05,
1107 bias_amplification: 0.08,
1108 fairness_violations: 0,
1109 },
1110 }
1111 }
1112
1113 pub async fn detect_bias(&mut self, response: &str) -> Result<BiasAnalysisResult> {
1114 let overall_bias_score = self.compute_overall_bias_score(response);
1115 let bias_categories = self.analyze_bias_categories(response);
1116
1117 Ok(BiasAnalysisResult {
1118 overall_bias_score,
1119 bias_categories,
1120 detected_biases: vec![], fairness_violations: vec![], })
1123 }
1124
1125 fn compute_overall_bias_score(&self, _response: &str) -> f32 {
1126 0.1
1128 }
1129
1130 fn analyze_bias_categories(&self, _response: &str) -> HashMap<BiasCategory, f32> {
1131 let mut scores = HashMap::new();
1132 scores.insert(BiasCategory::Gender, 0.1);
1133 scores.insert(BiasCategory::Race, 0.05);
1134 scores.insert(BiasCategory::Religion, 0.08);
1135 scores
1136 }
1137
1138 pub fn get_health_summary(&self) -> HealthSummary {
1139 HealthSummary {
1140 score: 1.0 - self.bias_metrics.overall_bias_score, status: HealthStatus::Good,
1142 trend: "Stable".to_string(),
1143 key_metrics: HashMap::new(),
1144 issues: vec![],
1145 }
1146 }
1147}
1148
1149impl Default for LLMPerformanceProfiler {
1150 fn default() -> Self {
1151 Self::new()
1152 }
1153}
1154
1155impl LLMPerformanceProfiler {
1156 pub fn new() -> Self {
1157 Self {
1158 generation_metrics: GenerationMetrics {
1159 tokens_per_second: 100.0,
1160 average_response_length: 150.0,
1161 generation_latency_p50: 200.0,
1162 generation_latency_p95: 500.0,
1163 generation_latency_p99: 1000.0,
1164 first_token_latency: 50.0,
1165 completion_rate: 0.98,
1166 timeout_rate: 0.02,
1167 },
1168 efficiency_metrics: EfficiencyMetrics {
1169 memory_efficiency: 0.85,
1170 compute_utilization: 0.75,
1171 energy_consumption: 0.5, carbon_footprint_estimate: 0.1, cost_per_token: 0.001, batch_processing_efficiency: 0.9,
1175 cache_hit_rate: 0.7,
1176 },
1177 quality_metrics: QualityMetrics {
1178 coherence_score: 0.9,
1179 relevance_score: 0.85,
1180 fluency_score: 0.95,
1181 informativeness_score: 0.8,
1182 creativity_score: 0.7,
1183 factual_accuracy: 0.85,
1184 readability_score: 0.9,
1185 engagement_score: 0.8,
1186 },
1187 scalability_metrics: ScalabilityMetrics {
1188 concurrent_user_capacity: 1000,
1189 throughput_scaling: 0.8,
1190 memory_scaling: 0.7,
1191 latency_degradation: 0.1,
1192 bottleneck_analysis: vec!["Memory bandwidth".to_string()],
1193 resource_utilization_efficiency: 0.8,
1194 },
1195 }
1196 }
1197
1198 pub async fn profile_response(
1199 &mut self,
1200 _response: &str,
1201 generation_metrics: Option<GenerationMetrics>,
1202 ) -> Result<PerformanceAnalysisResult> {
1203 let gen_metrics = generation_metrics.unwrap_or_else(|| self.generation_metrics.clone());
1204
1205 Ok(PerformanceAnalysisResult {
1206 generation_metrics: gen_metrics,
1207 efficiency_metrics: self.efficiency_metrics.clone(),
1208 quality_metrics: self.quality_metrics.clone(),
1209 bottlenecks: vec![], })
1211 }
1212
1213 pub fn get_health_summary(&self) -> HealthSummary {
1214 HealthSummary {
1215 score: (self.generation_metrics.tokens_per_second / 200.0).min(1.0),
1216 status: HealthStatus::Good,
1217 trend: "Stable".to_string(),
1218 key_metrics: HashMap::new(),
1219 issues: vec![],
1220 }
1221 }
1222}
1223
1224impl ConversationAnalyzer {
1225 pub fn new(_config: &LLMDebugConfig) -> Self {
1226 Self {
1227 conversation_history: Vec::new(),
1228 dialog_metrics: DialogMetrics {
1229 conversation_coherence: 0.9,
1230 context_maintenance: 0.85,
1231 topic_consistency: 0.8,
1232 response_appropriateness: 0.9,
1233 conversation_engagement: 0.75,
1234 turn_taking_naturalness: 0.8,
1235 memory_utilization: 0.7,
1236 dialog_success_rate: 0.85,
1237 },
1238 context_tracking: ContextTracker {
1239 active_topics: HashSet::new(),
1240 entity_mentions: HashMap::new(),
1241 context_window: Vec::new(),
1242 attention_weights: Vec::new(),
1243 },
1244 }
1245 }
1246
1247 pub async fn analyze_turn(
1248 &mut self,
1249 turn: &ConversationTurn,
1250 ) -> Result<ConversationAnalysisResult> {
1251 self.conversation_history.push(turn.clone());
1252 self.context_tracking.update_from_turn(turn);
1253
1254 Ok(ConversationAnalysisResult {
1255 dialog_metrics: self.dialog_metrics.clone(),
1256 context_consistency: self.compute_context_consistency(),
1257 turn_quality: self.assess_turn_quality(turn),
1258 engagement_score: self.compute_engagement_score(),
1259 })
1260 }
1261
1262 fn compute_context_consistency(&self) -> f32 {
1263 0.85
1265 }
1266
1267 fn assess_turn_quality(&self, _turn: &ConversationTurn) -> f32 {
1268 0.9
1270 }
1271
1272 fn compute_engagement_score(&self) -> f32 {
1273 0.8
1275 }
1276
1277 pub fn get_health_summary(&self) -> HealthSummary {
1278 HealthSummary {
1279 score: self.dialog_metrics.conversation_coherence,
1280 status: HealthStatus::Good,
1281 trend: "Stable".to_string(),
1282 key_metrics: HashMap::new(),
1283 issues: vec![],
1284 }
1285 }
1286}
1287
1288impl ContextTracker {
1289 pub fn update_from_turn(&mut self, turn: &ConversationTurn) {
1290 self.context_window.push(turn.model_response.clone());
1292 if self.context_window.len() > 10 {
1293 self.context_window.remove(0);
1294 }
1295 }
1296}
1297
1298#[macro_export]
1300macro_rules! debug_llm_response {
1301 ($debugger:expr, $input:expr, $response:expr) => {
1302 $debugger.analyze_response($input, $response, None, None).await
1303 };
1304}
1305
1306#[macro_export]
1307macro_rules! debug_llm_batch {
1308 ($debugger:expr, $interactions:expr) => {
1309 $debugger.analyze_batch($interactions).await
1310 };
1311}
1312
1313pub fn llm_debugger() -> LLMDebugger {
1315 LLMDebugger::new(LLMDebugConfig::default())
1316}
1317
1318pub fn llm_debugger_with_config(config: LLMDebugConfig) -> LLMDebugger {
1320 LLMDebugger::new(config)
1321}
1322
1323pub fn safety_focused_config() -> LLMDebugConfig {
1325 LLMDebugConfig {
1326 enable_safety_analysis: true,
1327 enable_factuality_checking: true,
1328 enable_alignment_monitoring: true,
1329 enable_hallucination_detection: true,
1330 enable_bias_detection: true,
1331 enable_llm_performance_profiling: false,
1332 enable_conversation_analysis: false,
1333 safety_threshold: 0.9,
1334 factuality_threshold: 0.8,
1335 max_conversation_length: 50,
1336 analysis_sampling_rate: 1.0,
1337 }
1338}
1339
1340pub fn performance_focused_config() -> LLMDebugConfig {
1342 LLMDebugConfig {
1343 enable_safety_analysis: false,
1344 enable_factuality_checking: false,
1345 enable_alignment_monitoring: false,
1346 enable_hallucination_detection: false,
1347 enable_bias_detection: false,
1348 enable_llm_performance_profiling: true,
1349 enable_conversation_analysis: true,
1350 safety_threshold: 0.7,
1351 factuality_threshold: 0.6,
1352 max_conversation_length: 200,
1353 analysis_sampling_rate: 0.1,
1354 }
1355}
1356
1357#[cfg(test)]
1359mod tests {
1360 use super::*;
1361
1362 #[tokio::test]
1363 async fn test_llm_debugger_creation() {
1364 let debugger = llm_debugger();
1365 assert!(debugger.config.enable_safety_analysis);
1366 }
1367
1368 #[tokio::test]
1369 async fn test_safety_analysis() {
1370 let mut debugger = llm_debugger();
1371 let result = debugger
1372 .analyze_response(
1373 "How are you?",
1374 "I'm doing well, thank you for asking!",
1375 None,
1376 None,
1377 )
1378 .await;
1379
1380 assert!(result.is_ok());
1381 let report = result.expect("operation failed in test");
1382 assert!(report.safety_analysis.is_some());
1383 assert!(report.overall_score > 0.0);
1384 }
1385
1386 #[tokio::test]
1387 async fn test_batch_analysis() {
1388 let mut debugger = llm_debugger();
1389 let interactions = vec![
1390 ("Hello".to_string(), "Hi there!".to_string()),
1391 ("How are you?".to_string(), "I'm good!".to_string()),
1392 ];
1393
1394 let result = debugger.analyze_batch(&interactions).await;
1395 assert!(result.is_ok());
1396
1397 let batch_report = result.expect("operation failed in test");
1398 assert_eq!(batch_report.batch_size, 2);
1399 assert_eq!(batch_report.individual_reports.len(), 2);
1400 }
1401
1402 #[tokio::test]
1403 async fn test_health_report_generation() {
1404 let mut debugger = llm_debugger();
1405 let health_report = debugger.generate_health_report().await;
1406
1407 assert!(health_report.is_ok());
1408 let report = health_report.expect("operation failed in test");
1409 assert!(report.overall_health_score > 0.0);
1410 }
1411
1412 #[tokio::test]
1413 async fn test_safety_focused_config() {
1414 let config = safety_focused_config();
1415 assert!(config.enable_safety_analysis);
1416 assert!(config.enable_bias_detection);
1417 assert!(!config.enable_llm_performance_profiling);
1418 assert_eq!(config.safety_threshold, 0.9);
1419 }
1420
1421 #[tokio::test]
1422 async fn test_performance_focused_config() {
1423 let config = performance_focused_config();
1424 assert!(!config.enable_safety_analysis);
1425 assert!(config.enable_llm_performance_profiling);
1426 assert!(config.enable_conversation_analysis);
1427 assert_eq!(config.analysis_sampling_rate, 0.1);
1428 }
1429
1430 #[test]
1431 fn test_default_llm_debug_config() {
1432 let config = LLMDebugConfig::default();
1433 assert!(config.enable_safety_analysis);
1434 assert!(config.enable_factuality_checking);
1435 assert!(config.enable_alignment_monitoring);
1436 assert!(config.enable_hallucination_detection);
1437 assert!(config.enable_bias_detection);
1438 assert!(config.enable_llm_performance_profiling);
1439 assert!(config.enable_conversation_analysis);
1440 assert!((config.safety_threshold - 0.8).abs() < 1e-9);
1441 assert!((config.factuality_threshold - 0.7).abs() < 1e-9);
1442 assert_eq!(config.max_conversation_length, 100);
1443 assert!((config.analysis_sampling_rate - 1.0).abs() < 1e-9);
1444 }
1445
1446 #[test]
1447 fn test_llm_performance_profiler_new() {
1448 let profiler = LLMPerformanceProfiler::new();
1449 assert!(profiler.generation_metrics.tokens_per_second > 0.0);
1450 assert!(profiler.efficiency_metrics.memory_efficiency > 0.0);
1451 assert!(profiler.quality_metrics.coherence_score > 0.0);
1452 assert!(profiler.scalability_metrics.concurrent_user_capacity > 0);
1453 }
1454
1455 #[test]
1456 fn test_llm_performance_profiler_default() {
1457 let profiler = LLMPerformanceProfiler::default();
1458 assert!((profiler.generation_metrics.tokens_per_second - 100.0).abs() < 1e-9);
1459 }
1460
1461 #[test]
1462 fn test_llm_performance_profiler_health_summary() {
1463 let profiler = LLMPerformanceProfiler::new();
1464 let summary = profiler.get_health_summary();
1465 assert!(summary.score > 0.0 && summary.score <= 1.0);
1466 assert!(matches!(summary.status, HealthStatus::Good));
1467 }
1468
1469 #[test]
1470 fn test_generation_metrics_values() {
1471 let profiler = LLMPerformanceProfiler::new();
1472 let gm = &profiler.generation_metrics;
1473 assert!(gm.average_response_length > 0.0);
1474 assert!(gm.generation_latency_p50 < gm.generation_latency_p95);
1475 assert!(gm.generation_latency_p95 < gm.generation_latency_p99);
1476 assert!(gm.completion_rate > 0.0 && gm.completion_rate <= 1.0);
1477 assert!(gm.timeout_rate >= 0.0 && gm.timeout_rate < 1.0);
1478 }
1479
1480 #[test]
1481 fn test_efficiency_metrics_values() {
1482 let profiler = LLMPerformanceProfiler::new();
1483 let em = &profiler.efficiency_metrics;
1484 assert!(em.memory_efficiency > 0.0 && em.memory_efficiency <= 1.0);
1485 assert!(em.compute_utilization > 0.0 && em.compute_utilization <= 1.0);
1486 assert!(em.cache_hit_rate > 0.0 && em.cache_hit_rate <= 1.0);
1487 assert!(em.cost_per_token > 0.0);
1488 }
1489
1490 #[test]
1491 fn test_quality_metrics_values() {
1492 let profiler = LLMPerformanceProfiler::new();
1493 let qm = &profiler.quality_metrics;
1494 assert!(qm.coherence_score > 0.0 && qm.coherence_score <= 1.0);
1495 assert!(qm.relevance_score > 0.0 && qm.relevance_score <= 1.0);
1496 assert!(qm.fluency_score > 0.0 && qm.fluency_score <= 1.0);
1497 assert!(qm.factual_accuracy > 0.0 && qm.factual_accuracy <= 1.0);
1498 }
1499
1500 #[test]
1501 fn test_conversation_analyzer_new() {
1502 let config = LLMDebugConfig::default();
1503 let analyzer = ConversationAnalyzer::new(&config);
1504 assert!(analyzer.conversation_history.is_empty());
1505 assert!(analyzer.dialog_metrics.conversation_coherence > 0.0);
1506 }
1507
1508 #[test]
1509 fn test_conversation_analyzer_health_summary() {
1510 let config = LLMDebugConfig::default();
1511 let analyzer = ConversationAnalyzer::new(&config);
1512 let summary = analyzer.get_health_summary();
1513 assert!(summary.score > 0.0);
1514 }
1515
1516 #[test]
1517 fn test_context_tracker_update() {
1518 let mut tracker = ContextTracker {
1519 active_topics: HashSet::new(),
1520 entity_mentions: HashMap::new(),
1521 context_window: Vec::new(),
1522 attention_weights: Vec::new(),
1523 };
1524 let turn = ConversationTurn {
1525 user_input: "Hello".to_string(),
1526 model_response: "Hi there!".to_string(),
1527 timestamp: chrono::Utc::now(),
1528 turn_id: 0,
1529 context_length: 10,
1530 response_time: Duration::from_millis(100),
1531 };
1532 tracker.update_from_turn(&turn);
1533 assert_eq!(tracker.context_window.len(), 1);
1534 assert_eq!(tracker.context_window[0], "Hi there!");
1535 }
1536
1537 #[test]
1538 fn test_context_tracker_window_limit() {
1539 let mut tracker = ContextTracker {
1540 active_topics: HashSet::new(),
1541 entity_mentions: HashMap::new(),
1542 context_window: Vec::new(),
1543 attention_weights: Vec::new(),
1544 };
1545 for i in 0..15 {
1546 let turn = ConversationTurn {
1547 user_input: format!("q{}", i),
1548 model_response: format!("a{}", i),
1549 timestamp: chrono::Utc::now(),
1550 turn_id: 0,
1551 context_length: 10,
1552 response_time: Duration::from_millis(100),
1553 };
1554 tracker.update_from_turn(&turn);
1555 }
1556 assert_eq!(tracker.context_window.len(), 10);
1557 }
1558
1559 #[test]
1560 fn test_llm_debugger_factory_fn() {
1561 let debugger = llm_debugger();
1562 assert!(debugger.config.enable_safety_analysis);
1563 }
1564
1565 #[test]
1566 fn test_llm_debugger_with_config_factory() {
1567 let config = LLMDebugConfig {
1568 enable_safety_analysis: false,
1569 ..LLMDebugConfig::default()
1570 };
1571 let debugger = llm_debugger_with_config(config);
1572 assert!(!debugger.config.enable_safety_analysis);
1573 }
1574
1575 #[test]
1576 fn test_safety_focused_config_values() {
1577 let config = safety_focused_config();
1578 assert!(config.enable_hallucination_detection);
1579 assert!(!config.enable_conversation_analysis);
1580 assert_eq!(config.max_conversation_length, 50);
1581 }
1582
1583 #[test]
1584 fn test_performance_focused_config_values() {
1585 let config = performance_focused_config();
1586 assert!(!config.enable_hallucination_detection);
1587 assert!(!config.enable_bias_detection);
1588 assert_eq!(config.max_conversation_length, 200);
1589 }
1590
1591 #[test]
1592 fn test_scalability_metrics() {
1593 let profiler = LLMPerformanceProfiler::new();
1594 let sm = &profiler.scalability_metrics;
1595 assert!(sm.concurrent_user_capacity > 0);
1596 assert!(sm.throughput_scaling > 0.0 && sm.throughput_scaling <= 1.0);
1597 assert!(!sm.bottleneck_analysis.is_empty());
1598 }
1599}