Бенчмарки и контроль качества

🔵 agent-os bench прогоняет агентов по сценариям end-to-end и пишет отчёт — так качество агентов проверяется автоматически, а не «на глаз».


16.1 Запуск

# против работающего сервера
agent-os bench --url https://HOST --max 5

# поднять собственный локальный сервер (нужен DEEPSEEK_API_KEY в .env)
agent-os bench --port 3001 --max 3

# конкретный агент
agent-os bench --url https://HOST --agent drom --max 5 --parallel 3

# сценарии по имени (подстрока; `a|b` = OR)
agent-os bench --url https://HOST --name "Camry|BMW" --max 10

# с LLM-судьёй качества и кодом возврата для CI
agent-os bench --url https://HOST --agent drom --judge --fail-on-error --out report.json

# 3 полных прогона с усреднением (борьба с шумом LLM/сети)
agent-os bench --url https://HOST --agent drom --repeats 3 --judge

Флаги: --url, --port (3001), --agent, --name, --max (0=все), --parallel (4), --timeout (90), --config (корень конфигов), --out (путь отчёта), --repeats (1), --judge, --judge-model, --fail-on-error. Форма — --flag value.

--repeats N прогоняет весь набор сценариев N раз и усредняет: ход считается пройденным только если прошёл во всех N прогонах (pass^N), а токены/стоимость/ время/judge — средние. Это убирает «качели» одиночных прогонов; в отчёте есть поле repeats.

Результат — bench_report_<timestamp>.json (или --out), со счётчиками ходов passed/failed, счётчиками сценариев scenarios_*, per-turn failures и полным текстом ответа в поле response. --fail-on-error даёт код возврата 1, если был хотя бы один провал.

16.2 Формат сценария

Сценарии в config/agents/<agent>/bench/scenarios.yaml:

name: "Drom Agent"
model: "drom-agent"

scenarios:
  - name: "Поиск Camry"
    turns:
      - user: "Найди Toyota Camry"
        assert:
          contains: [camry]
          min_links: 2
          valid_urls: true

Многоходовые сценарии

  - name: "Multi-turn: уточнение"
    turns:
      - user: "Первый вопрос"
        assert: { contains: [Слово], min_links: 2 }
      - user: "Уточнение"
        assert: { min_links: 1 }
      - user: "Финальное уточнение"
        assert: { valid_urls: true }

Типы проверок

Проверка Смысл
contains: [w1, w2] ответ должен содержать подстроки (без учёта регистра)
not_contains: [w1, w2] этих подстрок быть не должно
regex: ["..."] ответ должен соответствовать каждому regex
min_links: N минимум N markdown-ссылок [text](url)
min_urls: N минимум N URL (markdown-ссылки + голые http(s)://)
valid_urls: true все URL начинаются с http:// или https://
min_chars: N минимальная длина ответа
max_elapsed_ms: N потолок времени хода (скорость)
max_completion_tokens: N потолок токенов ответа (экономия)
max_cost_usd: X потолок стоимости хода

Скорость и экономию токенов задавайте явными потолками (max_elapsed_ms/max_completion_tokens/max_cost_usd), а не только судьёй.

16.3 Анализ результата

  1. Смотри консоль: ✓ (pass) / ✗ (fail).
  2. Читай bench_report_*.json: поля failures и error.
  3. Сравни два отчёта (diff) для поиска регрессий.

16.4 Хранилище запусков

Запуски пишутся в logs/bench.db и видны в админ-API:

Endpoint Описание
POST /v1/agents/:name/bench/run запустить бенчмарк шаблона
GET /v1/agents/:name/bench/runs история запусков шаблона
GET /v1/agents/:name/bench/runs/:id один запуск + его ходы (пока running — компактный статус; ?full=1 — полный)
GET /v1/bench/runs последние запуски по всем шаблонам
GET /v1/bench/catalog шаблоны с настроенными сценариями

Тело запуска (все поля необязательны): {"timeout_secs": 90, "parallel": 4, "judge": false, "judge_model": ""}. parallel задаёт одновременно выполняемые сценарии, judge включает LLM-оценку каждого успешного хода (средний балл — avg_judge_score). В админ-UI эти параметры доступны на вкладке «Бенчмарки».

Пока прогон идёт (status: running), GET .../runs/:id по умолчанию отдаёт компактный ответ (run, progress {done,total}, hint) без списка ходов — чтобы агент, который ждёт результат, не тянул весь список на каждом опросе. Полный список возвращается, когда status перестаёт быть running, либо по ?full=1. Агенту не нужно опрашивать чаще, чем раз в ~30 с — для этого есть инструмент wait_tool.

Если сервер остановили/перезапустили во время прогона, такой «сиротский» запуск при следующем старте помечается failed (finished_at + error: interrupted: server stopped before the run finished), а не висит в running.

16.5 Практики