تقييم الوكيل
يوفر The adk-eval crate أدوات شاملة لاختبار والتحقق من صحة سلوك الـ Agent. على عكس اختبار البرمجيات التقليدي، يجب أن يراعي تقييم الـ Agent الطبيعة الاحتمالية لـ LLMs مع الاستمرار في توفير جودة ذات معنى. إشارات.
نظرة عامة
يدعم تقييم الوكيل في ADK-Rust استراتيجيات تقييم متعددة:
- تقييم المسار: التحقق من أن agents تستدعي expected tools بالتسلسل الصحيح
- تشابه الاستجابة: مقارنة استجابات agent باستخدام خوارزميات مختلفة (Jaccard, Levenshtein, ROUGE)
- LLM-تقييم محكّم: استخدم LLM آخر لتقييم التشابه الدلالي والجودة
- التسجيل المستند إلى معايير: قيّم بناءً على معايير مخصصة مع تسجيل مرجح
بدء سريع
use adk_eval::{Evaluator, EvaluationConfig, EvaluationCriteria};
use std::sync::Arc;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create your agent
let agent = create_my_agent()?;
// Configure evaluator with criteria
let config = EvaluationConfig::with_criteria(
EvaluationCriteria::exact_tools()
.with_response_similarity(0.8)
);
let evaluator = Evaluator::new(config);
// Run evaluation against test file
let report = evaluator
.evaluate_file(agent, "tests/my_agent.test.json")
.await?;
// Check results
if report.all_passed() {
println!("All {} tests passed!", report.summary.total);
} else {
println!("{}", report.format_summary());
}
Ok(())
}
تنسيق ملف الاختبار
تُعرّف حالات الاختبار في JSON ملفات ذات اللاحقة .test.json:
{
"eval_set_id": "weather_agent_tests",
"name": "Weather Agent Tests",
"description": "Test weather agent functionality",
"eval_cases": [
{
"eval_id": "test_current_weather",
"conversation": [
{
"invocation_id": "inv_001",
"user_content": {
"parts": [{"text": "What's the weather in NYC?"}],
"role": "user"
},
"final_response": {
"parts": [{"text": "The weather in NYC is 65°F and sunny."}],
"role": "model"
},
"intermediate_data": {
"tool_uses": [
{
"name": "get_weather",
"args": {"location": "NYC"}
}
]
}
}
]
}
]
}
معايير التقييم
مطابقة مسار الأدوات
تتحقق من أن الوكلاء يستدعون الأدوات المتوقعة بالترتيب الصحيح:
let criteria = EvaluationCriteria {
tool_trajectory_score: Some(1.0), // Require 100% match
tool_trajectory_config: Some(ToolTrajectoryConfig {
strict_order: true, // Tools must be called in exact order
strict_args: false, // Allow extra arguments in tool calls
}),
..Default::default()
};
خيارات:
strict_order: يتطلب مطابقة تسلسل دقيقةstrict_args: يتطلب مطابقة وسيطة دقيقة (لا يُسمح بوسائط إضافية)- مطابقة جزئية مع عتبات قابلة للتكوين
تشابه الاستجابة
قارن نص الاستجابة باستخدام خوارزميات مختلفة:
let criteria = EvaluationCriteria {
response_similarity: Some(0.8), // 80% similarity required
response_match_config: Some(ResponseMatchConfig {
algorithm: SimilarityAlgorithm::Jaccard,
ignore_case: true,
normalize: true,
..Default::default()
}),
..Default::default()
};
الخوارزميات المتاحة:
| خوارزمية | الوصف |
|---|---|
Exact | مطابقة تامة للسلسلة النصية |
Contains | التحقق من السلسلة الفرعية |
Levenshtein | مسافة التحرير |
Jaccard | تداخل الكلمات (افتراضي) |
Rouge1 | تداخل أحادي الجرام |
Rouge2 | تداخل الثنائيات |
RougeL | أطول تسلسل فرعي مشترك |
LLM-المطابقة الدلالية المقيمة
استخدم LLM لتقييم التكافؤ الدلالي:
use adk_eval::{Evaluator, EvaluationConfig, EvaluationCriteria, LlmJudge};
use adk_model::GeminiModel;
// Create evaluator with LLM judge
let judge_model = Arc::new(GeminiModel::new(&api_key, "gemini-2.5-flash")?);
let config = EvaluationConfig::with_criteria(
EvaluationCriteria::semantic_match(0.85)
);
let evaluator = Evaluator::with_llm_judge(config, judge_model);
يقوم محكم LLM بتقييم:
- التكافؤ الدلالي (نفس المعنى، كلمات مختلفة)
- الدقة الواقعية
- اكتمال الاستجابة
التقييم القائم على المعايير
قم بالتقييم مقابل معايير مخصصة مع تسجيل مرجح:
use adk_eval::{Rubric, EvaluationCriteria};
let criteria = EvaluationCriteria::default()
.with_rubrics(0.7, vec![
Rubric::new("Accuracy", "Response is factually correct")
.with_weight(0.5),
Rubric::new("Helpfulness", "Response addresses user's needs")
.with_weight(0.3),
Rubric::new("Clarity", "Response is clear and well-organized")
.with_weight(0.2),
]);
يتم تسجيل كل معيار من 0-1 بواسطة LLM المحكّم، ثم يتم دمجها باستخدام الأوزان.
اكتشاف السلامة والهلوسة
تحقق من الاستجابات بحثًا عن قضايا السلامة والهلوسة:
let criteria = EvaluationCriteria {
safety_score: Some(0.95), // Require high safety score
hallucination_score: Some(0.9), // Require low hallucination rate
..Default::default()
};
الإبلاغ عن النتائج
يقدم تقرير التقييم نتائج مفصلة:
let report = evaluator.evaluate_file(agent, "tests/agent.test.json").await?;
// Summary statistics
println!("Total: {}", report.summary.total);
println!("Passed: {}", report.summary.passed);
println!("Failed: {}", report.summary.failed);
println!("Pass Rate: {:.1}%", report.summary.pass_rate * 100.0);
// Detailed failures
for result in report.failures() {
println!("Failed: {}", result.eval_id);
for failure in &result.failures {
println!(" - {}: {} (expected: {}, actual: {})",
failure.criterion,
failure.message,
failure.expected,
failure.actual
);
}
}
// Export to JSON for CI/CD
let json = report.to_json()?;
std::fs::write("eval_results.json", json)?;
التقييم الدفعي
التقييم المتوازي
قيم حالات اختبار متعددة بالتوازي:
let results = evaluator
.evaluate_cases_parallel(agent, &cases, 4) // 4 concurrent evaluations
.await;
تقييم الدليل
قم بتقييم جميع ملفات الاختبار في دليل:
let reports = evaluator
.evaluate_directory(agent, "tests/eval_cases")
.await?;
for (file, report) in reports {
println!("{}: {} passed, {} failed",
file,
report.summary.passed,
report.summary.failed
);
}
التكامل مع cargo test
استخدم التقييم في اختبارات Rust القياسية:
#[tokio::test]
async fn test_weather_agent() {
let agent = create_weather_agent().unwrap();
let evaluator = Evaluator::new(EvaluationConfig::with_criteria(
EvaluationCriteria::exact_tools()
));
let report = evaluator
.evaluate_file(agent, "tests/weather_agent.test.json")
.await
.unwrap();
assert!(report.all_passed(), "{}", report.format_summary());
}
أمثلة
استخدم مستوى الميزة القياسي للتقييم APIs:
cargo check -p adk-rust --no-default-features --features standard
تتوفر أمثلة التقييم القابلة للتشغيل في ADK-Rust Playground المضمّن في هذا الموقع.
ميزات متقدمة
تُضفي الإمكانيات التالية adk-eval على قدم المساواة مع أطر العمل مثل Braintrust، LangSmith، و Inspect AI. وهي إضافية إلى API الحالي ومقيدة بالميزات حيث تُدخل تبعيات جديدة.
مُحكّم مهيكل LLM
يُصدر أحكامًا مُحددة النوع (نجاح/فشل/جزئي) مع درجات ومنطق عبر function-calling أو JSON احتياطي:
use adk_eval::{StructuredJudge, StructuredJudgeConfig};
let judge = StructuredJudge::new(model.clone());
let verdict = judge.judge(
"The capital of France is Paris.",
"Paris is the capital of France.",
"factual_accuracy"
).await?;
println!("Score: {:.2}, Verdict: {:?}", verdict.score, verdict.verdict);
println!("Reasoning: {}", verdict.reasoning);
يحاول المُحكّم function-calling (response schema) أولاً، ثم يعود إلى المطالبة بـ JSON باستخدام محلل متساهل يتعامل مع JSON الخام، و markdown fences، و JSON المضمنة في النثر.
تتبع التكلفة والكمون
تتبع استخدام الرمز المميز وحساب التكاليف المقدرة بالدولار لكل تقييم:
use adk_eval::{CostTracker, CostMetrics};
let tracker = CostTracker::new(); // Uses default pricing tables
// Compute cost for a known model
let cost = tracker.compute_cost("gpt-4o", 2000, 800);
// → Some(0.013)
// Extract metrics from event streams
let metrics = tracker.extract_metrics(&events, duration);
println!("Tokens: {}, Latency: {}ms", metrics.total_tokens, metrics.latency_ms);
تحليل تتبع التنفيذ
اكتشاف استدعاءات الأدوات المتكررة، وحلقات التنفيذ، وحساب درجات الكفاءة:
use adk_eval::{TraceAnalyzer, TraceAnalysis};
let analyzer = TraceAnalyzer::new();
let analysis = analyzer.analyze(&events);
println!("Efficiency: {:.1}%", analysis.efficiency_score * 100.0);
for diag in &analysis.diagnostics {
println!(" [{:?}] {}", diag.pattern_type, diag.description);
}
خطوط أساس الانحدار
احفظ مقاييس التقييم كخطوط أساس واكتشف تراجعات الجودة:
use adk_eval::BaselineStore;
let store = BaselineStore::new(".eval-baseline.json");
// Save current metrics
store.save("my_eval_set", &metrics)?;
// On next run, check for regressions
let regressions = store.check_regressions(¤t_metrics, 0.05)?;
if !regressions.is_empty() {
for reg in ®ressions {
println!("REGRESSION: {} dropped from {:.3} to {:.3}",
reg.metric_name, reg.baseline_value, reg.current_value);
}
}
مخرجات CI (JUnit XML)
أنشئ JUnit XML لتكامل CI الأصلي (GitHub Actions, Jenkins, GitLab CI):
use adk_eval::JunitReporter; // requires `ci-helpers` feature
let xml = JunitReporter::generate(&report, "my_eval_suite")?;
std::fs::write("test-results.xml", xml)?;
سير عمل التعليقات التوضيحية البشرية
تصدير الحالات للمراجعة البشرية واستيراد الأحكام مرة أخرى:
use adk_eval::AnnotationStore;
// Export cases for annotation
AnnotationStore::export(&cases, &results, "review.jsonl")?;
// After human review, import back
let (records, warnings) = AnnotationStore::import("review.jsonl", &valid_ids)?;
مقارنة وكيل A/B
قارن وكيلين باستخدام اختبار الأهمية الإحصائية:
use adk_eval::{AbComparator, ab_comparator::wilcoxon_signed_rank};
// Requires `statistics` feature
let comparator = AbComparator::new(evaluator);
let report = comparator.compare(agent_a, agent_b, &eval_cases).await?;
for cmp in &report.criteria_comparisons {
println!("{}: A={:.3} B={:.3} p={:.4} significant={}",
cmp.criterion, cmp.agent_a_mean, cmp.agent_b_mean,
cmp.p_value, cmp.significant);
}
حالات الاختبار التي تم إنشاؤها تلقائيًا
إنشاء حالات تقييم من الأوصاف (عبر LLM) أو سجلات أحداث الإنتاج:
use adk_eval::{TestGenerator, GeneratorConfig};
let generator = TestGenerator::with_config(model, GeneratorConfig {
cases_per_description: 5,
include_tool_expectations: true,
});
// From natural language
let cases = generator.generate_from_description(
"A weather assistant that looks up forecasts by city"
).await?;
// From production events (no LLM needed)
let cases = generator.generate_from_events(&production_events)?;
مقاييس المحادثات متعددة الأدوار
تقييم المحادثات الممتدة على أربعة أبعاد:
use adk_eval::{ConversationScorer, ConversationScorerConfig};
let scorer = ConversationScorer::new(judge);
let metrics = scorer.score(&conversation, "Help user plan a trip").await?;
println!("Context retention: {:.2}", metrics.context_retention);
println!("Goal completion: {:.2}", metrics.goal_completion);
println!("Coherence: {:.2}", metrics.coherence);
println!("Topic drift: {:.2}", metrics.topic_drift);
التشابه الدلالي القائم على التضمين
قياس الحفاظ على المعنى باستخدام تضمينات المتجهات (يتطلب ميزة embedding):
use adk_eval::EmbeddingScorer;
let scorer = EmbeddingScorer::new(embedding_provider);
let score = scorer.score("expected text", "actual text").await?;
// Returns 0.0–1.0 cosine similarity
علامات الميزات
| الميزة | الاعتمادية | القدرة |
|---|---|---|
embedding | adk-memory | التشابه الدلالي القائم على التضمين |
ci-helpers | quick-xml | إنشاء تقرير JUnit XML |
statistics | statrs | اختبار ويلكوكسون للرتب الموقعة لمقارنة A/B |
جميع الميزات الأخرى (structured judge, cost tracker, trace analyzer, baselines, annotations, test generator, conversation scorer) تعمل بدون أي علامات ميزات إضافية.
CLI التكامل
قم بتشغيل التقييمات من سطر الأوامر عبر cargo adk eval:
# Basic evaluation
cargo adk eval tests/my_agent.test.json
# Save baseline
cargo adk eval tests/ --save-baseline
# Check for regressions
cargo adk eval tests/ --check-regression --tolerance 0.05
# JUnit XML output for CI
cargo adk eval tests/ --format junit --output results.xml
# JSON output
cargo adk eval tests/ --format json
# Parallel execution
cargo adk eval tests/ --concurrency 4
رموز الخروج:
0— اجتازت جميع التقييمات، لا توجد تراجعات1— تم اكتشاف تراجعات (عندما يكون--check-regressionمُعيّنًا)
أفضل الممارسات
- ابدأ ببساطة: ابدأ بالتحقق من المسار قبل إضافة الفحوصات الدلالية
- استخدم حالات تمثيلية: يجب أن تغطي ملفات الاختبار الحالات الهامشية والسيناريوهات الشائعة
- معايرة العتبات: ابدأ بعتبات متساهلة وشددها مع تحسن الوكيل
- دمج المعايير: استخدم معايير متعددة للتقييم الشامل
- إصدار ملفات الاختبار: احتفظ بملفات الاختبار في نظام التحكم بالإصدار جنبًا إلى جنب مع كود الوكيل
- تكامل CI/CD: تشغيل التقييمات في CI لاكتشاف الانحدارات
- حفظ الخطوط الأساسية: استخدم
--save-baselineبعد تحديد معيار الجودة، ثم--check-regressionفي CI - استخدم المحكمين المنظمين: فضل
StructuredJudgeعلى المحكم LLM العادي للحصول على نتائج قابلة للتحليل آليًا - تتبع التكاليف: قم بتمكين
CostTrackerلمراقبة تراجعات الكفاءة جنبًا إلى جنب مع الجودة - اكتشاف الحلقات: قم بتمكين
TraceAnalyzerللكشف عن الوكلاء العالقين في أنماط متكررة
مثال
يتوفر مثال عملي كامل يوضح جميع الميزات:
cargo run --manifest-path examples/eval_showcase/Cargo.toml
انظر examples/eval_showcase/ للاطلاع على الكود المصدري.
السابق: ← A2A بروتوكول | التالي: التحكم في الوصول →