144 lines
4.4 KiB
Rust
144 lines
4.4 KiB
Rust
//! # 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!");
|
|
}
|