141 lines
4.8 KiB
Rust
141 lines
4.8 KiB
Rust
|
|
//! # Learning Curves Example
|
|||
|
|
//!
|
|||
|
|
//! Demonstrates how agent learning curves are computed and displayed.
|
|||
|
|
//!
|
|||
|
|
//! ## What This Example Shows
|
|||
|
|
//! - Recording execution data over time
|
|||
|
|
//! - Computing learning curves from historical data
|
|||
|
|
//! - Understanding performance trends
|
|||
|
|
//! - Visualizing improvement over time
|
|||
|
|
//!
|
|||
|
|
//! ## Run
|
|||
|
|
//! ```bash
|
|||
|
|
//! cargo run --example 02-learning-curves -p vapora-knowledge-graph
|
|||
|
|
//! ```
|
|||
|
|
|
|||
|
|
use chrono::{Duration, Utc};
|
|||
|
|
|
|||
|
|
fn main() {
|
|||
|
|
println!("=== Learning Curves Example ===\n");
|
|||
|
|
|
|||
|
|
// Step 1: Simulate 30 days of execution history
|
|||
|
|
let now = Utc::now();
|
|||
|
|
|
|||
|
|
#[derive(Clone)]
|
|||
|
|
struct DailyStats {
|
|||
|
|
date: String,
|
|||
|
|
executions: u32,
|
|||
|
|
successful: u32,
|
|||
|
|
avg_duration_ms: u32,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
let mut daily_data = vec![];
|
|||
|
|
|
|||
|
|
for day in 0..30 {
|
|||
|
|
let date_obj = now - Duration::days(day);
|
|||
|
|
let date_str = date_obj.format("%Y-%m-%d").to_string();
|
|||
|
|
|
|||
|
|
// Simulate improvement: success rate increases over time
|
|||
|
|
let base_success_rate = 0.70 + (day as f64 / 30.0) * 0.22; // From 70% to 92%
|
|||
|
|
let executions = 10;
|
|||
|
|
let successful = (executions as f64 * base_success_rate) as u32;
|
|||
|
|
let avg_duration = 300 - (day as u32 * 3); // Tasks get faster
|
|||
|
|
|
|||
|
|
daily_data.push(DailyStats {
|
|||
|
|
date: date_str,
|
|||
|
|
executions,
|
|||
|
|
successful,
|
|||
|
|
avg_duration_ms: avg_duration,
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Reverse to show chronologically
|
|||
|
|
daily_data.reverse();
|
|||
|
|
|
|||
|
|
// Step 2: Display learning curve data
|
|||
|
|
println!("=== Agent: developer-bob (30-day history) ===\n");
|
|||
|
|
println!("Date | Success Rate | Duration | Trend");
|
|||
|
|
println!("-----------|------|");
|
|||
|
|
|
|||
|
|
let mut prev_success = 0.0;
|
|||
|
|
for data in &daily_data {
|
|||
|
|
let success_rate = (data.successful as f64 / data.executions as f64) * 100.0;
|
|||
|
|
let trend = if success_rate > prev_success {
|
|||
|
|
"↑"
|
|||
|
|
} else if success_rate < prev_success {
|
|||
|
|
"↓"
|
|||
|
|
} else {
|
|||
|
|
"→"
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
let bar_length = (success_rate / 5.0) as usize;
|
|||
|
|
let bar = "█".repeat(bar_length) + &"░".repeat(20 - bar_length);
|
|||
|
|
|
|||
|
|
println!(
|
|||
|
|
"{} | {} | {:.0}% | {}ms | {}",
|
|||
|
|
data.date, bar, success_rate, data.avg_duration_ms, trend
|
|||
|
|
);
|
|||
|
|
prev_success = success_rate;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Step 3: Compute overall learning curve
|
|||
|
|
println!("\n=== Learning Curve Analysis ===\n");
|
|||
|
|
|
|||
|
|
let total_executions: u32 = daily_data.iter().map(|d| d.executions).sum();
|
|||
|
|
let total_successful: u32 = daily_data.iter().map(|d| d.successful).sum();
|
|||
|
|
let overall_success = (total_successful as f64 / total_executions as f64) * 100.0;
|
|||
|
|
|
|||
|
|
println!("Total executions: {}", total_executions);
|
|||
|
|
println!("Total successful: {}", total_successful);
|
|||
|
|
println!("Overall success rate: {:.1}%\n", overall_success);
|
|||
|
|
|
|||
|
|
// Compute 7-day and 14-day windows
|
|||
|
|
let recent_7 = &daily_data[daily_data.len() - 7..];
|
|||
|
|
let recent_14 = &daily_data[daily_data.len() - 14..];
|
|||
|
|
|
|||
|
|
let recent_7_success: f64 = recent_7.iter().map(|d| d.successful as f64).sum::<f64>()
|
|||
|
|
/ recent_7.iter().map(|d| d.executions as f64).sum::<f64>();
|
|||
|
|
let recent_14_success: f64 = recent_14.iter().map(|d| d.successful as f64).sum::<f64>()
|
|||
|
|
/ recent_14.iter().map(|d| d.executions as f64).sum::<f64>();
|
|||
|
|
|
|||
|
|
println!("Last 7 days success rate: {:.1}%", recent_7_success * 100.0);
|
|||
|
|
println!(
|
|||
|
|
"Last 14 days success rate: {:.1}%",
|
|||
|
|
recent_14_success * 100.0
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
// Step 4: Demonstrate recency bias
|
|||
|
|
println!("\n=== Recency Bias ===");
|
|||
|
|
println!("Recent days weighted 3× higher than older days");
|
|||
|
|
println!("Last 7 days: 3.0x weight");
|
|||
|
|
println!("Days 8-30: 1.0x weight\n");
|
|||
|
|
|
|||
|
|
let weighted_recent = recent_7_success * 3.0;
|
|||
|
|
let weighted_older: f64 = daily_data[0..23]
|
|||
|
|
.iter()
|
|||
|
|
.map(|d| (d.successful as f64 / d.executions as f64))
|
|||
|
|
.sum::<f64>()
|
|||
|
|
/ 23.0;
|
|||
|
|
let weighted_older = weighted_older * 1.0;
|
|||
|
|
|
|||
|
|
let final_score = (weighted_recent + weighted_older) / (3.0 + 1.0);
|
|||
|
|
println!("Weighted score: {:.1}%", final_score * 100.0);
|
|||
|
|
|
|||
|
|
// Step 5: Recommendations
|
|||
|
|
println!("\n=== Agent Performance Trend ===");
|
|||
|
|
let improvement =
|
|||
|
|
recent_7_success - (daily_data[0].successful as f64 / daily_data[0].executions as f64);
|
|||
|
|
if improvement > 0.0 {
|
|||
|
|
println!("✓ IMPROVING (+{:.1}%)", improvement * 100.0);
|
|||
|
|
println!(" → Agent is learning from experience");
|
|||
|
|
println!(" → Ready for more complex tasks");
|
|||
|
|
} else if improvement < 0.0 {
|
|||
|
|
println!("✗ DECLINING ({:.1}%)", improvement * 100.0);
|
|||
|
|
println!(" → Check for blocking issues");
|
|||
|
|
println!(" → Consider additional training");
|
|||
|
|
} else {
|
|||
|
|
println!("→ STABLE");
|
|||
|
|
println!(" → Consistent performance");
|
|||
|
|
}
|
|||
|
|
}
|