mod cross_model_validator;
mod adversarial_generator;
mod semantic_equivalence;
mod consistency_metrics;
pub use cross_model_validator::*;
pub use adversarial_generator::*;
pub use semantic_equivalence::*;
pub use consistency_metrics::*;
use crate::error::Result;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SemanticValidationConfig {
pub min_models: usize,
pub similarity_threshold: f64,
pub max_variance: f64,
pub enable_adversarial_generation: bool,
pub adversarial_intensity: f64,
pub enable_caching: bool,
pub cache_ttl_secs: u64,
}
impl Default for SemanticValidationConfig {
fn default() -> Self {
Self {
min_models: 3,
similarity_threshold: 0.85,
max_variance: 0.15,
enable_adversarial_generation: true,
adversarial_intensity: 0.3,
enable_caching: true,
cache_ttl_secs: 3600, }
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ModelValidation {
pub model_id: String,
pub provider: String,
pub response: String,
pub confidence: f64,
pub factual_accuracy: Option<f64>,
pub logical_consistency: Option<f64>,
pub latency_ms: u64,
pub warnings: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MultiModelValidation {
pub query: String,
pub target_answer: Option<String>,
pub model_validations: Vec<ModelValidation>,
pub consensus: ConsensusMetrics,
pub semantic_variance: f64,
pub outliers: Vec<OutlierDetection>,
pub time_to_consensus_ms: u64,
pub recommendations: Vec<ValidationRecommendation>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConsensusMetrics {
pub reached: bool,
pub score: f64,
pub agreeing_models: usize,
pub disagreeing_models: usize,
pub consensus_response: Option<String>,
pub consensus_consistency: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OutlierDetection {
pub outlier_model: String,
pub distance_from_consensus: f64,
pub reason: OutlierReason,
pub suggested_correction: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OutlierReason {
SemanticDistance,
FactualInaccuracy,
LogicalInconsistency,
ResponseAnomaly,
AdversarialSusceptibility,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ValidationRecommendation {
pub priority: RecommendationPriority,
pub text: String,
pub action: String,
pub expected_improvement: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum RecommendationPriority {
Critical,
High,
Medium,
Low,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum AttackStrategy {
ContradictionInjection,
LogicalFallacyEmbedding,
AmbiguityAmplification,
BoundaryExploration,
SemanticPollution,
FormatManipulation,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AdversarialTestSuite {
pub base_prompt: String,
pub adversarial_variants: Vec<AdversarialVariant>,
pub strategies: Vec<AttackStrategy>,
pub success_rates: Vec<f64>,
pub susceptibility_scores: Vec<ModelSusceptibility>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AdversarialVariant {
pub id: String,
pub prompt: String,
pub strategy: AttackStrategy,
pub intensity: f64,
pub expected_impact: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ModelSusceptibility {
pub model_id: String,
pub score: f64,
pub strategy_scores: Vec<StrategySusceptibility>,
pub vulnerability_patterns: Vec<VulnerabilityPattern>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StrategySusceptibility {
pub strategy: AttackStrategy,
pub score: f64,
pub success_rate: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct VulnerabilityPattern {
pub pattern_id: String,
pub description: String,
pub severity: VulnerabilitySeverity,
pub mitigations: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum VulnerabilitySeverity {
Critical,
High,
Medium,
Low,
}
pub trait SemanticValidator {
fn validate_query(
&self,
query: &str,
target_answer: Option<&str>,
) -> Result<MultiModelValidation>;
fn check_consistency(
&self,
current: &MultiModelValidation,
previous: &MultiModelValidation,
) -> ConsistencyResult;
fn generate_adversarial_suite(
&self,
base_prompt: &str,
strategies: Vec<AttackStrategy>,
) -> Result<AdversarialTestSuite>;
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConsistencyResult {
pub consistent: bool,
pub score: f64,
pub drift_amount: f64,
pub drift_direction: DriftDirection,
pub corrections: Vec<ConsistencyCorrection>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum DriftDirection {
Improvement,
Regression,
SemanticShift,
NoSignificantDrift,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConsistencyCorrection {
pub correction_type: CorrectionType,
pub suggested_action: String,
pub expected_impact: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum CorrectionType {
SemanticAlignment,
ModelRetraining,
PromptEnhancement,
ValidationStrengthening,
}
pub mod utils {
use super::*;
pub fn calculate_semantic_similarity(text1: &str, text2: &str) -> f64 {
let words1: Vec<&str> = text1.split_whitespace().collect();
let words2: Vec<&str> = text2.split_whitespace().collect();
let common_words: Vec<&str> = words1
.iter()
.filter(|w| words2.contains(w))
.copied()
.collect();
let total_words = words1.len().max(words2.len());
if total_words == 0 {
return 1.0; }
common_words.len() as f64 / total_words as f64
}
pub fn detect_semantic_drift(
old: &MultiModelValidation,
new: &MultiModelValidation,
) -> DriftAnalysis {
let similarity = calculate_semantic_similarity(
&old.query,
&new.query,
);
let consensus_diff = (old.consensus.score - new.consensus.score).abs();
let variance_diff = (old.semantic_variance - new.semantic_variance).abs();
DriftAnalysis {
semantic_similarity: similarity,
consensus_change: consensus_diff,
variance_change: variance_diff,
significant_drift: consensus_diff > 0.1 || variance_diff > 0.1,
}
}
#[derive(Debug, Clone)]
pub struct DriftAnalysis {
pub semantic_similarity: f64,
pub consensus_change: f64,
pub variance_change: f64,
pub significant_drift: bool,
}
}