Перейти к основному содержимому

Формат траекторий

VibeOS сохраняет траектории диалогов в совместимом с ShareGPT формате JSONL для использования в качестве обучающих данных, артефактов отладки и наборов данных для обучения с подкреплением.

Исходные файлы: 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)​

Массив conversations использует соглашения о ролях ShareGPT:

Роль APIShareGPT from
system"system"
user"human"
assistant"gpt"
tool"tool"

Полный пример​

{
"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": "<think>\nThe user wants to know the Python version. I should run python3 --version.\n</think>\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": "<think>\nGot the version. I can now answer the user.\n</think>\nPython 3.11.6 is installed on this system."
}
],
"timestamp": "2026-03-30T14:22:31.456789",
"model": "anthropic/claude-sonnet-4.6",
"completed": true
}

Правила нормализации​

Разметка содержимого рассуждений​

Конвертер траекторий нормализует ВСЕ рассуждения в теги &lt;think&gt;, независимо от того, как модель изначально их создала:

  1. Нативные токены мышления (поле msg["reasoning"] от провайдеров Anthropic, OpenAI o-series): Оборачиваются как &lt;think&gt;\n{reasoning}\n&lt;/think&gt;\n и добавляются перед содержимым.

  2. REASONING_SCRATCHPAD XML (когда нативное мышление отключено и модель рассуждает через XML, заданный системным промптом): Теги &lt;REASONING_SCRATCHPAD&gt; преобразуются в &lt;think&gt; через convert_scratchpad_to_think().

  3. Пустые блоки think: Каждый ход gpt гарантированно содержит блок &lt;think&gt;. Если рассуждений не было, вставляется пустой блок: &lt;think&gt;\n&lt;/think&gt;\n — это обеспечивает согласованный формат для обучающих данных.

Нормализация вызовов инструментов​

Вызовы инструментов из формата API (с tool_call_id, именем функции, аргументами в виде JSON-строки) преобразуются в JSON, обёрнутый в XML:

<tool_call>
{"name": "terminal", "arguments": {"command": "ls -la"}}
</tool_call>
  • Аргументы парсятся из JSON-строк обратно в объекты (без двойного кодирования)
  • Если парсинг JSON не удаётся (не должно происходить — проверяется во время диалога), используется пустой {} с записью предупреждения в лог
  • Несколько вызовов инструментов в одном ходе ассистента создают несколько блоков &lt;tool_call&gt; в одном сообщении gpt

Нормализация ответов инструментов​

Все результаты инструментов, следующие за сообщением ассистента, группируются в один ход tool с JSON-ответами, обёрнутыми в XML:

<tool_response>
{"tool_call_id": "call_abc123", "name": "terminal", "content": "output here"}
</tool_response>
  • Если содержимое инструмента выглядит как JSON (начинается с { или [), оно парсится, чтобы поле content содержало JSON-объект/массив, а не строку
  • Несколько результатов инструментов объединяются с переносом строки в одном сообщении
  • Имя инструмента сопоставляется по позиции с массивом tool_calls родительского ассистента

Системное сообщение​

Системное сообщение генерируется в момент сохранения (не берётся из диалога). Оно следует шаблону промпта вызова функций VibeOS, включающему:

  • Преамбулу, объясняющую протокол вызова функций
  • XML-блок &lt;tools&gt;, содержащий JSON-определения инструментов
  • Ссылку на схему для объектов FunctionCall
  • Пример &lt;tool_call&gt;

Определения инструментов включают name, description, parameters и required (установлено в 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() вызывается в конце каждого хода диалога.

Пакетный запускатор всегда сохраняет траектории (это его основная цель).

Примеры с нулевым количеством рассуждений во всех ходах автоматически отбрасываются пакетным запускатором, чтобы избежать загрязнения обучающих данных примерами без рассуждений.