Окружения, бенчмарки и генерация данных
Hermes Agent включает в себя полноценный каркас окружений, который включает в себя его возможности инструментов с фреймворком RL-обучения Atropos. Это позволяет реализовать три рабочих процесса:
- RL-обучение — обучение языковых моделей на многих клиентских агентских задачах с помощью GRPO.
- Бенчмарки — оценка моделей на стандартизированных агентских бенчмарках.
- Генерация данных — создание SFT-обучающих данных из развёртывания агента.
Все три основаны на одном и том же: класс окружения, который определяет задачу, запускает цикл агента и измеряет результат.:::информация Окружения репозитория vs инструменты RL-обучения
Фреймворк окружения на Python, описанный здесь, находится в каталоге environments/, репозиторий и представляет собой реализацию уровня API для руководителей Hermes/Atropos. Он отделён от инструментов rl_*, которые работают как оркестрационный слой для удаленных рабочих процессов RL-обучения.:::
💡 Tip
Быстрые ссылки - Хотите запустить тесты? Переходите к Доступные тесты - Хотите обучаться с RL? См. Инструменты RL-обучения для интерфейса, управляемого агентом, или Запуск окружений для ручного выполнения - Хотите создать новое окружение? См. Создание окруженийАрхитектура
Система окружения построек на трехуровневой цепочке наследия:
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 (Атропос)
Основа из атропослиб. Предоставляет:
- Управление сервером — подключение к API, совместимым с OpenAI (VLLM, SGLang, OpenRouter)
- Планирование рабочих процессов — координация параллельных разворотов.
- Интеграция с Wandb — логирование метрик и визуализация развёртывания
- CLI-интерфейс — три подкоманды: «обслуживать», «обрабатывать», «оценивать»
- Логирование eval — evaluate_log() сохраняет результаты в формате JSON + JSONL.
HermesAgentBaseEnv
Слой hermes-agent (environments/hermes_base_env.py). Добавляет:
- Настройка терминального бэкенда — задаёт TERMINAL_ENV для изолированного выполнения (local, Docker, Modal, Daytona, SSH, Singularity)
- Разрешение инструментов — _resolve_tools_for_group() вызывает get_tool_definitions() из hermes-agent для соответствующих инструментов схем в зависимости от включенных/отключенных наборов инструментов
- Цикл интеграции агента — collect_trajectory() запускает HermesAgentLoop и оценивает результат
- Двухфазная операция — Фаза 1 (сервер OpenAI) для eval/SFT, Фаза 2 (VLLM ManagedServer) для качественного RL с logprobs
- Патчи для асинхронной безопасности — мои патчи бэкенда Модальный для работы внутри цикла событий Atropos
Конкретные окружения
Окружение тела наследуется от HermesAgentBaseEnv и реализуется пятью методами:
| Метод | Назначение |
|---|---|
настройка() |
Загрузка набора данных, инициализация состояния |
get_next_item() |
Возвращает следующий элемент для развёртывания |
format_prompt(элемент) |
Преобразует элемент в сообщение пользователя |
compute_reward(предмет, результат, ctx) |
Оценивает развёртывание (0,0–1,0) |
оценить() |
Логика периодической оценки |
Основные компоненты
Цикл агента
HermesAgentLoop (environments/agent_loop.py) — это многократно повторяющийся многопользовательский движок-агента. Он выполняет тот же шаблон вызова инструментов, что и основной цикл hermes-agent:
- Отправляет сообщения + схемы инструментов в API через
server.chat_completion() - Если ответ содержит
tool_calls, каждый отправляется черезhandle_function_call() - Добавляет инструменты в разговор, возвращается к шагу 1.
- Если
tool_callsнет, агент завершён
Вызовы инструментов выполняются в пуле потоков (ThreadPoolExecutor(128)), чтобы асинхронные бэкенды (Modal, Docker) не вызывали взаимную блокировку внутри событий цикла 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
Доступные методы:
| Категория | Методы |
|---|---|
| Терминал | терминал(команда, тайм-аут) |
| Файлы | read_file(путь), write_file(путь, содержимое), поиск (запрос, путь) |
| Передача | upload_file(), upload_dir(), download_file(), download_dir() |
| Веб | web_search(запрос), 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" и т.д.
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) парсеры не нужны — сервер обрабатывает инструменты синтаксического анализа вызовов изначально.
Доступные бенчмарки
ТерминалBench2
89 сложных терминальных задач с изолированными Docker-окружениями для каждой задачи.
| Что тестирует | Способность к выполнению одношаговых задач по программированию/администрированию |
| Оценка | Бинарный проход/непроход (проверка набора тестов) |
| Изоляция | Облачные изолированные окружения Модальные (Docker-образы для каждой задачи) |
| Инструменты | терминал + файл |
| Задачи | 89 задач по различным категориям |
| Стоимость | ~$50–200 за полную оценку (параллельное выполнение) |
| Время | ~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 (программирование/администрирование), калиброванные уровни сложности |
| Оценка | Бинарный проход/непроход |
| Изоляция | Облачные изолированные окружения Модальный |
| Инструменты | терминал + файл |
| Задачи | 100 задач: Лёгкие (40), Средние (26), Сложные (26), Экстремальные (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/openoughts-tblite.
YC-Скамейка
Стратегический ориентир длительного горизонта — роль агента выполняет генеральный директор AI-стартапа.
| Что тестирует | Стратегическое согласие на протяжении сотен шагов |
| Оценка | Составная: 0,5 × выживание + 0,5 × нормализованные_средства |
| Изоляция | Локальный терминал (Модальный режим не требуется) |
| Инструменты | Только терминал |
| Запуски | 9 по умолчанию (3 пресета × 3 сида), последовательно |
| Стоимость | ~$50–200 за полную оценку |
| Время | ~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 областями навыков (исследования, выводы, данные по окружающей среде, обучение), формой престижа, управлением сотрудниками и потенциальным испытанием. В отличие от бинарной оценки по задаче в TB2, измерения YC-Bench позволяют агенту поддерживать согласованную реакцию на протяжении всех сотен взаимозависимых решений.
Обучающие окружения
ТерминалТестЭнв
Минимальное самодостаточное окружение с различными задачами (без внешнего набора данных). Используется для сквозной проверки полного стека. каждая задача требует от модели создать файл известным способом; верификатор последних стандартов.
# Режим process (сохраняет развёртывания в JSONL, не требуется сервер обучения)
python environments/terminal_test_env/terminal_test_env.py process \
--env.data_path_to_save_groups terminal_test_output.jsonl
# Режим serve (подключается к API Atropos для RL-обучения)
python environments/terminal_test_env/terminal_test_env.py serve
HermesSweEnv
Обучающее окружение в стиле SWE-bench. Модель получает задание по программированию, использованию терминальных, файловых и веб-инструментов для решения ее, функция вознаграждения за запуск тестов в том же изолированном модальном режиме.
python environments/hermes_swe_env/hermes_swe_env.py serve \
--openai.model_name ВашаМодель \
--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 — Подключение к Атропос для RL-обучения
Подключает окружение к рабочему серверу API Atropos (run-api). Используется во время живого RL-обучения.
# Терминал 1: Запуск API Atropos
run-api
# Терминал 2: Запуск окружения
python environments/hermes_swe_env/hermes_swe_env.py serve \
--openai.model_name ВашаМодель
Окружение получает элементы от Атропоса, запускает агенты развёртывания, получает вознаграждение и отправляет оценённые траектории обратно для обучения.
Двухфазная операция
Фаза 1: Сервер OpenAI (Eval/SFT)
Использует server.chat_completion() с параметром tools=. Сервер (VLLM, SGLang, OpenRouter, OpenAI) обрабатывает инструменты синтаксического анализа вызовов изначально. Возвращает объекты ChatCompletion со структурированнымиtool_calls.
- Использовать для: оценки, генерация SFT-данных, бенчмарков, тестирование.
- Плейсхолдеры токенов терминала для конвейера Atropos (так как реальные ID токенов доступны через API OpenAI)
Фаза 2: VLLM ManagedServer (Полное RL)
Использует ManagedServer для точных идентификаторов токенов + logprobs через /generate. Парсер вызовов инструментов на стороне клиента организует структурированные tool_calls из необработанного результата.
- Использовать для: полное RL-обучение с GRPO/PPO
- Реальные токены, маски и логпробы, передаваемые через конвейер.
- Установите
tool_call_parserв конфигурации в соответствии с форматом вашей модели (например, `"hermes", "qwen", "mistral").
Создание окружений
Обучающее окружение
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:
- Создайте в
environments/benchmarks/ваш-бенчмарк/ - Настроить конфигурацию только для eval:
eval_handling=STOP_TRAIN,steps_per_eval=1,total_steps=1 - Заглушите методы обучения:
collect_trajectories()возвращает(None, []),score()возвращаетNone - Реализовать
rollout_and_score_eval(eval_item)— цикл агента + оценка для каждого элемента - Реализовать
evaluate()— управляющий всеми запусками вычисляет агрегированные метрики. - Добавьте потоковый JSONL для сохранения результатов, связанных с боями.
- Добавить очистку: обработка
KeyboardInterrupt,cleanup_all_environments(),_tool_executor.shutdown() - Запускайте с подкомандой
оценить
См. environments/benchmarks/yc_bench/yc_bench_env.py для чистой, хорошо документированной эталонной реализации.
Справочник по конфигурации
Поля HermesAgentEnvConfig
| Поле | Тип | По умолчанию | Описание |
|---|---|---|---|
enabled_toolsets |
Список[стр] |
Нет (все) |
Какие наборы инструментов Hermes включить |
disabled_toolsets |
Список[стр] |
Нет |
Наборы инструментов для отключения |
распределение |
ул |
Нет |
Имя вероятностного распределения набор инструментов |
max_agent_turns |
интервал |
30 |
Максимальное количество LLM-вызовов для развёртывания |
agent_temperature |
плавать |
1.0 |
Температурный сэмплирования |
system_prompt |
ул |
Нет |
Системное сообщение для агента |
terminal_backend |
ул |
"местный" |
local, docker, modal, daytona, ssh, singularity |
terminal_timeout |
интервал |
120 |
Секунда на терминале |
terminal_lifetime |
интервал |
3600 |
Максимальное время жизни изолированного окружения |
имя_набора_данных |
ул |
Нет |
Идентификатор набора данных HuggingFace |
tool_pool_size |
интервал |
128 |
Размер пула потоков для выполнения инструментов |
tool_call_parser |
ул |
"Гермес" |
Парсер для необработанного результата Фазы 2 |
extra_body |
Дикт |
Нет |
Дополнительные параметры для API OpenAI (например, настройки провайдера OpenRouter) |
eval_handling |
Энум |
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
Предварительные требования
Для всех окружений
- Питон >= 3.11
atroposlib:pip install git+https://github.com/NousResearch/atropos.git- Ключ API LLM (OpenRouter, OpenAI или собственный VLLM/SGLang)
Для бенчмарков с модальной изоляцией (TB2, TBLite)
- Учётная запись Modal и CLI:
pip install "hermes-agent[modal]" - Переменные окружения
MODAL_TOKEN_IDиMODAL_TOKEN_SECRET
Для YC-скамейки
pip install "hermes-agent[yc-bench]"(устанавливает CLI yc-bench + SQLAlchemy)- Модальный режим не требуется — работает с локальным терминальным бэкендом
Для RL-обучения
TINKER_API_KEY— ключ API для сервиса обучения TinkerWANDB_API_KEY— для идентификации метрики веса и смещения.- Подмодуль
tinker-atropos(вtinker-atropos/в репозитории)
См. RL-обучение для рабочего процесса RL, управляемого агентом.
Структура каталогов
environments/
├── hermes_base_env.py # Абстрактный базовый класс (HermesAgentBaseEnv)
├── agent_loop.py # Многопользовательский движок агента (HermesAgentLoop)
├── tool_context.py # Доступ к инструментам для функций вознаграждения в развёртывании
├── patches.py # Патчи для асинхронной безопасности бэкенда Modal
│
├── tool_call_parsers/ # Парсеры Фазы 2 на стороне клиента
│ ├── hermes_parser.py # Формат Hermes/ChatML <tool_call>
│ ├── mistral_parser.py # Формат Mistral [TOOL_CALLS]
│ ├── llama_parser.py # Вызов инструментов Llama 3 JSON
│ ├── 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
├── tblite/ # 100 калиброванных задач (быстрый прокси TB2)
└── yc_bench/ # Стратегический бенчмарк длительного горизонта