Как оценивать AI-агентов

Что измерять: точность кода, скорость, стоимость на задачу, качество PR. Практическая система оценки с lm-eval-harness.

📊 Средний⏱ 10 мин

# 1. МЕТРИКИ ДЛЯ АГЕНТОВ

# Ключевые метрики для оценки AI-агентов
# 1. pass@k — вероятность, что хотя бы 1 из k генераций пройдёт тесты
# 2. Latency (P50/P95/P99) — время ответа агента
# 3. Cost per task — стоимость токенов на одну задачу
# 4. Success Rate — доля успешно выполненных задач
# 5. Tool Accuracy — правильно ли агент выбирает инструменты

import time
from dataclasses import dataclass

@dataclass
class EvalMetrics:
    total_tasks: int      = 0
    passed: int          = 0
    total_latency: float = 0.0
    total_cost: float   = 0.0
    total_tokens: int   = 0

    @property
    def accuracy(self):
        return self.passed / self.total_tasks if self.total_tasks else 0

    @property
    def avg_latency(self):
        return self.total_latency / self.total_tasks if self.total_tasks else 0

# 2. LM-EVAL-HARNESS — УСТАНОВКА И ЗАПУСК

git clone https://github.com/EleutherAI/lm-evaluation-harness
cd lm-evaluation-harness
pip install -e .

# Бенчмарк MMLU (знания в 57 доменах)
python -m lm_eval --model hf --model_args pretrained=meta-llama/Llama-3-8B --tasks mmlu --batch_size 8

# GSM8K (математические задачи)
python -m lm_eval --model openai-completions --model_args model=gpt-4 --tasks gsm8k

# HumanEval (генерация кода)
python -m lm_eval --model hf --model_args pretrained=deepseek-ai/deepseek-coder-6.7b --tasks humaneval

# 3. КАСТОМНЫЙ EVAL ДЛЯ АГЕНТА

# test_agent_eval.py — pytest-based eval для агента
import pytest
from my_agent import CodeAgent

# Датасет: (задача, эталонный ответ, критерий проверки)
TASKS = [
    {"task": "Напиши функцию fibonacci(n)",
     "check": lambda out: "def fibonacci" in out and "return" in out},
    {"task": "Создай Dockerfile для Python приложения",
     "check": lambda out: "FROM" in out and "python" in out.lower()},
    {"task": "SQL запрос: топ-5 пользователей по заказам",
     "check": lambda out: "SELECT" in out and "GROUP BY" in out and "ORDER BY" in out},
]

@pytest.mark.parametrize("case", TASKS)
def test_agent_task(case):
    agent = CodeAgent(model="gpt-4")
    result = agent.run(case["task"])
    assert case["check"](result), f"❌ Failed: {case['task'][:50]}..."

# Запуск: pytest test_agent_eval.py -v --tb=short

# 4. ТРЕКИНГ ЭКСПЕРИМЕНТОВ

pip install wandb

import wandb

wandb.init(project="agent-eval", name="gpt4-baseline")

def evaluate_agent(agent, tasks):
    metrics = EvalMetrics()
    for task in tasks:
        start = time.time()
        result = agent.run(task)
        latency = time.time() - start
        passed = task.verify(result)
        metrics.total_tasks += 1
        metrics.passed += passed
        metrics.total_latency += latency
        metrics.total_cost += result.cost
        wandb.log({"task_latency": latency, "task_passed": passed})
    wandb.log({"accuracy": metrics.accuracy,
                "avg_latency": metrics.avg_latency,
                "total_cost": metrics.total_cost})
    return metrics

# 5. A/B ТЕСТИРОВАНИЕ ПРОМПТОВ

import numpy as np
from scipy import stats

def ab_test_prompts(prompt_a, prompt_b, tasks, n_trials=50):
    """Сравниваем два промпта на N задачах со статистической значимостью."""
    scores_a = []
    scores_b = []
    for task in tasks[:n_trials]:
        scores_a.append(run_with_prompt(prompt_a, task))
        scores_b.append(run_with_prompt(prompt_b, task))

    # T-test для парных выборок
    t_stat, p_value = stats.ttest_rel(scores_a, scores_b)
    print(f"Prompt A mean: {np.mean(scores_a):.3f}")
    print(f"Prompt B mean: {np.mean(scores_b):.3f}")
    print(f"p-value: {p_value:.4f} {'✅ Significant!' if p_value < 0.05 else '❌ Not significant'}")
    return p_value < 0.05

# 6. ELO-РЕЙТИНГ ДЛЯ АГЕНТОВ

class EloRating:
    """Рейтинговая система как в шахматах для попарного сравнения агентов."""
    def __init__(self, k=32):
        self.ratings = {}
        self.k = k

    def expected(self, r_a, r_b):
        return 1 / (1 + 10 ** ((r_b - r_a) / 400))

    def update(self, a, b, score_a):
        """score_a: 1 если A победил, 0 если B, 0.5 ничья."""
        if a not in self.ratings: self.ratings[a] = 1500
        if b not in self.ratings: self.ratings[b] = 1500
        ea = self.expected(self.ratings[a], self.ratings[b])
        self.ratings[a] += self.k * (score_a - ea)
        self.ratings[b] += self.k * ((1-score_a) - (1-ea))

# Пример: сравниваем GPT-4 и Claude на 10 задачах
elo = EloRating()
elo.update("GPT-4", "Claude", 1)   # GPT-4 лучше
elo.update("GPT-4", "Claude", 1)   # GPT-4 лучше
elo.update("GPT-4", "Claude", 0)   # Claude лучше
print(elo.ratings)  # {'GPT-4': 1532.0, 'Claude': 1468.0}

🔗 Полезные ссылки

📖 lm-evaluation-harness📖 Weights & Biases📖 Chatbot Arena (LMSYS)📖 HumanEval Paper