原文链接:Trajectory Format Hermes Agent 以 ShareGPT 兼容的 JSONL 格式保存对话轨迹(Trajectory),用作训练数据、调试产物和强化学习数据集。 源文件:agent/trajectory.py、run agent.py(搜索 save trajectory)、batc
> 原文链接:Trajectory Format
轨迹格式(Trajectory Format)
Hermes Agent 以 ShareGPT 兼容的 JSONL 格式保存对话轨迹(Trajectory),用作训练数据、调试产物和强化学习数据集。
源文件: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),带有额外的元数据字段。
你可以通过 save_trajectory() 中的 filename 参数覆盖文件名。
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),默认为零值,确保各条目之间 Schema 一致,便于 HuggingFace 数据集加载。
conversations 数组(ShareGPT 格式)
conversations 数组使用 ShareGPT 角色约定:
| API 角色 | ShareGPT 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_results> </tool_results> 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_call> </tool_call_call> XML tags.\\nExample:\\n<tool_call_call>\\n{'name': <function-name>,'arguments': <args-dict>}\\n</tool_call_call>\\n"
},
{
"from": "human",
"value": "What Python version is installed?"
},
{
"from": "gpt",
"value": "<think_call>\\nThe user wants to know the Python version. I should run python3 --version.\\n</think_call>\\n<tool_call_call>\\n{\\\"name\\\": \\\"terminal\\\", \\\"arguments\\\": {\\\"command\\\": \\\"python3 --version\\\"}}\\n</tool_call_call>"
},
{
"from": "tool",
"value": "<tool_results>\\n{\\\"tool_call_id\\\": \\\"call_abc123\\\", \\\"name\\\": \\\"terminal\\\", \\\"content\\\": \\\"Python 3.11.6\\\"}\\n</tool_results>"
},
{
"from": "gpt",
"value": "<think_call>\\nGot the version. I can now answer the user.\\n</think_call>\\nPython 3.11.6 is installed on this system."
}
],
"timestamp": "2026-03-30T14:22:31.456789",
"model": "anthropic/claude-sonnet-4.6",
"completed": true
}
标准化规则
推理内容标记
轨迹转换器将所有推理内容标准化为 <think_call> 标签,无论模型最初如何生成:
-
原生思考 token(来自 Anthropic、OpenAI o 系列等 Provider 的
msg["reasoning"]字段):包装为<think_call>\n{reasoning}\n</think_call>\n并前置到内容之前。 -
REASONING_SCRATCHPAD XML(当原生思考被禁用且模型通过系统提示词指示的 XML 推理时):
<REASONING_SCRATCHPAD>标签通过convert_scratchpad_to_think()转换为<think_call>。 -
空思考块:每个
gpt轮次保证有一个<think_call>块。如果没有生成推理内容,则插入一个空块:<think_call>\n</think_call>— 这确保训练数据格式一致。
工具调用标准化
来自 API 格式的工具调用(带有 tool_call_id、函数名、JSON 字符串参数)被转换为 XML 包装的 JSON:
<tool_call_call>
{"name": "terminal", "arguments": {"command": "ls -la"}}
</tool_call_call>
- 参数从 JSON 字符串解析回对象(非双重编码)
- 如果 JSON 解析失败(不应发生 — 对话期间已验证),使用空
{}并记录警告 - 一个 Assistant 轮次中的多个工具调用在单个
gpt消息中生成多个<tool_call_call>块
工具响应标准化
Assistant 消息之后的所有工具结果被分组到一个带有 XML 包装 JSON 响应的 tool 轮次中:
<tool_results>
{"tool_call_id": "call_abc123", "name": "terminal", "content": "output here"}
</tool_results>
- 如果工具内容看起来像 JSON(以
{或[开头),它会被解析,使 content 字段包含 JSON 对象/数组而非字符串 - 多个工具结果在一条消息中用换行符连接
- 工具名称按位置匹配父级 Assistant 的
tool_calls数组
系统消息
系统消息在保存时生成(不从对话中获取)。它遵循 Hermes 函数调用提示模板,包含:
- 解释函数调用协议的前导说明
- 包含 JSON 工具定义的
<tools>XML 块 FunctionCall对象的 Schema 参考<tool_call_call>示例
工具定义包括 name、description、parameters 和 required(设为 null 以匹配规范格式)。
加载轨迹
轨迹是标准 JSONL — 使用任何 JSON Lines 读取器加载:
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 Schema 确保所有条目具有相同的列,防止数据集加载时的 Arrow Schema 不匹配错误。
控制轨迹保存
在 CLI 中,轨迹保存由以下配置控制:
# config.yaml
agent:
save_trajectories: true # 默认:false
或通过 --save-trajectories 标志。当 Agent 以 save_trajectories=True 初始化时,_save_trajectory() 方法在每个对话轮次结束时调用。
批量运行器始终保存轨迹(这是其主要目的)。
所有轮次中零推理的样本会被批量运行器自动丢弃,以避免用非推理样本污染训练数据。