Что измерять: точность кода, скорость, стоимость на задачу, качество PR. Практическая система оценки с lm-eval-harness.
# Ключевые метрики для оценки 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
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
# 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
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
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
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}