Vapora/crates/vapora-agents/examples/03-agent-selection.rs

144 lines
4.4 KiB
Rust
Raw Permalink Normal View History

2026-01-12 03:34:01 +00:00
//! # Agent Selection Example
//!
//! Demonstrates how agents are ranked and selected based on expertise and load.
//!
//! ## What This Example Shows
//! - Comparing multiple agents for a task
//! - Understanding the scoring formula: 0.3*load + 0.5*expertise +
//! 0.2*confidence
//! - How load balancing prevents over-allocation
//! - Real-world selection decisions
//!
//! ## Run
//! ```bash
//! cargo run --example 03-agent-selection -p vapora-agents
//! ```
fn main() {
println!("=== Agent Selection Example ===\n");
// Step 1: Define agent profiles with different characteristics
#[derive(Debug, Clone)]
struct AgentProfile {
name: String,
expertise: f64, // 0.0 to 1.0
confidence: f64, // 0.0 to 1.0 (based on sample size)
current_load: f64, // 0.0 to 1.0
}
let agents = vec![
AgentProfile {
name: "alice".to_string(),
expertise: 0.92,
confidence: 0.95,
current_load: 0.30, // Moderately busy
},
AgentProfile {
name: "bob".to_string(),
expertise: 0.78,
confidence: 0.85,
current_load: 0.05, // Very available
},
AgentProfile {
name: "carol".to_string(),
expertise: 0.88,
confidence: 0.70,
current_load: 0.50, // Quite busy
},
];
println!("Available agents for 'coding' task:\n");
for agent in &agents {
println!(
" {}: expertise={:.0}%, confidence={:.0}%, load={:.0}%",
agent.name,
agent.expertise * 100.0,
agent.confidence * 100.0,
agent.current_load * 100.0
);
}
// Step 2: Apply scoring formula
println!("\n=== Scoring Formula ===");
println!("score = (1 - 0.3*load) + 0.5*expertise + 0.2*confidence");
println!(" ↓ ↓ ↓");
println!(" availability expertise confidence/trust\n");
// Normalize load contribution (lower load = higher score)
let scores: Vec<_> = agents
.iter()
.map(|agent| {
let availability = 1.0 - (0.3 * agent.current_load);
let expertise_score = 0.5 * agent.expertise;
let confidence_score = 0.2 * agent.confidence;
let total = availability + expertise_score + confidence_score;
(
agent,
availability,
expertise_score,
confidence_score,
total,
)
})
.collect();
println!("Agent Scores:");
for (agent, avail, exp, conf, total) in &scores {
println!(
"\n {}: {:.3} (avail={:.3}, exp={:.3}, conf={:.3})",
agent.name, total, avail, exp, conf
);
}
// Step 3: Rank agents
let mut sorted_scores = scores.clone();
sorted_scores.sort_by(|a, b| b.4.partial_cmp(&a.4).unwrap_or(std::cmp::Ordering::Equal));
println!("\n=== Ranking (Best → Worst) ===");
for (rank, (agent, _, _, _, total)) in sorted_scores.iter().enumerate() {
let medal = match rank {
0 => "🥇",
1 => "🥈",
2 => "🥉",
_ => " ",
};
println!(
"{} {}. {} (score: {:.3})",
medal,
rank + 1,
agent.name,
total
);
}
// Step 4: Selection decision
let best_agent = sorted_scores[0].0;
println!("\n=== Selection Decision ===");
println!("Assigned to: {}", best_agent.name);
println!(
"Reason: Best balance of expertise ({:.0}%), availability ({:.0}%), and confidence \
({:.0}%)",
best_agent.expertise * 100.0,
(1.0 - (0.3 * best_agent.current_load)) * 100.0,
best_agent.confidence * 100.0
);
// Step 5: Demonstrate impact of load balancing
println!("\n=== Load Balancing Impact ===");
println!("If alice wasn't available (hypothetical):");
let mut remaining = sorted_scores.clone();
remaining.remove(0);
let second_best = &remaining[0].0;
println!(
" → Would select: {} (score: {:.3})",
second_best.name, remaining[0].4
);
println!("\nWithout load balancing, carol would be selected despite:");
println!(" - Lower expertise (88% vs 92%)");
println!(" - Same recent success rate");
println!(" BUT: It's already running at 50% capacity!");
}