use anyhow::Result;
use std::collections::HashMap;
use vecstore::{
text_splitter::{RecursiveCharacterTextSplitter, TextSplitter},
Metadata, Query, VecStore,
};
fn main() -> Result<()> {
println!("📊 RAG Evaluation Demo\n");
println!("This example shows how to evaluate your RAG system quality.\n");
println!("Step 1: Building RAG system...");
let documents = vec![
"VecStore is a high-performance vector database built in Rust.",
"It provides HNSW indexing, persistence, and a complete RAG toolkit.",
"VecStore achieves 10-100x faster performance compared to Python implementations.",
];
let mut store = VecStore::open("./data/09_evaluation")?;
let splitter = RecursiveCharacterTextSplitter::new(200, 20);
for (i, doc) in documents.iter().enumerate() {
let chunks = splitter.split_text(doc)?;
for (j, chunk) in chunks.into_iter().enumerate() {
let mut metadata = Metadata {
fields: HashMap::new(),
};
metadata
.fields
.insert("text".to_string(), serde_json::json!(chunk));
store.upsert(format!("doc{}_{}", i, j), mock_embed(&chunk), metadata)?;
}
}
println!(" ✓ RAG system ready\n");
println!("Step 2: Evaluating RAG quality...\n");
let test_cases = vec![
(
"What is VecStore?",
"VecStore is a high-performance vector database built in Rust.",
),
(
"How fast is VecStore?",
"VecStore achieves 10-100x faster performance than Python.",
),
];
let mut total_score = 0.0;
for (query, expected) in &test_cases {
println!("❓ Query: {}", query);
let results = store.query(Query {
vector: mock_embed(query),
k: 2,
filter: None,
})?;
let score = results.first().map(|r| r.score).unwrap_or(0.0);
total_score += score;
println!(" 📄 Retrieved {} chunks", results.len());
println!(" 📈 Relevance Score: {:.3}\n", score);
}
let avg_score = total_score / test_cases.len() as f32;
println!("Overall Average Score: {:.3}", avg_score);
println!("\n💡 For complete evaluation with LLM-as-judge:");
println!(" See: vecstore-eval/examples/evaluate_rag.rs");
println!(" Metrics: Context Relevance, Answer Faithfulness, Answer Correctness");
println!("\n✅ Evaluation Demo Complete!");
Ok(())
}
fn mock_embed(text: &str) -> Vec<f32> {
let words: Vec<&str> = text.split_whitespace().collect();
let mut embedding = vec![0.0; 384];
for (i, word) in words.iter().enumerate() {
embedding[(word.len() * (i + 1)) % 384] += 1.0;
}
let mag: f32 = embedding.iter().map(|x| x * x).sum::<f32>().sqrt();
if mag > 0.0 {
for val in &mut embedding {
*val /= mag;
}
}
embedding
}