{/ Эта страница автоматически создается на основе файла SKILL.md навыка с помощью сайта site/scripts/generate-skill-docs.py. Редактируйте исходный код SKILL.md, а не эту страницу. /}

Окружающая среда Гермеса Атропоса

Создавайте, тестируйте и отлаживайте среды Hermes Agent RL для обучения Atropos. Охватывает интерфейс HermesAgentBaseEnv, функции вознаграждения, интеграцию цикла агента, оценку с помощью инструментов, ведение журнала wandb и три режима CLI (обслуживание/обработка/оценка). Используйте при создании, проверке или исправлении сред RL в репозитории hermes-agent.

Метаданные навыков

Источник Необязательно — установите с помощью hermesskills installofficial/mlops/hermes-atropos-environments
Путь необязательные-навыки/mlops/hermes-atropos-environments
Версия 1.1.0
Автор Агент Гермес
Лицензия Массачусетский технологический институт
Платформы Linux, MacOS, Windows
Теги атропос, rl, среда, обучение, обучение с подкреплением, функции вознаграждения
Сопутствующие навыки axolotl, fine-tuning-with-trl, lm-evaluation-harness

Ссылка: полная версия SKILL.md:::информация

Ниже приведено полное определение навыка, которое Гермес загружает при активации этого навыка. Это то, что агент видит в качестве инструкций, когда навык активен.

Гермес Агент Атропос Окружающая среда

Руководство по созданию сред RL в репозитории hermes-agent, которые интегрируются с обучающей средой Atropos.

Обзор архитектуры

Atropos BaseEnv (atroposlib/envs/base.py)
    └── HermesAgentBaseEnv (environments/hermes_base_env.py)
            ├── Handles agent loop orchestration
            ├── Handles tool resolution per group
            ├── Handles ToolContext for reward verification
            └── YOUR ENVIRONMENT (environments/your_env.py)
                    Only implements: setup, get_next_item, format_prompt,
                                    compute_reward, evaluate, wandb_log

Среды Hermes особенные, поскольку в них выполняется многооборотный цикл агента с вызовом инструментов, а не просто однооборотные завершения. Базовая среда env обрабатывает цикл; Вы выполняете задание и получаете балл.

Расположение файлов

Файл Цель
environments/hermes_base_env.py Базовый класс с циклом агента + разрешение инструмента
environments/agent_loop.py Класс данных HermesAgentLoop + AgentResult
среды/tool_context.py ToolContext для проверки вознаграждения
environments/tool_call_parsers.py Парсеры вызовов инструментов фазы 2 (hermes, mistral и т. д.)
среды/your_env.py Реализация вашей среды

Настройка вывода — сначала спросите пользователя

ВАЖНО: Прежде чем запускать какую-либо команду тестирования, оценки или создания данных, всегда спрашивайте пользователя, как он хочет обрабатывать логические выводы. НЕ предполагайте OpenRouter или какую-либо конкретную конечную точку. Представьте такие варианты:

  1. OpenRouter — спросите, какую модель они хотят использовать (например, «anthropic/claude-sonnet-4.5», «google/gemini-2.5-pro», «meta-llama/llama-3.3-70b-instruct» и т. д.). В среде требуется OPENROUTER_API_KEY.
  2. Автономная конечная точка VLLM — запросите базовый URL-адрес (например, http://localhost:8000/v1) и название модели. Установите --openai.server_type vllm.
  3. Другой API, совместимый с OpenAI. Запросите базовый URL-адрес, название модели и любой необходимый ключ API. Установите --openai.server_type openai и --openai.health_check false.
  4. Локальный обучающий сервер Atropos — для режима обслуживания с живым циклом обучения. По умолчанию http://localhost:8000/v1.

Как только пользователь сообщит вам свои настройки, используйте эти значения во всех командах CLI для этого сеанса. Пример подсказки:

«Прежде чем я запущу это, как бы вы хотели обработать вывод? 1. OpenRouter (мне понадобится предпочитаемая вами модель, например claude-sonnet-4.5) 2. Автономная конечная точка VLLM (дайте мне URL-адрес и название модели). 3. Другой OpenAI-совместимый API (дайте мне URL, модель и любые данные аутентификации) 4. Локальный обучающий сервер Атропос (режим обслуживания)"

Ключевые флаги по провайдерам:

Провайдер --openai.server_type --openai.health_check --openai.api_key
OpenRouter опенай ложь $OPENROUTER_API_KEY
VLLM (автономное размещение) вллм (по умолчанию) (не требуется)
Другое OpenAI-совместимое опенай ложь По мере необходимости
Местный Атропос (по умолчанию) (по умолчанию) (не требуется)

Обязательные методы

1. setup() — Загрузка набора данных и инициализация состояния

async def setup(self) -> None:
    """Called once at startup. Load datasets, initialize state."""
    # Try HuggingFace first, fallback to built-in samples
    try:
        from datasets import load_dataset
        ds = load_dataset("your/dataset", split="test")
        self._items = [...]
    except Exception:
        self._items = BUILTIN_SAMPLES

    # Always split into train/eval
    random.shuffle(self._items)
    eval_size = max(20, int(len(self._items) * 0.1))
    self._eval_items = self._items[:eval_size]
    self._items = self._items[eval_size:]

2. get_next_item() — Возвращает следующий обучающий элемент

async def get_next_item(self) -> dict:
    """Return next item, cycling through dataset."""
    item = self._items[self._index % len(self._items)]
    self._index += 1
    return item

3. format_prompt(item) — Преобразовать элемент в сообщение пользователя.

def format_prompt(self, item: dict) -> str:
    """Convert a dataset item into the user-facing prompt."""
    return f"Research this question: {item['question']}"

4. compute_reward(item, result, ctx) — Оценка развертывания

КРИТИЧЕСКОЕ: «result» — это «AgentResult», а НЕ словарь. Он имеет следующие атрибуты: - result.messages — Список сообщений сообщений (формат OpenAI) - result.turns_used — Количество сделанных вызовов LLM - result.finished_naturally — True, если модель остановилась добровольно - result.tool_errors — Список объектов ToolError

AgentResult НЕ имеет: final_response, tool_calls, tools_used. Вы должны извлечь их из result.messages:

async def compute_reward(self, item, result: AgentResult, ctx: ToolContext) -> float:
    # Extract final response (last assistant message with content)
    final_response = ""
    tools_used = []
    for msg in reversed(result.messages):
        if msg.get("role") == "assistant" and msg.get("content") and not final_response:
            final_response = msg["content"]
        if msg.get("role") == "assistant" and msg.get("tool_calls"):
            for tc in msg["tool_calls"]:
                fn = tc.get("function", {}) if isinstance(tc, dict) else {}
                name = fn.get("name", "")
                if name:
                    tools_used.append(name)

    # Score using LLM judge, heuristic, or ToolContext verification
    correctness = await self._llm_judge(item, final_response)
    return correctness

ctx (ToolContext) предоставляет вам доступ к терминалу/файлу к песочнице агента для проверки:

# Run tests in the agent's sandbox
result = ctx.terminal("pytest /workspace/test.py")
return 1.0 if result["exit_code"] == 0 else 0.0

5. evaluate() — Периодическая оценка с полным циклом агента

ДОЛЖЕН использовать полный цикл агента с инструментами, а не одноразовое чат_завершение. Вся суть гермес-агентных сред заключается в агентной оценке:

async def evaluate(self, *args, **kwargs) -> None:
    import time, uuid
    from environments.agent_loop import HermesAgentLoop
    from environments.tool_context import ToolContext

    start_time = time.time()
    tools, valid_names = self._resolve_tools_for_group()
    samples = []

    for item in self._eval_items[:self.config.eval_size]:
        task_id = str(uuid.uuid4())
        messages = []
        if self.config.system_prompt:
            messages.append({"role": "system", "content": self.config.system_prompt})
        messages.append({"role": "user", "content": self.format_prompt(item)})

        agent = HermesAgentLoop(
            server=self.server,
            tool_schemas=tools,
            valid_tool_names=valid_names,
            max_turns=self.config.max_agent_turns,
            task_id=task_id,
            temperature=0.0,  # Deterministic for eval
            max_tokens=self.config.max_token_length,
            extra_body=self.config.extra_body,
        )
        result = await agent.run(messages)

        ctx = ToolContext(task_id)
        try:
            reward = await self.compute_reward(item, result, ctx)
        finally:
            ctx.cleanup()

        samples.append({"prompt":..., "response":..., "reward": reward})

    eval_metrics = {"eval/mean_reward":...}
    await self.evaluate_log(metrics=eval_metrics, samples=samples,
                            start_time=start_time, end_time=time.time())

6. wandb_log() — Регистрация пользовательских метрик

Всегда вызывайте super().wandb_log() в конце:

async def wandb_log(self, wandb_metrics=None):
    if wandb_metrics is None:
        wandb_metrics = {}
    if self._reward_buffer:
        n = len(self._reward_buffer)
        wandb_metrics["train/mean_reward"] = sum(self._reward_buffer) / n
        self._reward_buffer.clear()
    await super().wandb_log(wandb_metrics)  # MUST call super

Подводная ошибка: compute_reward добавляется к буферам метрик. Во время оценки это ухудшает показатели обучения. Откат записей буфера, добавленных во время оценки.

Класс конфигурации

Всегда создавайте собственный подкласс конфигурации с дескрипторами полей Pydantic. Ключевые унаследованные поля, которые вы можете настроить: enabled_toolsets, max_agent_turns, agent_temperature, system_prompt, terminal_backend, group_size, steps_per_eval, total_steps.

config_init() — Конфигурация по умолчанию

Метод класса возвращает (YourEnvConfig, [APIServerConfig(...)]). Установите для server_type значение «openai» для OpenRouter/внешних API. Загрузите ключ API из переменной среды.

Три режима CLI

# SERVE — Full training loop (connects to Atropos API server)
python environments/my_env.py serve --openai.base_url http://localhost:8000/v1

# PROCESS — Offline data generation (saves JSONL)
python environments/my_env.py process --env.total_steps 10 --env.group_size 1 \
    --env.use_wandb false --env.data_path_to_save_groups output.jsonl \
    --openai.base_url "<USER_BASE_URL>" \
    --openai.model_name "<USER_MODEL>" \
    --openai.server_type <USER_SERVER_TYPE> --openai.health_check false

# EVALUATE — Standalone eval (runs setup + evaluate only)
python environments/my_env.py evaluate --env.eval_size 20 \
    --env.data_dir_to_save_evals /tmp/eval_results \
    --openai.base_url "<USER_BASE_URL>" \
    --openai.model_name "<USER_MODEL>" \
    --openai.server_type <USER_SERVER_TYPE> --openai.health_check false

Приоритет конфигурации: аргументы CLI > файл YAML > значения по умолчанию config_init().

Распространенные ошибки

  1. AgentResult имеет.messages, а не.final_response — извлеките окончательный ответ, перебирая обратный(result.messages) поиск последнего сообщения помощника с содержимым.

  2. evaluate() должен использовать HermesAgentLoop, а не chat_completion — для однооборотной функции Chat_Completion нет инструментов. Вся суть тестов Hermes-Agent заключается в агентной оценке с использованием инструментов.

  3. Не вызывайте _llm_judge дважды — если Compute_reward уже вызывает его, извлеките оценку из буфера вместо отдельного вызова судьи в Assessment().

  4. Eval загрязняет обучающие буферы — Compute_reward добавляется к буферам метрик. Во время оценки откатите записи буфера, чтобы сохранить чистоту показателей обучения.

  5. Всегда устанавливайте health_check=false для OpenRouter — OpenRouter не имеет конечной точки /health.

  6. Установите data_dir_to_save_evals в режиме оценки — без этого результаты не сохраняются.

  7. Переменная класса default_toolsets и конфигурация Enable_toolsets — переменная класса является подсказкой; поле конфигурации — это то, что фактически контролирует разрешение инструмента.

  8. Разбор вызовов инструментов в сообщениях — Вызовы инструментов представляют собой словари с {"function": {"name":..., "arguments":...}}. Всегда проверяйте isinstance(tc, dict)`.

  9. ToolContext.cleanup() — всегда вызывайте блокfinally, чтобы освободить ресурсы песочницы.

  10. server_type должен быть «openai» для внешних API — без него Atropos предполагает локальный сервер VLLM.

  11. Всегда спрашивайте у пользователя настройки вывода — Никогда не программируйте жестко и не предполагайте конкретного поставщика/модель. См. раздел «Настройка вывода» выше.

Шаблоны функций вознаграждения

LLM Judge (для открытых задач)

Используйте self.server.chat_completion() с подсказкой о подсчете очков. Разобрать ответ JSON на наличие плавающей оценки. Всегда включайте эвристический запасной вариант (перекрытие ключевых слов) на случай, если вызов судьи не удался.

Двоичная проверка (для задач кода/терминала)

Используйте ctx.terminal("pytest test.py -q") для запуска тестов в изолированной программной среде агента. Возвращайте 1,0 в случае прохождения, 0,0 в случае неудачи.

Multi-Signal (объединить несколько индикаторов)

Правильность веса (0,6) + использование инструмента (0,2) + эффективность (0,2) + дополнительные бонусы. Зафиксировать на [0, 1].

Тестирование вашей среды

  1. Тест импорта: python -c "from Environments.my_env import MyEnv; print('OK')"
  2. Попросите пользователя настроить вывод (см. раздел «Настройка вывода» выше).
  3. Режим обработки (1 элемент): убедитесь, что выходные данные JSONL содержат действительные токены, маски и оценки.
  4. Режим оценки: проверьте выполнение полного цикла агента с помощью инструментов и правильность регистрации показателей.
  5. Проверьте диапазон наград: баллы должны быть в диапазоне [0, 1], не все они одинаковы.

Минимальный контрольный список реализации

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

    @classmethod
    def config_init(cls):...          # Default server + env config
    async def setup(self):...         # Load dataset + train/eval split
    async def get_next_item(self):... # Cycle through training items
    def format_prompt(self, item):... # Item → user message string
    async def compute_reward(self, item, result, ctx):...  # Score rollout
    async def evaluate(self, *args, **kwargs):...  # Full agent loop eval
    async def wandb_log(self, metrics=None):...    # Custom metrics + super()

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