Среды, бенчмарки и генерация данных

Hermes Agent включает полноценный фреймворк окружений, который соединяет его возможности вызова инструментов с Atropos — фреймворком для RL-обучения. Это обеспечивает три рабочих процесса:

  1. RL-обучение — обучение языковых моделей на multi-turn агентных задачах с GRPO

  2. Бенчмарки — оценка моделей на стандартизированных агентных бенчмарках

  3. Генерация данных — создание SFT-данных для обучения из агентных прогонов

Все три используют одну и ту же основу: класс окружения (environment), который определяет задачи, запускает агентный цикл и оценивает результат.

info Репозиторий окружений vs инструменты RL-обучения Документируемый здесь фреймворк окружений на Python находится в директории environments/ репозитория и представляет собой API уровня реализации для интеграции Hermes/Atropos. Это отделено от пользовательских инструментов rl_*, которые работают как оркестрационная обёртка для удалённых рабочих процессов RL-обучения.

tip Быстрые ссылки

Архитектура

Система окружений построена на трёхуровневой цепочке наследования:

classDiagram
    class BaseEnv {
      Server management
      Worker scheduling
      Wandb logging
      CLI: serve / process / evaluate
    }

    class HermesAgentBaseEnv {
      Terminal backend configuration
      Tool resolution
      Agent loop engine
      ToolContext access
    }

    class TerminalTestEnv {
      Stack testing
    }

    class HermesSweEnv {
      SWE training
    }

    class TerminalBench2EvalEnv {
      Benchmark evaluation
    }

    class TBLiteEvalEnv {
      Fast benchmark
    }

    class YCBenchEvalEnv {
      Long-horizon benchmark
    }

    BaseEnv <|-- HermesAgentBaseEnv
    HermesAgentBaseEnv <|-- TerminalTestEnv
    HermesAgentBaseEnv <|-- HermesSweEnv
    HermesAgentBaseEnv <|-- TerminalBench2EvalEnv
    TerminalBench2EvalEnv <|-- TBLiteEvalEnv
    TerminalBench2EvalEnv <|-- YCBenchEvalEnv

BaseEnv (Atropos)

Фундамент из atroposlib. Предоставляет:

HermesAgentBaseEnv

Уровень hermes-agent (environments/hermes_base_env.py). Добавляет:

Конкретные окружения

Ваше окружение наследуется от HermesAgentBaseEnv и реализует пять методов:

Метод Назначение
setup() Загрузка датасета, инициализация состояния
get_next_item() Возвращает следующий элемент для прогона
format_prompt(item) Преобразует элемент в сообщение пользователя
compute_reward(item, result, ctx) Оценивает прогон (0.0–1.0)
evaluate() Логика периодической оценки

Основные компоненты

Агентный цикл

HermesAgentLoop (environments/agent_loop.py) — это переиспользуемый multi-turn агентный движок. Он выполняет тот же шаблон вызова инструментов, что и основной цикл hermes-agent:

  1. Отправляет сообщения + схемы инструментов в API через server.chat_completion()

  2. Если ответ содержит tool_calls, выполняет каждый через handle_function_call()

  3. Добавляет результаты вызова инструментов в разговор, возвращается к шагу 1

  4. Если tool_calls нет, агент завершает работу

Вызовы инструментов выполняются в пуле потоков (ThreadPoolExecutor(128)), чтобы async-бэкенды (Modal, Docker) не блокировались внутри event loop Atropos.

Возвращает AgentResult:

@dataclass
class AgentResult:
    messages: List[Dict[str, Any]]       # Полная история разговора
    turns_used: int                       # Количество сделанных вызовов LLM
    finished_naturally: bool              # True, если модель остановилась сама
    reasoning_per_turn: List[Optional[str]]  # Извлечённое содержимое рассуждений
    tool_errors: List[ToolError]          # Ошибки, возникшие при выполнении инструментов
    managed_state: Optional[Dict]         # Состояние VLLM ManagedServer (Фаза 2)

Контекст инструментов

ToolContext (environments/tool_context.py) даёт функциям вознаграждения прямой доступ к той же изолированной среде, которую модель использовала во время своего прогона. Область видимости task_id гарантирует сохранение всего состояния (файлы, процессы, вкладки браузера).

async def compute_reward(self, item, result, ctx: ToolContext):
    # Запуск тестов в терминальной изолированной среде модели
    test = ctx.terminal("pytest -v")
    if test["exit_code"] == 0:
        return 1.0

    # Проверка, был ли создан файл
    content = ctx.read_file("/workspace/solution.py")
    if content.get("content"):
        return 0.5

    # Скачивание файлов для локальной проверки
    ctx.download_file("/remote/output.bin", "/local/output.bin")
    return 0.0

Доступные методы:

Категория Методы
Терминал terminal(command, timeout)
Файлы read_file(path), write_file(path, content), search(query, path)
Передача upload_file(), upload_dir(), download_file(), download_dir()
Веб web_search(query), web_extract(urls)
Браузер browser_navigate(url), browser_snapshot()
Общее call_tool(name, args) — запасной выход для любого инструмента hermes-agent
Очистка cleanup() — освобождение всех ресурсов

Парсеры вызовов инструментов

Для Фазы 2 (VLLM ManagedServer) сервер возвращает сырой текст без структурированных вызовов инструментов. Клиентские парсеры в environments/tool_call_parsers/ извлекают tool_calls из сырого вывода:

from environments.tool_call_parsers import get_parser

parser = get_parser("hermes")  # или "mistral", "llama3_json", "qwen", "deepseek_v3", etc.
content, tool_calls = parser.parse(raw_model_output)

Доступные парсеры: hermes, mistral, llama3_json, llama4_json, qwen, qwen3_coder, deepseek_v3, deepseek_v3_1 (алиас deepseek_v31), kimi_k2, longcat, glm45, glm47.

В Фазе 1 (тип сервера OpenAI) парсеры не нужны — сервер обрабатывает парсинг вызовов инструментов нативно.

Доступные бенчмарки

TerminalBench2

89 сложных терминальных задач с изолированными Docker-окружениями для каждой задачи.

Что тестирует Способность к одношаговому программированию / администрированию системы
Оценка Бинарный провал/успех (проверка через тестовый набор)
Изолированная среда Modal cloud sandboxes (Docker-образы для каждой задачи)
Инструменты terminal + file
Задачи 89 задач из нескольких категорий
Стоимость ~$50–200 за полный eval (параллельное выполнение)
Время ~2–4 часа
python environments/benchmarks/terminalbench_2/terminalbench2_env.py evaluate \\
    --config environments/benchmarks/terminalbench_2/default.yaml

# Запуск конкретных задач
python environments/benchmarks/terminalbench_2/terminalbench2_env.py evaluate \\
    --config environments/benchmarks/terminalbench_2/default.yaml \\
    --env.task_filter fix-git,git-multibranch

Датасет: NousResearch/terminal-bench-2 на HuggingFace.

TBLite (OpenThoughts Terminal Bench Lite)

100 задач с калибровкой по сложности — более быстрый прокси для TerminalBench2.

Что тестирует То же, что и TB2 (программирование/администрирование), калиброванные уровни сложности
Оценка Бинарный провал/успех
Изолированная среда Modal cloud sandboxes
Инструменты terminal + file
Задачи 100 задач: Easy (40), Medium (26), Hard (26), Extreme (8)
Корреляция r=0.911 с полным TB2
Скорость в 2.6–8× быстрее, чем TB2
python environments/benchmarks/tblite/tblite_env.py evaluate \\
    --config environments/benchmarks/tblite/default.yaml

TBLite — это тонкий подкласс TerminalBench2, отличающийся только датасетом и таймаутами. Создан командой OpenThoughts Agent (Snorkel AI + Bespoke Labs). Датасет: NousResearch/openthoughts-tblite.

YC-Bench

Долгосрочный стратегический бенчмарк — агент играет роль CEO AI-стартапа.

Что тестирует Многошаговую стратегическую согласованность на сотнях шагов
Оценка Композитная: 0.5 × выживание + 0.5 × нормализованные_средства
Изолированная среда Локальный терминал (Modal не требуется)
Инструменты Только terminal
Прогоны 9 по умолчанию (3 пресета × 3 сида), последовательно
Стоимость ~$50–200 за полный eval
Время ~3–6 часов
# Установка yc-bench (опциональная зависимость)
pip install "hermes-agent[yc-bench]"

# Запуск оценки
bash environments/benchmarks/yc_bench/run_eval.sh

# Или напрямую
python environments/benchmarks/yc_bench/yc_bench_env.py evaluate \\
    --config environments/benchmarks/yc_bench/default.yaml

# Быстрый тест с одним пресетом
python environments/benchmarks/yc_bench/yc_bench_env.py evaluate \\
    --config environments/benchmarks/yc_bench/default.yaml \\
    --env.presets '["fast_test"]' --env.seeds '[1]'

YC-Bench использует collinear-ai/yc-bench — детерминированную симуляцию с 4 доменами навыков (research, inference, data_environment, training), системой престижа, управлением сотрудниками и финансовым давлением. В отличие от бинарной оценки TB2 для каждой задачи, YC-Bench измеряет, способен ли агент поддерживать согласованную стратегию на протяжении сотен взаимосвязанных решений.

Окружения для обучения

TerminalTestEnv

Минимальное самодостаточное окружение со встроенными задачами (без внешнего датасета). Используется для сквозной проверки всего стека. Каждая задача просит модель создать файл по известному пути; верификатор проверяет содержимое.

# Режим обработки (сохраняет прогоны в JSONL, сервер обучения не требуется)
python environments/terminal_test_env/terminal_test_env.py process \\
    --env.data_path_to_save_groups terminal_test_output.jsonl

# Режим сервера (подключается к Atropos API для RL-обучения)
python environments/terminal_test_env/terminal_test_env.py serve

HermesSweEnv

Окружение для обучения в стиле SWE-bench. Модель получает задачу по программированию, использует инструменты terminal + file + web для её решения, а функция вознаграждения запускает тесты в той же Modal-изолированной среде.

python environments/hermes_swe_env/hermes_swe_env.py serve \\
    --openai.model_name YourModel \\
    --env.dataset_name bigcode/humanevalpack \\
    --env.terminal_backend modal

Запуск окружений

Каждое окружение — это отдельный Python-скрипт с тремя CLI-подкомандами:

evaluate — Запуск бенчмарка

Для окружений, предназначенных только для оценки (бенчмарки). Запускает все элементы, вычисляет метрики, логирует в wandb.

python environments/benchmarks/tblite/tblite_env.py evaluate \\
    --config environments/benchmarks/tblite/default.yaml \\
    --openai.model_name anthropic/claude-sonnet-4.6

Сервер обучения или run-api не требуются. Окружение справляется со всем самостоятельно.

process — Генерация SFT-данных

Запускает прогоны и сохраняет оценённые траектории в JSONL. Полезно для генерации обучающих данных без полного RL-цикла.

python environments/terminal_test_env/terminal_test_env.py process \\
    --env.data_path_to_save_groups output.jsonl \\
    --openai.model_name anthropic/claude-sonnet-4.6

Формат вывода: каждая строка — это оценённая траектория с полной историей разговора, вознаграждением и метаданными.

serve — Подключение к Atropos для RL-обучения

Подключает окружение к запущенному серверу Atropos API (run-api). Используется во время живого RL-обучения.

# Терминал 1: Запуск Atropos API
run-api

# Терминал 2: Запуск окружения
python environments/hermes_swe_env/hermes_swe_env.py serve \\
    --openai.model_name YourModel

Окружение получает элементы от Atropos, запускает агентные прогоны, вычисляет вознаграждения и отправляет оценённые траектории обратно для обучения.

Двухфазная работа

Фаза 1: OpenAI Server (Eval / SFT)

Использует server.chat_completion() с параметром tools=. Сервер (VLLM, SGLang, OpenRouter, OpenAI) обрабатывает парсинг вызовов инструментов нативно. Возвращает объекты ChatCompletion со структурированными tool_calls.

Фаза 2: VLLM ManagedServer (Полноценное RL)

Использует ManagedServer для точных ID токенов + logprobs через /generate. Клиентский парсер вызовов инструментов восстанавливает структурированные tool_calls из сырого вывода.

Создание окружений

Окружение для обучения

from environments.hermes_base_env import HermesAgentBaseEnv, HermesAgentEnvConfig
from atroposlib.envs.server_handling.server_manager import APIServerConfig

class MyEnvConfig(HermesAgentEnvConfig):
    my_custom_field: str = "default_value"

class MyEnv(HermesAgentBaseEnv):
    name = "my-env"
    env_config_cls = MyEnvConfig

    @classmethod
    def config_init(cls):
        env_config = MyEnvConfig(
            enabled_toolsets=["terminal", "file"],
            terminal_backend="modal",
            max_agent_turns=30,
        )
        server_configs = [APIServerConfig(
            base_url="https://openrouter.ai/api/v1",
            model_name="anthropic/claude-sonnet-4.6",
            server_type="openai",
        )]
        return env_config, server_configs

    async def setup(self):
        from datasets import load_dataset
        self.dataset = list(load_dataset("my-dataset", split="train"))
        self.iter = 0

    async def get_next_item(self):
        item = self.dataset[self.iter % len(self.dataset)]
        self.iter += 1
        return item

    def format_prompt(self, item):
        return item["instruction"]

    async def compute_reward(self, item, result, ctx):
        # ctx предоставляет полный доступ к инструментам в изолированной среде прогона
        test = ctx.terminal("pytest -v")
        return 1.0 if test["exit_code"] == 0 else 0.0

    async def evaluate(self, *args, **kwargs):
        # Периодическая оценка во время обучения
        pass

if __name__ == "__main__":
    MyEnv.cli()

Бенчмарк только для оценки

Для бенчмарков следуйте шаблону, используемому TerminalBench2, TBLite и YC-Bench:

  1. Создайте в environments/benchmarks/your-benchmark/

  2. Установите конфиг только для оценки: eval_handling=STOP_TRAIN, steps_per_eval=1, total_steps=1

  3. Заглушите методы обучения: collect_trajectories() возвращает (None, []), score() возвращает None

  4. Реализуйте rollout_and_score_eval(eval_item) — агентный цикл + оценка для каждого элемента

  5. Реализуйте evaluate() — оркестрирует все прогоны, вычисляет агрегированные метрики

  6. Добавьте потоковый JSONL для устойчивого к сбоям сохранения результатов

  7. Добавьте очистку: обработка KeyboardInterrupt, cleanup_all_environments(), _tool_executor.shutdown()

  8. Запускайте с подкомандой evaluate

Смотрите environments/benchmarks/yc_bench/yc_bench_env.py для чистой, хорошо документированной эталонной реализации.

Справочник по конфигурации

Поля HermesAgentEnvConfig

Поле Тип По умолчанию Описание
enabled_toolsets List[str] None (все) Какие наборы инструментов hermes включить
disabled_toolsets List[str] None Наборы инструментов для исключения
distribution str None Название вероятностного распределения наборов инструментов
max_agent_turns int 30 Максимальное количество вызовов LLM на один прогон
agent_temperature float 1.0 Температура семплирования
system_prompt str None Системное сообщение для агента
terminal_backend str "local" local, docker, modal, daytona, ssh, singularity
terminal_timeout int 120 Секунд на одну терминальную команду
terminal_lifetime int 3600 Максимальное время жизни изолированной среды
dataset_name str None Идентификатор датасета на HuggingFace
tool_pool_size int 128 Размер пула потоков для выполнения инструментов
tool_call_parser str "hermes" Парсер для сырого вывода Фазы 2
extra_body Dict None Дополнительные параметры для OpenAI API (например, предпочтения провайдера OpenRouter)
eval_handling Enum STOP_TRAIN STOP_TRAIN, LIMIT_TRAIN, NONE

YAML-конфигурация

Окружения можно настраивать через YAML-файлы, передаваемые с --config:

env:
  enabled_toolsets: ["terminal", "file"]
  max_agent_turns: 60
  max_token_length: 32000
  agent_temperature: 0.8
  terminal_backend: "modal"
  terminal_timeout: 300
  dataset_name: "NousResearch/terminal-bench-2"
  tokenizer_name: "NousResearch/Hermes-3-Llama-3.1-8B"
  use_wandb: true
  wandb_name: "my-benchmark"

openai:
  base_url: "https://openrouter.ai/api/v1"
  model_name: "anthropic/claude-sonnet-4.6"
  server_type: "openai"
  health_check: false

Значения YAML переопределяют значения по умолчанию из config_init(). Аргументы CLI переопределяют значения YAML:

python my_env.py evaluate \\
    --config my_config.yaml \\
    --openai.model_name anthropic/claude-opus-4.6  # переопределяет YAML

Предварительные требования

Для всех окружений

Для бенчмарков в Modal-изолированной среде (TB2, TBLite)

Для YC-Bench

Для RL-обучения

Смотрите RL-обучение для рабочего процесса RL на основе агента.

Структура директорий

environments/
├── hermes_base_env.py          # Абстрактный базовый класс (HermesAgentBaseEnv)
├── agent_loop.py               # Multi-turn агентный движок (HermesAgentLoop)
├── tool_context.py             # Доступ к инструментам для функций вознаграждения
├── patches.py                  # Async-безопасные патчи для Model бэкенда

├── tool_call_parsers/          # Клиентские парсеры для Фазы 2
   ├── hermes_parser.py        # Формат Hermes/ChatML <tool_call>
   ├── mistral_parser.py       # Формат Mistral [TOOL_CALLS]
   ├── llama_parser.py         # Llama 3 JSON tool calling
   ├── qwen_parser.py          # Формат Qwen
   ├── deepseek_v3_parser.py   # Формат DeepSeek V3
   └── ...                     # + kimi_k2, longcat, glm45/47, и др.

├── terminal_test_env/          # Валидация стека (встроенные задачи)
├── hermes_swe_env/             # Окружение для обучения в стиле SWE-bench

└── benchmarks/                 # Оценочные бенчмарки
    ├── terminalbench_2/        # 89 терминальных задач, Modal sandboxes
    ├── tblite/                 # 100 калиброванных задач (быстрый прокси TB2)
    └── yc_bench/               # Долгосрочный стратегический бенчмарк