Пакетная обработка
Пакетная обработка нужна, чтобы прогнать Hermes Agent сразу через сотни или тысячи промптов параллельно и получить структурированные данные траекторий. Главный сценарий — генерация обучающих данных: на выходе вы получаете траектории в формате ShareGPT со статистикой использования инструментов, которые потом идут на дообучение модели или на оценку её качества.
Обзор
Пакетный раннер (batch_runner.py) берёт JSONL-датасет с промптами и прогоняет каждый из них через полноценную сессию агента с доступом к инструментам. Под каждый промпт выделяется отдельное изолированное окружение. Результат — структурированные данные траектории: полная история диалога, статистика вызовов инструментов и метрики покрытия рассуждениями.
Быстрый старт
# Базовый пакетный прогон
python batch_runner.py \
--dataset_file=data/prompts.jsonl \
--batch_size=10 \
--run_name=my_first_run \
--model=anthropic/claude-sonnet-4.6 \
--num_workers=4
# Возобновить прерванный прогон
python batch_runner.py \
--dataset_file=data/prompts.jsonl \
--batch_size=10 \
--run_name=my_first_run \
--resume
# Показать доступные дистрибуции наборов инструментов
python batch_runner.py --list_distributions
Пакетный прогон поднимает множество параллельных сессий агента, и каждая делает вызовы модели и вызовы инструментов. Подписка на Nous Portal объединяет доступ к моделям с веб-поиском, генерацией изображений, TTS и облачными браузерами в одном счёте — удобно, когда нужна стабильная цена за траекторию и не хочется жонглировать лимитами по пяти разным аккаунтам у вендоров. Настраивается командой hermes setup --portal, после чего в --model указываете модель Nous.
Формат датасета
На вход подаётся JSONL-файл — по одному JSON-объекту на строку. В каждой записи обязательно поле prompt:
{"prompt": "Write a Python function that finds the longest palindromic substring"}
{"prompt": "Create a REST API endpoint for user authentication using Flask"}
{"prompt": "Debug this error: TypeError: cannot unpack non-iterable NoneType object"}
Дополнительно запись может содержать:
imageилиdocker_image: образ контейнера для песочницы этого промпта (работает с бэкендами Docker, Modal и Singularity)cwd: переопределение рабочего каталога для терминальной сессии задачи
Параметры конфигурации
| Параметр | По умолчанию | Описание |
|---|---|---|
--dataset_file | (обязательный) | Путь к JSONL-датасету |
--batch_size | (обязательный) | Количество промптов в пакете |
--run_name | (обязательный) | Имя прогона (используется для каталога вывода и контрольных точек) |
--distribution | "default" | Дистрибуция наборов инструментов, из которой берутся сэмплы |
--model | claude-sonnet-4.6 | Используемая модель |
--base_url | https://openrouter.ai/api/v1 | Базовый URL API |
--api_key | (переменная окружения) | API-ключ для модели |
--max_turns | 10 | Максимум итераций с вызовом инструментов на один промпт |
--num_workers | 4 | Число параллельных рабочих процессов |
--resume | false | Возобновить с контрольной точки |
--verbose | false | Включить подробное логирование |
--max_samples | все | Обработать только первые N сэмплов из датасета |
Маршрутизация по провайдерам (OpenRouter)
| Параметр | Описание |
|---|---|
--providers_allowed | Разрешённые провайдеры через запятую (например, "anthropic,openai") |
--providers_ignored | Игнорируемые провайдеры через запятую (например, "together,deepinfra") |
--providers_order | Предпочтительный порядок провайдеров через запятую |
--provider_sort | Сортировка по "price", "throughput" или "latency" |
Управление рассуждениями
| Параметр | Описание |
|---|---|
--reasoning_effort | Уровень усилий на рассуждения: none, minimal, low, medium, high, xhigh, max, ultra |
--reasoning_disabled | Полностью отключить токены рассуждений/размышлений |
Дополнительные параметры
| Параметр | Описание |
|---|---|
--ephemeral_system_prompt | Системный промпт, который используется при выполнении, но НЕ сохраняется в траектории |
--log_prefix_chars | Сколько символов показывать в превью логов (по умолчанию: 100) |
--prefill_messages_file | Путь к JSON-файлу с предзаполненными сообщениями для few-shot-затравки |
Дистрибуции наборов инструментов
Каждому промпту достаётся случайно выбранный набор инструментов из дистрибуции. Так обучающие данные охватывают разные комбинации инструментов. Полный список дистрибуций смотрите через --list_distributions.
В нынешней реализации дистрибуция задаёт вероятность для каждого отдельного набора инструментов. Сэмплер независимо подбрасывает монетку по каждому набору, а затем гарантирует, что хотя бы один набор окажется включён. Это не то же самое, что вручную составленная таблица готовых комбинаций.
Формат вывода
Весь вывод складывается в data/<run_name>/:
data/my_run/
├── trajectories.jsonl # Объединённый финальный вывод (все пакеты слиты вместе)
├── batch_0.jsonl # Результаты отдельных пакетов
├── batch_1.jsonl
├── ...
├── checkpoint.json # Контрольная точка для возобновления
└── statistics.json # Сводная статистика по использованию инструментов
Формат траектории
Каждая строка в trajectories.jsonl — это JSON-объект:
{
"prompt_index": 42,
"conversations": [
{"from": "human", "value": "Write a function..."},
{"from": "gpt", "value": "I'll create that function...",
"tool_calls": [...]},
{"from": "tool", "value": "..."},
{"from": "gpt", "value": "Here's the completed function..."}
],
"metadata": {
"batch_num": 2,
"timestamp": "2026-01-15T10:30:00",
"model": "anthropic/claude-sonnet-4.6"
},
"completed": true,
"partial": false,
"api_calls": 3,
"toolsets_used": ["terminal", "file"],
"tool_stats": {
"terminal": {"count": 2, "success": 2, "failure": 0},
"read_file": {"count": 1, "success": 1, "failure": 0}
},
"tool_error_counts": {
"terminal": 0,
"read_file": 0
}
}
Поле conversations использует формат в духе ShareGPT с полями from и value. Статистика по инструментам нормализуется: туда добавляются все возможные инструменты с нулевыми значениями по умолчанию, чтобы схема была одинаковой во всех записях и совместимой с датасетами HuggingFace.
Контрольные точки
У пакетного раннера надёжный механизм контрольных точек на случай сбоев:
- Файл контрольной точки: сохраняется после завершения каждого пакета и хранит индексы готовых промптов
- Возобновление по содержимому: при
--resumeраннер сканирует существующие файлы пакетов и сопоставляет завершённые промпты по их фактическому текстовому содержимому (а не только по индексам), так что восстановление сработает даже при изменении порядка записей в датасете - Неудавшиеся промпты: готовыми помечаются только успешно завершённые промпты — те, что упали, будут повторены при возобновлении
- Слияние пакетов: по завершении все файлы пакетов (включая прежние прогоны) сливаются в единый
trajectories.jsonl
Как работает возобновление
- Сканируем все файлы
batch_*.jsonlна предмет завершённых промптов (сопоставление по содержимому) - Фильтруем датасет, исключая уже завершённые промпты
- Заново разбиваем оставшиеся промпты на пакеты
- Обрабатываем только оставшиеся промпты
- Сливаем все файлы пакетов (старые + новые) в финальный вывод
Фильтрация по качеству
Пакетный раннер автоматически фильтрует данные по качеству:
- Фильтр отсутствия рассуждений: сэмплы, где ни в одном ходе ассистента нет рассуждений (нет ни
<REASONING_SCRATCHPAD>, ни нативных токенов размышлений), отбрасываются - Фильтр повреждённых записей: записи с галлюцинированными именами инструментов (которых нет в списке допустимых) отсеиваются при финальном слиянии
- Статистика рассуждений: считается доля ходов с рассуждениями и без них по всему прогону
Статистика
По завершении раннер выводит подробную статистику:
- Использование инструментов: число вызовов, доля успехов и неудач по каждому инструменту
- Покрытие рассуждениями: доля ходов ассистента, содержащих рассуждения
- Отброшенные сэмплы: сколько сэмплов отсеяно из-за отсутствия рассуждений
- Длительность: общее время обработки
Та же статистика сохраняется в statistics.json для программного анализа.
Сценарии использования
Генерация обучающих данных
Получить разнообразные траектории использования инструментов под дообучение:
python batch_runner.py \
--dataset_file=data/coding_prompts.jsonl \
--batch_size=20 \
--run_name=coding_v1 \
--model=anthropic/claude-sonnet-4.6 \
--num_workers=8 \
--distribution=default \
--max_turns=15
Оценка модели
Проверить, насколько хорошо модель пользуется инструментами на стандартизированном наборе промптов:
python batch_runner.py \
--dataset_file=data/eval_suite.jsonl \
--batch_size=10 \
--run_name=eval_gpt4 \
--model=openai/gpt-4o \
--num_workers=4 \
--max_turns=10
Свой образ контейнера для каждого промпта
Когда бенчмарку нужны конкретные окружения, любой промпт может задать собственный образ контейнера:
{"prompt": "Install numpy and compute eigenvalues of a 3x3 matrix", "image": "python:3.11-slim"}
{"prompt": "Compile this Rust program and run it", "image": "rust:1.75"}
{"prompt": "Set up a Node.js Express server", "image": "node:20-alpine", "cwd": "/app"}
Перед запуском каждого промпта пакетный раннер проверяет, что образы Docker доступны.