智能体评估

adk-eval crate 提供了全面的工具,用于测试和验证 Agent 行为。与传统的软件测试不同,Agent 评估必须考虑到 LLM 的概率性质,同时仍然提供有意义的质量信号。

概述

ADK-Rust 中的 Agent 评估支持多种评估策略:

  • 轨迹评估:验证 Agent 以正确的顺序调用预期的 Tool
  • 响应相似度:使用各种算法(Jaccard、Levenshtein、ROUGE)比较 Agent 响应
  • 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(())
}

测试文件格式

测试用例在带有 .test.json 扩展名的 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"}
              }
            ]
          }
        }
      ]
    }
  ]
}

评估标准

工具轨迹匹配

验证 Agent 以正确的顺序调用预期的 Tool:

let criteria = EvaluationCriteria {
    tool_trajectory_score: Some(1.0),  // 要求 100% 匹配
    tool_trajectory_config: Some(ToolTrajectoryConfig {
        strict_order: true,   // Tool 必须以精确的顺序调用
        strict_args: false,   // 允许 Tool 调用中包含额外的参数
    }),
    ..Default::default()
};

选项:

  • strict_order:要求精确的序列匹配
  • strict_args:要求精确的参数匹配(不允许额外参数)
  • 可配置阈值的部分匹配

响应相似度

使用各种算法比较响应文本:

let criteria = EvaluationCriteria {
    response_similarity: Some(0.8),  // 要求 80% 的相似度
    response_match_config: Some(ResponseMatchConfig {
        algorithm: SimilarityAlgorithm::Jaccard,
        ignore_case: true,
        normalize: true,
        ..Default::default()
    }),
    ..Default::default()
};

可用算法:

Algorithm描述
Exact精确字符串匹配
Contains子字符串检查
Levenshtein编辑距离
Jaccard词语重叠(默认)
Rouge1一元语法重叠
Rouge2二元语法重叠
RougeL最长公共子序列

LLM 判定的语义匹配

使用 LLM 评估语义等效性:

use adk_eval::{Evaluator, EvaluationConfig, EvaluationCriteria, LlmJudge};
use adk_model::GeminiModel;

// 使用 LLM 判定器创建评估器
let judge_model = Arc::new(GeminiModel::new(&api_key, "gemini-2.0-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("准确性", "响应事实正确")
            .with_weight(0.5),
        Rubric::new("帮助性", "响应满足用户需求")
            .with_weight(0.3),
        Rubric::new("清晰度", "响应清晰且组织良好")
            .with_weight(0.2),
    ]);

每个评分标准由 LLM 判定器进行 0-1 评分,然后根据权重进行组合。

安全性和幻觉检测

检查响应是否存在安全问题和幻觉:

let criteria = EvaluationCriteria {
    safety_score: Some(0.95),        // 要求高安全性得分
    hallucination_score: Some(0.9),  // 要求低幻觉率
    ..Default::default()
};

结果报告

评估报告提供详细结果:

let report = evaluator.evaluate_file(agent, "tests/agent.test.json").await?;

// 汇总统计
println!("总计:{}", report.summary.total);
println!("通过:{}", report.summary.passed);
println!("失败:{}", report.summary.failed);
println!("通过率:{:.1}%", report.summary.pass_rate * 100.0);

// 详细失败信息
for result in report.failures() {
    println!("失败:{}", result.eval_id);
    for failure in &result.failures {
        println!("  - {}: {}(预期:{},实际:{})",
            failure.criterion,
            failure.message,
            failure.expected,
            failure.actual
        );
    }
}

// 导出为 JSON 用于 CI/CD
let json = report.to_json()?;
std::fs::write("eval_results.json", json)?;

批量评估

并行评估

并发评估多个测试用例:

let results = evaluator
    .evaluate_cases_parallel(agent, &cases, 4)  // 4 次并发评估
    .await;

目录评估

评估目录中的所有测试文件:

let reports = evaluator
    .evaluate_directory(agent, "tests/eval_cases")
    .await?;

for (file, report) in reports {
    println!("{}: {} 通过, {} 失败",
        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());
}

示例

# 基本评估
cargo run --example eval_basic

# 轨迹验证
cargo run --example eval_trajectory

# LLM 评判的语义匹配
cargo run --example eval_semantic

# 基于评分标准的评分
cargo run --example eval_rubric

# 响应相似度算法
cargo run --example eval_similarity

# 报告生成
cargo run --example eval_report

最佳实践

  1. 从简单开始:在添加语义检查之前,先从轨迹验证开始
  2. 使用具有代表性的用例:测试文件应涵盖边界情况和常见场景
  3. 校准阈值:从宽松的阈值开始,随着 Agent 改进而收紧
  4. 结合评估标准:使用多个评估标准进行全面评估
  5. 版本控制测试文件:将测试文件与 Agent 代码一起放入版本控制
  6. CI/CD 集成:在 CI 中运行评估以捕获回归

上一页: ← A2A Protocol | 下一页: Access Control →