Формат траекторий
Агент Hermes сохраняет траектории диалогов в формате JSONL, совместимом с ShareGPT, для использования в качестве обучающих данных, документов отладки и наборов данных для обучения с подкреплением.
Исходные файлы: agent/trajectory.py, run_agent.py (поиск _save_trajectory), batch_runner.py
Соглашение об именах файлов
Траектории поиска результатов в текущих рабочих директориях:
| Файл | Когда |
|---|---|
trajectory_samples.jsonl |
Диалоги, завершенные успешно (completed=True) |
failed_trajectories.jsonl |
Диалоги, завершившиеся неудачи или прерванные (completed=False) |
Пакетный запускатор (batch_runner.py) записывает в пользовательский выходной файл для каждого пакета.
(например, batch_001_output.jsonl) с другими полями метаданных.
Вы можете переопределить имя файла через параметр filename в save_trajectory().
Формат записи JSONL
каждая строка в файле представляет собой самодостаточный JSON-объект. Существует два варианта:
Формат CLI/интерактивный (из _save_trajectory)
{
"conversations": [... ],
"timestamp": "2026-03-30T14:22:31.456789",
"model": "anthropic/claude-sonnet-4.6",
"completed": true
}
Формат пакетного запускатора (из batch_runner.py)
{
"prompt_index": 42,
"conversations": [... ],
"metadata": { "prompt_source": "gsm8k", "difficulty": "hard" },
"completed": true,
"partial": false,
"api_calls": 7,
"toolsets_used": ["code_tools", "file_tools"],
"tool_stats": {
"terminal": {"count": 3, "success": 3, "failure": 0},
"read_file": {"count": 2, "success": 2, "failure": 0},
"write_file": {"count": 0, "success": 0, "failure": 0}
},
"tool_error_counts": {
"terminal": 0,
"read_file": 0,
"write_file": 0
}
}
Словари tool_stats и tool_error_counts нормализованы так, чтобы включать их.
ВСЕ возможные инструменты (из model_tools.TOOL_TO_TOOLSET_MAP) с нулевыми значениями по умолчанию,
что обеспечивает согласованную схему для всех записей при включении набора данных HuggingFace.
Массив диалогов (формат ShareGPT)
Массовые «беседы» используют соглашение о ролях ShareGPT:
| Роль API | ShareGPT от |
|---|---|
| система | "система" |
| пользователь | "человек" |
| помощник | "ГПТ" |
| инструмент | "инструмент" |
Полный пример
{
"conversations": [
{
"from": "system",
"value": "You are a function calling AI model. You are provided with function signatures within <tools> </tools> XML tags. You may call one or more functions to assist with the user query. If available tools are not relevant in assisting with user query, just respond in natural conversational language. Don't make assumptions about what values to plug into functions. After calling & executing the functions, you will be provided with function results within <tool_response> </tool_response> XML tags. Here are the available tools:\n<tools>\n[{\"name\": \"terminal\", \"description\": \"Execute shell commands\", \"parameters\": {\"type\": \"object\", \"properties\": {\"command\": {\"type\": \"string\"}}}, \"required\": null}]\n</tools>\nFor each function call return a JSON object, with the following pydantic model json schema for each:\n{'title': 'FunctionCall', 'type': 'object', 'properties': {'name': {'title': 'Name', 'type': 'string'}, 'arguments': {'title': 'Arguments', 'type': 'object'}}, 'required': ['name', 'arguments']}\nEach function call should be enclosed within <tool_call> </tool_call> XML tags.\nExample:\n<tool_call>\n{'name': <function-name>,'arguments': <args-dict>}\n</tool_call>"
},
{
"from": "human",
"value": "What Python version is installed?"
},
{
"from": "gpt",
"value": " thinking\nThe user wants to know the Python version. I should run python3 --version.\n response\n<tool_call>\n{\"name\": \"terminal\", \"arguments\": {\"command\": \"python3 --version\"}}\n</tool_call>"
},
{
"from": "tool",
"value": "<tool_response>\n{\"tool_call_id\": \"call_abc123\", \"name\": \"terminal\", \"content\": \"Python 3.11.6\"}\n</tool_response>"
},
{
"from": "gpt",
"value": " thinking\nGot the version. I can now answer the user.\n response\nPython 3.11.6 is installed on this system."
}
],
"timestamp": "2026-03-30T14:22:31.456789",
"model": "anthropic/claude-sonnet-4.6",
"completed": true
}
Правила нормализации
Разметка оценок рассуждений
Конвертер траекторий нормализует ВСЕ рассуждения в теги мышление, независимо от того,
как модель изначально их создала:
-
Собственные токены рассуждений (поле
msg["рассуждение"]от провайдеров, такие как Anthropic, OpenAI o-series): Оборачиваются какмышление\n{рассуждение}\n ответ\nи включиться перед содержимым. -
REASONING_SCRATCHPAD XML (при индивидуальном рассуждении отключены и модели рассуждает через XML, заданным системным промптом): Теги
<REASONING_SCRATCHPAD>преобразуются вмышлениис помощьюconvert_scratchpad_to_think(). -
Пустые блоки думают: Каждый ход
gptгарантированно содержит блокмышления. Если рассуждений не было, вставляется пустой блок:мышление\nответ\n— это обеспечивает единообразную форму для обучающихся данных.
Нормализация вызовов инструментов
Вызовы инструментов формирования API (с tool_call_id, именем функции, аргументами в видео
JSON-строки) преобразуются в XML-обёрнутый JSON:
<tool_call>
{"name": "terminal", "arguments": {"command": "ls -la"}}
</tool_call>
- Аргументы парятся из JSON-строка обратно в объекты (не двойное кодирование)
- Если парсинг JSON не удался (не нужно начинать — сначала во время диалога),
используется пустой
{}при записи ссылки в журнале - Несколько вызовов инструментов за один ход ассистента отображают несколько блоков
<tool_call>в одномgpt
Нормализация инструментов ответов
Все результаты работы инструментов после сообщений ассистента группируются за один ход
tool с XML-обёрнутыми JSON-ответами:
<tool_response>
{"tool_call_id": "call_abc123", "name": "terminal", "content": "output here"}
</tool_response>
- Если необходимый инструмент выглядит как JSON (начинается с
{или[), он парсится, чтобы поле содержимого отображается в формате JSON-объект/массив, а не в виде текста - Несколько инструментов для получения результатов объединяются с переносом строк в одном месте.
- Имя инструмента сопоставляется с массивом
tool_callsродительского ассистента.
Системное сообщение
Системное сообщение происходит во время сохранения (не берётся из диалога). Оно следует шаблону промпта вызова функций Hermes, включая:
- Преамбулу, объясняющую вызов функций протокола.
- XML-блок
<tools>, содержащая JSON-определения инструментов - Отправка на схему для объектов
FunctionCall - Пример
<tool_call>
Инструменты определения включают «имя», «описание», «параметры» и «обязательные».
(установлено в null для соответствия стандартному формату).
Загрузка траекторий
Траектории — это стандартный JSONL — загружайте любые средства чтения JSON-строк:
import json
def load_trajectories(path: str):
"""Загружает записи траекторий из JSONL-файла."""
entries = []
with open(path, "r", encoding="utf-8") as f:
for line in f:
line = line.strip()
if line:
entries.append(json.loads(line))
return entries
# Фильтрация только успешных завершений
successful = [e for e in load_trajectories("trajectory_samples.jsonl")
if e.get("completed")]
# Извлечение только диалогов для обучения
training_data = [e["conversations"] for e in successful]
Загрузка для набора данных HuggingFace
from datasets import load_dataset
ds = load_dataset("json", data_files="trajectory_samples.jsonl")
Нормализованная схема tool_stats гарантирует, что все записи имеют одинаковые столбцы,
предотвращающая ошибки несоответствия схемы Arrow при включении набора данных.
Управление сохранением траекторий
В CLI сохранение траекторий управляется через:
# config.yaml
agent:
save_trajectories: true # по умолчанию: false
Или через флаг --save-trajectories. Когда агентизируется с
save_trajectories=True, метод _save_trajectory() возникает в конце
каждый ход диалога.
Пакетный пусковой механизм всегда сохраняет траектории (это его основная цель).
Образцы с нулевым уровнем распределения во всех ходах автоматически выбрасываются. пакетным запуском, чтобы избежать загрязнения обучающих данных примерами без рассуждений.