use async_trait::async_trait;
use langchainrust::evaluation::*;
use langchainrust::schema::Message;
use langchainrust::{
BaseChatModel, OpenAIChat, OpenAIConfig, OpenAIEmbeddings, OpenAIEmbeddingsConfig,
};
struct ModelPredictor {
model: OpenAIChat,
}
#[async_trait]
impl Predictor for ModelPredictor {
async fn predict(&self, input: &str) -> Result<String, EvalError> {
let system = "You answer the user's question concisely. Use only known facts.";
let reply = self
.model
.chat_with_system(system.to_string(), vec![Message::human(input)])
.await
.map_err(|e| EvalError::PredictorError(e.to_string()))?;
Ok(reply.content)
}
async fn begin_run(&self, run_id: &str) {
println!("starting evaluation run {run_id}");
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let api_key = std::env::var("OPENAI_API_KEY")
.map_err(|_| "please set the OPENAI_API_KEY environment variable")?;
let base_url =
std::env::var("OPENAI_BASE_URL").unwrap_or_else(|_| "https://api.openai.com/v1".into());
let judge_model = std::env::var("EVAL_JUDGE_MODEL").unwrap_or_else(|_| "gpt-4o-mini".into());
let embed_name =
std::env::var("EVAL_EMBED_MODEL").unwrap_or_else(|_| "text-embedding-ada-002".into());
let chat_config = OpenAIConfig {
api_key: api_key.clone(),
base_url: base_url.clone(),
model: judge_model,
..Default::default()
};
let answerer = OpenAIChat::new(chat_config.clone());
let judge1 = OpenAIChat::new(chat_config.clone());
let judge2 = OpenAIChat::new(chat_config.clone());
let judge3 = OpenAIChat::new(chat_config);
let embeddings = OpenAIEmbeddings::new(OpenAIEmbeddingsConfig {
api_key,
base_url,
model: embed_name,
..Default::default()
})?;
let dataset = Dataset::new(vec![Example::with_contexts(
"Which planet is closest to the Sun?",
"Mercury",
vec![
"Mercury is the smallest planet in the Solar System and the closest to the Sun.".into(),
"Venus is the second planet from the Sun, between Mercury and Earth.".into(),
],
)]);
let run_id = std::env::var("EVAL_RUN_ID").unwrap_or_else(|_| "ragas-demo".to_string());
let runner = EvalRunner::new(vec![])
.with_rag_evaluators(vec![
Box::new(ContextPrecision::new(judge1)),
Box::new(ContextRecall::new(judge2)),
Box::new(AnswerRelevancy::new(judge3, embeddings)),
])
.with_run_id(run_id);
let report = runner
.run(&dataset, &ModelPredictor { model: answerer })
.await?;
println!("{}", report.to_table());
match std::env::var("EVAL_EXPORT") {
Ok(path) => {
report.write_jsonl(&path).await?;
println!("wrote JSONL export to {path}");
}
Err(_) => print!("{}", report.to_jsonl()),
}
Ok(())
}