先说一个最重要的边界:
text
这套 RL / Evaluation Environment 和 Hermes 主 Agent 的 memory、skills、subagent 自进化能力关系不大。
它虽然放在 hermes-agent 仓库里,也复用了 Hermes 的 terminal/file/web 等工具,
但它的主要目标不是让模型在对话中自动沉淀 skills、调用 subagent、管理长期记忆,
而是评测模型效果、收集工具调用轨迹、生成训练数据,并在可训练模型场景下做 RL 训练。
换句话说,它训练或评测的是更底层的能力:
text
模型能不能读懂任务 -> 调用工具 -> 观察结果 -> 继续修正 -> 完成任务 -> 被 verifier 自动打分。
如果你想研究 Hermes 的完整自进化能力,应该重点看 memory、skills、multi-agent delegation 等模块;如果你想研究模型如何在可验证任务里被评测、采样 trajectory、计算 reward、进入 RL 训练管线,才应该看这套环境。
这篇文档把两个问题放在一起讲:
text
1. 作为使用者,我什么时候需要这套功能?怎么跑?准备什么数据和命令?
2. 作为开发者,Hermes 内部是怎么把任务跑成 rollout、怎么调用工具、怎么打分、怎么产出训练/评测数据的?
先给一个最短定义:
text
RL / Evaluation Environment 是一个"自动考场"。
它给模型出题,允许模型调用工具做题,
记录模型完整做题过程,
再用 verifier 自动判分。
在 Hermes 里,这个自动考场主要由两层组成:
text
hermes-agent/environments/
真正的环境实现:出题、跑 agent loop、调用工具、自动判分、保存 trajectory。
tools/rl_training_tool.py
聊天里的训练管理工具:选择训练环境、改配置、启动训练、查状态、停止训练。
第一次学习时,不要直接做 RL 训练。推荐顺序是:
text
1. 用 TerminalTestEnv process 跑通最小链路。
2. 用 TBLite evaluate 跑少量 benchmark 任务。
3. 看 HermesSweEnv,理解代码任务和测试型 reward。
4. 再研究 Phase 1 / Phase 2、tool parser、ScoredDataItem。
5. 最后才看 rl_* 工具和真正训练。
1. 先选使用场景:你到底想用它干什么
如果你不知道应该从哪里开始,先看这张表。
| 目标 | 适合的环境 | 数据准备 | 推荐命令 | 结果看什么 |
|---|---|---|---|---|
| 验证整套 RL/eval 栈能不能跑通 | TerminalTestEnv |
不需要,任务内置 | process |
JSONL 里的 scores 和 messages |
| 快速看模型会不会用 terminal/file 工具 | TerminalTestEnv 或 TBLite |
TBLite 自动下载 HF dataset |
process / evaluate |
pass rate、tool calls、失败原因 |
| 正式评测 terminal agent 能力 | TBLite / Terminal-Bench 2 |
自动下载 HuggingFace dataset | evaluate |
overall/category pass rate |
| 评测代码修复能力 | HermesSweEnv |
HuggingFace dataset 或自定义 dataset | process / serve |
测试通过率、reward、messages |
| 生成工具调用训练数据 | 任意合适 environment | 任务集 + verifier | process --env.data_path_to_save_groups |
高分 trajectory |
| 真正做 RL 训练 | 自定义或已有 Atropos env | 稳定 reward + 训练服务 | serve + trainer / rl_* |
WandB、reward 曲线、checkpoint |
判断标准很简单:
text
如果任务能被程序自动判定成功/失败,就适合做 Evaluation / RL Environment。
如果只能靠人主观判断回答好不好,就不适合直接做 RL Environment。
适合的任务:
text
文件是否创建
测试是否通过
网页状态是否达成
API 返回是否正确
数据库是否写入目标值
命令行任务是否产出指定结果
不适合的任务:
text
开放式闲聊
纯主观写作质量判断
没有自动 verifier 的任务
真实付款、真实发消息等不可重复外部副作用
2. 最小上手:用 TerminalTestEnv 跑通链路
这是第一次学习最应该跑的环境。它不需要你准备 dataset,任务写在代码里。
它验证的是:
text
环境能不能启动
模型 API 能不能调用
工具 schema 能不能传给模型
模型能不能调用 terminal/file
reward 能不能在同一个 sandbox 里检查结果
trajectory 能不能保存成 JSONL
2.1 准备依赖和密钥
最低需要:
text
Python >= 3.11
Hermes RL 依赖
OPENROUTER_API_KEY
Modal 认证,如果使用 terminal_backend=modal
安装依赖:
bash
uv venv venv --python 3.11
source venv/bin/activate
uv pip install -e ".[rl,dev,modal]"
注意:pyproject.toml 里的 all extra 当前没有包含 rl extra,所以如果你只装了 .[all,dev],建议再显式安装 .[rl,dev,modal]。
配置模型 key:
bash
cp .env.example .env
# 编辑 .env,填 OPENROUTER_API_KEY
如果使用 Modal:
bash
modal setup
相关配置说明 / Modal Setup
英文原文:
text
Modal uses CLI authentication, not environment variables.
Run: pip install modal && modal setup
This will authenticate via browser and store credentials locally.
No API key needed in .env - Modal handles auth automatically.
中文对照:
text
Modal 使用 CLI 认证,不使用环境变量。
运行:pip install modal && modal setup。
它会通过浏览器认证,并把凭据保存在本地。
.env 不需要 Modal API key,Modal 会自动处理认证。
2.2 第一次推荐命令:process 模式
第一次建议用 process,不要先用 serve。process 会直接跑 rollout 并保存 JSONL,适合确认整条链路是否正常。
bash
python environments/terminal_test_env/terminal_test_env.py process \
--config environments/terminal_test_env/default.yaml \
--env.use_wandb false \
--env.data_path_to_save_groups terminal_test_output.jsonl
如果你想先不用 Modal,改成本地 terminal:
bash
python environments/terminal_test_env/terminal_test_env.py process \
--config environments/terminal_test_env/default.yaml \
--env.terminal_backend local \
--env.use_wandb false \
--env.data_path_to_save_groups terminal_test_output.jsonl
本地模式容易跑,但隔离弱。Modal 模式更接近正式评测。
2.3 这个环境给模型出的题
TerminalTestEnv 内置了三类训练任务:
text
Create a file at ~/greeting.txt containing exactly the text: Hello from Hermes Agent
Create a file at ~/count.txt containing the numbers 1 through 5, one per line
Create a file at ~/answer.txt containing the result of 123 + 456
任务 item 长这样:
json
{
"prompt": "Create a file at ~/greeting.txt containing exactly the text: Hello from Hermes Agent",
"verify_path": "~/greeting.txt",
"expected_content": "Hello from Hermes Agent"
}
2.4 模型看到的 prompt 和工具
TerminalTestEnv 使用一个很薄的 system prompt。
相关提示词 / System Prompt
英文原文:
text
You are a helpful assistant with access to a terminal and file tools. Complete the user's request by using the available tools. Be precise and follow instructions exactly.
中文对照:
text
你是一个有 terminal 和 file 工具访问权限的助手。使用可用工具完成用户请求。要精确,并严格遵循指令。
这段 prompt 只告诉模型:你应该用工具完成任务。真正让模型能调用 terminal/file 的,是 environment 配置里的 toolsets:
yaml
enabled_toolsets: ["terminal", "file"]
相关配置说明 / Config Field Description
英文原文:
text
enabled_toolsets: Explicit list of hermes toolsets to enable (e.g., ['terminal', 'file', 'web']). If None and distribution is also None, all available toolsets are enabled.
中文对照:
text
enabled_toolsets:显式启用哪些 Hermes toolsets,例如 ['terminal', 'file', 'web']。如果为 None 且 distribution 也为 None,就启用所有可用 toolsets。
这说明:模型不是因为代码里写了"如果创建文件就调用 terminal"才行动,而是因为它看到 user prompt + terminal/file tool schema 后,自己决定调用工具。
2.5 背后的实现:一次 TerminalTest rollout 怎么跑
从代码路径看,这次命令最终走的是:
text
TerminalTestEnv.get_next_item()
↓
TerminalTestEnv.format_prompt(item)
↓
HermesAgentBaseEnv.collect_trajectory(item)
↓
HermesAgentLoop.run(messages)
↓
模型多轮 tool calling
↓
TerminalTestEnv.compute_reward(item, result, ctx)
↓
ScoredDataItem 写入 JSONL
compute_reward() 的核心逻辑是:
text
ctx.terminal(f"cat {item['verify_path']}")
↓
实际内容 == expected_content → 1.0
expected_content 包含在实际内容中 → 0.5
否则 → 0.0
关键是 ctx。它是 ToolContext(task_id),会进入模型刚才操作过的同一个 sandbox。
相关实现说明 / ToolContext Description
英文原文:
text
A per-rollout handle that gives reward/verification functions direct access to
ALL hermes-agent tools, scoped to the rollout's task_id. The same task_id means
the terminal/browser session is the SAME one the model used during its rollout --
all state (files, processes, browser tabs) is preserved.
中文对照:
text
ToolContext 是每个 rollout 的句柄,让 reward / verification 函数可以直接访问所有 Hermes Agent 工具,并且作用域限定在这个 rollout 的 task_id。相同 task_id 表示 terminal/browser session 和模型 rollout 时使用的是同一个,因此文件、进程、浏览器标签页等状态都会保留。
所以 reward 不是看模型最后说"我完成了",而是在真实环境里检查文件内容。
2.6 跑完看什么
看输出文件:
bash
head -n 1 terminal_test_output.jsonl
重点看:
text
scores:每个 rollout 的分数
messages:完整消息和工具调用轨迹
一条正常轨迹应该有:
text
user prompt
assistant tool_calls
tool result
assistant final answer
score
如果全 0,优先检查:
text
模型是否调用工具
tool result 是否报错
terminal backend 是否启动成功
verify_path 路径是否一致
OPENROUTER_API_KEY 是否正确
3. 快速评测 terminal agent:用 TBLite
跑通最小环境后,可以用 TBLite 做轻量 benchmark。
TBLite 是 Terminal-Bench 2 的更轻量代理集:
text
数据集:NousResearch/openthoughts-tblite
任务数:100
用途:快速观察 terminal agent 能力
特点:比 Terminal-Bench 2 更适合迭代和调试
3.1 准备项
你需要:
text
OPENROUTER_API_KEY
Modal setup
HuggingFace dataset 可访问
可选 WANDB_API_KEY,如果 use_wandb=true
如果没有 WandB:
bash
--env.use_wandb false
3.2 先跑两个任务
第一次不要全量跑。先用 task_filter:
bash
python environments/benchmarks/tblite/tblite_env.py evaluate \
--config environments/benchmarks/tblite/default.yaml \
--openai.model_name anthropic/claude-sonnet-4 \
--env.task_filter "broken-python,pandas-etl" \
--env.max_concurrent_tasks 2 \
--env.use_wandb false
你要确认:
text
任务能加载
Modal sandbox 能创建
模型能调用 terminal/file
test.sh 能运行
结果能输出 PASS / FAIL
3.3 全量评测命令
bash
python environments/benchmarks/tblite/tblite_env.py evaluate \
--config environments/benchmarks/tblite/default.yaml \
--openai.model_name anthropic/claude-sonnet-4 \
--env.use_wandb false
3.4 背后的实现:TBLite 复用 TerminalBench2EvalEnv
TBLiteEvalEnv 继承 TerminalBench2EvalEnv。它主要改了默认 dataset 和 timeout:
text
dataset_name = NousResearch/openthoughts-tblite
task_timeout = 1200
评测逻辑复用 Terminal-Bench 2:
text
加载 HuggingFace dataset
↓
每个 task 解析 docker_image / environment_tar
↓
为 task_id 注册 sandbox 镜像 override
↓
运行 HermesAgentLoop
↓
rollout 结束后上传 tests
↓
执行 test.sh
↓
读取 /logs/verifier/reward.txt
↓
汇总 pass rate
跑完看:
text
Overall Pass Rate
Category Breakdown
Task Results
messages
error
turns_used
如果任务失败,要优先看 messages:
text
模型有没有调用工具?
命令输出是什么?
有没有 JSON 参数错误?
有没有超时?
最终是不是没跑完?
4. 正式 benchmark:Terminal-Bench 2
Terminal-Bench 2 更正式,也更重。它适合比较模型能力,不适合第一次上手。
默认配置大致是:
text
dataset: NousResearch/terminal-bench-2
terminal_backend: modal
max_agent_turns: 60
task_timeout: 1800 秒
max_concurrent_tasks: 8
4.1 先跑少量任务
bash
python environments/benchmarks/terminalbench_2/terminalbench2_env.py evaluate \
--config environments/benchmarks/terminalbench_2/default.yaml \
--openai.model_name anthropic/claude-sonnet-4 \
--env.task_filter fix-git,git-multibranch \
--env.max_concurrent_tasks 2 \
--env.use_wandb false
4.2 全量评测
bash
python environments/benchmarks/terminalbench_2/terminalbench2_env.py evaluate \
--config environments/benchmarks/terminalbench_2/default.yaml \
--openai.model_name anthropic/claude-sonnet-4
如果没有 WandB:
bash
python environments/benchmarks/terminalbench_2/terminalbench2_env.py evaluate \
--config environments/benchmarks/terminalbench_2/default.yaml \
--openai.model_name anthropic/claude-sonnet-4 \
--env.use_wandb false
4.3 数据长什么样
你不需要自己写数据,它从 HuggingFace 下载。每条 item 大致包含:
json
{
"task_name": "fix-git",
"category": "git",
"instruction": "Natural language task for the model",
"docker_image": "prebuilt image",
"environment_tar": "optional base64 tar",
"tests_tar": "base64 tar of tests",
"test_sh": "bash script that writes /logs/verifier/reward.txt"
}
模型只看到 instruction。测试文件在模型完成后才上传。
4.4 背后的实现:为什么测试后上传
TerminalBench2EvalEnv.rollout_and_score_eval() 的关键步骤是:
text
1. 为任务解析 docker image
2. register_task_env_overrides(task_id, ...)
3. 用 HermesAgentLoop 让模型解决 instruction
4. 创建 ToolContext(task_id)
5. 上传 tests_tar 和 test_sh
6. 运行 bash /tests/test.sh
7. 下载 /logs/verifier
8. 读取 reward.txt
9. 清理 sandbox 和临时目录
这样设计是为了减少 reward 投机:
text
如果测试文件一开始就在 sandbox 里,模型可能修改测试。
如果 rollout 后才上传 tests,模型只能根据 instruction 完成任务。
相关实现说明 / Eval Environment Description
英文原文:
text
This is an eval-only environment (not a training environment). It is designed to
be run via the `evaluate` subcommand:
The evaluate flow:
1. setup() -- Loads the TB2 dataset from HuggingFace
2. evaluate() -- Iterates over all tasks, running each through:
a. rollout_and_score_eval() -- Per-task agent loop + test verification
- Resolves Docker image (pre-built Hub image or Dockerfile fallback)
- Registers per-task Modal sandbox via register_task_env_overrides()
- Runs the HermesAgentLoop (terminal + file tools)
- Uploads test suite and runs test.sh in the same sandbox
- Returns binary pass/fail result
b. Aggregates per-task, per-category, and overall pass rates
c. Logs results via evaluate_log() and wandb
中文对照:
text
这是一个只用于评测的环境,不是训练环境。它设计为通过 `evaluate` 子命令运行。
评测流程:
1. setup():从 HuggingFace 加载 TB2 数据集。
2. evaluate():遍历所有任务,每个任务执行:
a. rollout_and_score_eval():单任务 agent loop + 测试验证。
- 解析 Docker image,优先使用预构建 Hub image,否则回退到 Dockerfile。
- 通过 register_task_env_overrides() 注册每任务 Modal sandbox。
- 运行 HermesAgentLoop(terminal + file 工具)。
- 上传测试套件,并在同一个 sandbox 中运行 test.sh。
- 返回二元 pass/fail 结果。
b. 汇总每任务、每 category 和整体 pass rate。
c. 通过 evaluate_log() 和 wandb 记录结果。
5. 代码修复类任务:HermesSweEnv
HermesSweEnv 用来表达这类场景:
text
给模型一个代码任务
模型用 terminal/file/web 工具修改代码
reward 用测试判断是否修好
5.1 使用已有 HuggingFace dataset
默认配置:
text
dataset_name: bigcode/humanevalpack
dataset_split: test
prompt_field: prompt
先用 process 跑少量样本:
bash
python environments/hermes_swe_env/hermes_swe_env.py process \
--config environments/hermes_swe_env/default.yaml \
--openai.base_url https://openrouter.ai/api/v1 \
--openai.api_key "$OPENROUTER_API_KEY" \
--openai.model_name anthropic/claude-sonnet-4 \
--openai.server_type openai \
--env.terminal_backend local \
--env.total_steps 3 \
--env.group_size 2 \
--env.use_wandb false \
--env.data_path_to_save_groups hermes_swe_sample.jsonl
5.2 数据字段要求
默认至少需要:
json
{
"prompt": "Write a Python function add(a, b) that returns a + b.",
"test": "from solution import add\nassert add(2, 3) == 5"
}
实际读取逻辑:
text
prompt_field 指定任务字段,默认 prompt
test / test_code / tests 作为测试字段
模型看到的 user prompt 会是:
text
原始 prompt
Tests to pass:
测试内容
5.3 模型看到的 system prompt
相关提示词 / System Prompt
英文原文:
text
You are a skilled software engineer. You have access to a terminal, file tools, and web search. Use these tools to complete the coding task. Write clean, working code and verify it runs correctly before finishing.
中文对照:
text
你是一名熟练的软件工程师。你可以使用 terminal、file tools 和 web search。使用这些工具完成编码任务。编写干净、可运行的代码,并在结束前验证它能正确运行。
这段 prompt 让模型倾向于读代码、改代码、验证运行。工具能力来自:
yaml
enabled_toolsets: ["terminal", "file", "web"]
5.4 默认 reward 怎么算
默认 compute_reward():
text
如果有 test/test_code/tests:
cd /workspace && python3 -c "<test_code>"
exit_code == 0 → reward = 1.0
否则:
查找模型是否创建过 .py 文件
有 → reward = 0.1
无 → reward = 0.0
真实代码修复任务通常要自定义:
text
安装依赖
运行项目测试
隐藏测试
lint / typecheck
限制可修改文件
防止模型修改测试
6. 核心实现一:HermesAgentBaseEnv 怎么把任务变成 ScoredDataItem
现在看实现主干。
HermesAgentBaseEnv 继承 Atropos 的 BaseEnv,是 Hermes 和 Atropos 之间的适配层。它负责:
text
设置 terminal backend
解析 Hermes toolsets
构造 messages
运行 HermesAgentLoop
创建 ToolContext
调用 compute_reward
生成 ScoredDataItem
处理 Phase 1 / Phase 2
6.1 Environment 子类必须实现什么
相关实现说明 / Base Env Contract
英文原文:
text
Subclasses must implement:
setup() -- Load dataset, initialize state
get_next_item() -- Return the next item to roll out
format_prompt() -- Convert a dataset item into the user message string
compute_reward() -- Score the rollout using ToolContext
evaluate() -- Periodic evaluation
中文对照:
text
子类必须实现:
setup():加载数据集,初始化状态。
get_next_item():返回下一个要 rollout 的 item。
format_prompt():把 dataset item 转成用户消息字符串。
compute_reward():使用 ToolContext 给 rollout 打分。
evaluate():周期性评测逻辑。
这五个方法对应五个设计问题:
text
setup:题库从哪里来?
get_next_item:下一道题怎么取?
format_prompt:题目怎么说给模型听?
compute_reward:怎么自动判卷?
evaluate:怎么汇总整批题的结果?
6.2 collect_trajectory 的完整流程
一次 rollout 在 collect_trajectory() 里可以理解成:
text
1. 生成 task_id
2. 解析本组可用工具
3. 构造初始 messages
- system prompt,如果 config.system_prompt 存在
- user prompt,由 format_prompt(item) 生成
4. 判断 Phase 1 / Phase 2
5. 创建 HermesAgentLoop
6. 调用 agent.run(messages)
7. 如果模型没有产生有效输出,reward = 0.0
8. 否则创建 ToolContext(task_id)
9. 调用 compute_reward(item, result, ctx)
10. cleanup sandbox/browser/background processes
11. 根据 ManagedServer state 构造真实 tokens/masks,或在 Phase 1 生成 placeholder tokens
12. 把 result.messages 放入 scored_item["messages"]
13. 返回 ScoredDataItem
这个设计把"做题过程"和"判卷过程"绑定到同一个 task_id,让 verifier 能看到模型实际造成的环境状态。
7. 核心实现二:HermesAgentLoop 怎么跑多轮工具调用
HermesAgentLoop 是 environment 里的轻量 tool loop,不是完整聊天版 AIAgent。
相关实现说明 / Agent Loop Description
英文原文:
text
Runs hermes-agent's tool-calling loop using standard OpenAI-spec tool calling.
Same pattern as run_agent.py:
- Pass tools= to the API
- Check response.choices[0].message.tool_calls
- Dispatch via handle_function_call()
中文对照:
text
使用标准 OpenAI 风格 tool calling 运行 Hermes Agent 的工具调用循环。
模式和 run_agent.py 相同:
- 调 API 时传入 tools=
- 检查 response.choices[0].message.tool_calls
- 通过 handle_function_call() 分发执行
7.1 一轮 tool loop 做什么
每一轮:
text
server.chat_completion(messages=messages, tools=tool_schemas)
↓
提取 assistant message 和 reasoning
↓
如果有 tool_calls:
规范化 tool call 格式
校验 tool_name 是否在 valid_tool_names
JSON parse arguments
handle_function_call(tool_name, args, task_id)
maybe_persist_tool_result()
把 role=tool 的结果追加到 messages
继续下一轮
如果没有 tool_calls:
把 assistant final content 追加到 messages
finished_naturally = True
返回 AgentResult
如果达到 max_agent_turns 仍未结束:
text
finished_naturally = False
返回当前 AgentResult
7.2 工具调用错误如何进入 trajectory
如果模型调用未知工具:
json
{
"error": "Unknown tool 'xxx'. Available tools: [...]"
}
如果 arguments 不是合法 JSON:
json
{
"error": "Invalid JSON in tool arguments: ... Please retry with valid JSON."
}
这些错误会进入 messages,也会记录到 tool_errors,再由环境写入 WandB 指标或 JSONL。这样你能分析模型失败是因为不会做任务,还是工具调用格式错误。
7.3 为什么工具执行要进线程池
Docker、Modal、Daytona 等 backend 内部可能使用 asyncio.run()。Atropos 自己也在 asyncio event loop 里运行。如果直接嵌套,容易死锁或报错。
Hermes 的做法是:
text
把同步工具调用放进 ThreadPoolExecutor
每个工具调用在单独线程里执行
让后端拥有干净的 event loop
tool_pool_size 控制线程池大小。评测并发高时,如果太小会排队甚至看起来像卡住。
8. 核心实现三:ToolContext 为什么能验证同一个环境
普通评测最大的风险是 verifier 看不到模型刚才做过的事。
Hermes 用 task_id 解决:
text
collect_trajectory 生成 task_id=A
↓
HermesAgentLoop 执行工具时传 task_id=A
↓
terminal/browser/file 工具状态都归属 A
↓
reward 阶段创建 ToolContext(A)
↓
ctx.terminal / ctx.read_file / ctx.browser_snapshot 进入同一个环境 A
ToolContext 提供:
text
terminal(command, timeout)
read_file(path)
write_file(path, content)
upload_file / upload_dir
download_file / download_dir
web_search / web_extract
browser_navigate / browser_snapshot
call_tool(name, args)
cleanup()
这就是为什么 compute_reward() 可以真实检查:
text
文件是否存在
测试是否通过
浏览器状态是否正确
verifier 日志是否写出 reward.txt
9. 命令模式:process / evaluate / serve 怎么选
| 命令 | 用途 | 是否适合第一次 | 典型输出 |
|---|---|---|---|
process |
跑一些 rollout,保存 JSONL,适合数据生成和调试 | 是 | output.jsonl |
evaluate |
跑 benchmark,汇总 pass rate 和 samples | 是,但先小任务 | eval metrics、samples、logs |
serve |
接 Atropos 训练/服务流程 | 否 | 训练过程、WandB、server 交互 |
推荐:
text
第一次:process
要跑 benchmark:evaluate
要训练:serve
9.1 process 输出是什么
process 常见命令:
bash
python <env_file.py> process \
--config <env_config.yaml> \
--env.total_steps 10 \
--env.group_size 4 \
--env.data_path_to_save_groups output.jsonl
输出 JSONL 里最重要的是:
text
messages:完整工具调用轨迹
scores:reward
tokens/masks:训练管线需要的字段
如果你做 SFT 数据生成,通常筛选:
text
只保留 score 高的轨迹
去掉工具错误太多的样本
检查 tool arguments 是否合法
保留代表目标能力的任务类型
9.2 evaluate 输出是什么
evaluate 用于 benchmark:
bash
python environments/benchmarks/tblite/tblite_env.py evaluate \
--config environments/benchmarks/tblite/default.yaml \
--env.task_filter "broken-python,pandas-etl" \
--env.use_wandb false
你会看到:
text
Overall Pass Rate
Category Breakdown
Task Results
并保存 samples / logs。样本中通常包含:
text
task_name
category
passed
reward
turns_used
messages
error
9.3 serve 用在什么时候
serve 更接近训练流程,需要 Atropos 相关服务:
bash
run-api
另一个终端:
bash
python environments/terminal_test_env/terminal_test_env.py serve \
--config environments/terminal_test_env/default.yaml
如果你只是学习或调试 environment,不建议先用 serve。
10. Phase 1 / Phase 2:为什么评测和完整 RL 不一样
这部分最容易被忽略,但对理解实现边界很重要。
10.1 Phase 1:OpenAI Server,适合评测和 SFT 数据生成
相关实现说明 / Phase 1 Description
英文原文:
text
Phase 1: OpenAI Server (Evaluation / SFT Data Generation)
Uses `server.chat_completion()` with `tools=` parameter. The server (VLLM, SGLang, OpenRouter, OpenAI) handles tool call parsing natively. Returns `ChatCompletion` objects with structured `tool_calls`.
- Good for: evaluation, SFT data generation, testing
- Run with: `serve` (with `run-api`), `process`, or `evaluate` subcommands
- Placeholder tokens are created for the Atropos pipeline
中文对照:
text
Phase 1:OpenAI Server(评测 / SFT 数据生成)
使用带 `tools=` 参数的 `server.chat_completion()`。服务器端(VLLM、SGLang、OpenRouter、OpenAI)负责原生解析 tool call,返回包含结构化 `tool_calls` 的 ChatCompletion 对象。
- 适合:评测、SFT 数据生成、测试。
- 运行方式:`serve`(配合 run-api)、`process` 或 `evaluate` 子命令。
- 会为 Atropos pipeline 创建占位 tokens。
Phase 1 可以评测、可以保存 messages、可以生成 JSONL,但没有真实 RL 所需的精确 token/logprob。Hermes 会创建 placeholder tokens,让数据管线不断,但这不等于可以直接做完整 RL 训练。
10.2 Phase 2:ManagedServer,适合完整 RL training
相关实现说明 / Phase 2 Description
英文原文:
text
Phase 2: VLLM ManagedServer (Full RL Training)
Uses ManagedServer for exact token IDs + logprobs via `/generate`. Client-side tool call parser (from `tool_call_parsers/`) reconstructs structured `tool_calls` from raw output.
- Good for: full RL training with GRPO/PPO
- Run with: `serve` subcommand
- Real tokens, masks, and logprobs flow through the pipeline
中文对照:
text
Phase 2:VLLM ManagedServer(完整 RL 训练)
通过 `/generate` 使用 ManagedServer 获得精确 token IDs 和 logprobs。客户端 tool call parser(来自 `tool_call_parsers/`)从原始输出文本中重建结构化 `tool_calls`。
- 适合:使用 GRPO/PPO 的完整 RL 训练。
- 运行方式:`serve` 子命令。
- 真实 tokens、masks 和 logprobs 会进入训练 pipeline。
10.3 为什么 Phase 2 需要 tool call parser
Phase 1 服务端直接返回结构化 tool call:
json
{
"tool_calls": [
{
"function": {
"name": "terminal",
"arguments": "{\"command\":\"ls\"}"
}
}
]
}
Phase 2 的 /generate 更可能返回原始文本:
text
<tool_call>{"name": "terminal", "arguments": {"command": "ls"}}</tool_call>
所以 Hermes 需要 parser 把原始文本还原成结构化 tool call。
相关实现说明 / Parser Description
英文原文:
text
Client-side parsers that extract structured tool_calls from raw model output text.
Used in Phase 2 (VLLM server type) where ManagedServer's /generate endpoint returns
raw text without tool call parsing.
中文对照:
text
客户端 parser 用来从模型原始输出文本中提取结构化 tool_calls。
它用于 Phase 2(VLLM server type),因为 ManagedServer 的 /generate endpoint 返回的是未解析 tool call 的原始文本。
11. 聊天里的 rl_* 工具:训练管理,不是 rollout 本身
如果你在普通 Hermes 聊天里启用了 rl toolset,模型可以调用 rl_* 工具管理训练。
这组工具的用途是:
text
列出训练环境
选择环境
查看/修改配置
做 inference smoke test
启动训练
检查状态
停止训练
获取结果
它不是被训练模型在 rollout 中使用的工具。
11.1 使用前准备
需要:
text
TINKER_API_KEY
WANDB_API_KEY
Python >= 3.11
RL 依赖 .[rl]
相关配置说明 / RL Training Keys
英文原文:
text
Tinker API Key - RL training service
Get at: https://tinker-console.thinkingmachines.ai/keys
Weights & Biases API Key - Experiment tracking and metrics
Get at: https://wandb.ai/authorize
中文对照:
text
Tinker API Key:RL training service 使用的密钥。
获取地址:https://tinker-console.thinkingmachines.ai/keys
Weights & Biases API Key:实验追踪和指标记录使用的密钥。
获取地址:https://wandb.ai/authorize
11.2 模型看到的关键工具描述
相关提示词 / Tool Description
英文原文:
text
rl_test_inference: Quick inference test for any environment. Runs a few steps of inference + scoring using OpenRouter. Default: 3 steps x 16 completions = 48 rollouts per model, testing 3 models = 144 total. Tests environment loading, prompt construction, inference parsing, and verifier logic. Use BEFORE training to catch issues.
rl_start_training: Start a new RL training run with the current environment and config. Most training parameters (lora_rank, learning_rate, etc.) are fixed. Use rl_edit_config() to set group_size, batch_size, wandb_project before starting. WARNING: Training takes hours.
rl_check_status: Get status and metrics for a training run. RATE LIMITED: enforces 30-minute minimum between checks for the same run. Returns WandB metrics: step, state, reward_mean, loss, percent_correct.
中文对照:
text
rl_test_inference:对任意环境做快速 inference test。通过 OpenRouter 跑少量 inference + scoring。默认 3 steps x 16 completions = 每个模型 48 rollouts,测试 3 个模型共 144 个 rollouts。用于验证环境加载、prompt 构造、inference parsing 和 verifier 逻辑。训练前应先使用。
rl_start_training:用当前环境和配置启动新的 RL training run。多数训练参数(lora_rank、learning_rate 等)固定。启动前用 rl_edit_config() 设置 group_size、batch_size、wandb_project。警告:训练需要数小时。
rl_check_status:获取 training run 的状态和指标。有限流:同一个 run 至少间隔 30 分钟检查一次。返回 WandB 指标:step、state、reward_mean、loss、percent_correct。
这些描述会引导模型按顺序操作:
text
rl_list_environments
↓
rl_select_environment
↓
rl_get_current_config
↓
rl_edit_config
↓
rl_test_inference
↓
rl_start_training
↓
rl_check_status / rl_stop_training / rl_get_results
11.3 rl_* 和 environments/ 的边界
一定要分清:
text
hermes-agent/environments/
是 Hermes 自己的 RL/eval environment 实现。
它定义任务怎么跑、tool loop 怎么执行、reward 怎么算。
tools/rl_training_tool.py
是聊天 agent 的训练管理工具。
当前扫描的是 tinker-atropos/tinker_atropos/environments。
如果你只是学习 Hermes eval 环境,直接跑:
bash
python environments/.../xxx_env.py process
python environments/.../xxx_env.py evaluate
更直观。
如果你要让 Hermes 聊天 agent 帮你管理 Tinker-Atropos 训练,才重点看 rl_*。
12. 结果大小、并发和超时:为什么环境不会无限爆炸
RL / Eval 环境会批量运行模型和工具,比普通聊天更容易爆资源。
12.1 工具输出太大怎么办
工具输出可能非常大:
text
pytest -vv
npm install
cat 大文件
browser snapshot
Hermes 在 HermesAgentLoop 里调用:
text
maybe_persist_tool_result(...)
enforce_turn_budget(...)
相关配置:
相关配置说明 / Tool Result Budget
英文原文:
text
Default per-tool threshold (chars) for persisting large results to sandbox. Results exceeding this are written to /tmp/hermes-results/ and replaced with a preview. Per-tool registry values take precedence unless overridden via tool_result_overrides.
中文对照:
text
单个工具结果持久化到 sandbox 的默认字符阈值。超过阈值的结果会写入 /tmp/hermes-results/,并在消息里替换成 preview。除非通过 tool_result_overrides 覆盖,否则每个工具在 registry 里的配置优先。
相关配置说明 / Turn Budget
英文原文:
text
Aggregate char budget per assistant turn. If all tool results in a single turn exceed this, the largest are persisted to disk first.
中文对照:
text
每个 assistant turn 的工具结果总字符预算。如果同一轮所有工具结果超过这个预算,会优先把最大的结果持久化到磁盘。
这不是让模型永远看不到大结果,而是把大结果转为:
text
磁盘文件 + inline preview
避免一轮工具输出撑爆 trajectory。
12.2 并发怎么控制
常见参数:
text
group_size:每个 item 生成多少 rollout
tool_pool_size:工具执行线程池大小
max_concurrent_tasks:benchmark 同时跑多少 task
eval_concurrency:eval 并发度
Terminal-Bench 2 默认限制 max_concurrent_tasks=8,因为过多 Modal sandbox 同时创建会导致阻塞或死锁。
12.3 timeout 怎么控制
常见参数:
text
max_agent_turns:最多 LLM 调用多少轮
terminal_timeout:单条 terminal 命令最多运行多久
task_timeout:一个 benchmark task 最多多久
terminal_lifetime:sandbox 空闲多久后清理
如果模型一直调用工具不结束,max_agent_turns 截断。
如果命令卡住,terminal_timeout 杀掉命令。
如果整个任务卡住,task_timeout 记 fail。
13. 跑完怎么判断结果正常
13.1 看 scores / reward
正常结果应该有:
text
scores 存在
reward 不是全部 0
pass rate 和任务难度大致匹配
如果全 0,可能是:
text
模型没调用工具
工具 schema 没传成功
terminal backend 没起来
测试命令失败
reward 路径写错
模型改错位置
13.2 看 messages
重点看:
text
assistant 有没有 tool_calls
tool_calls 的 name 是否在 enabled_toolsets 里
arguments 是否是合法 JSON
tool result 是否有 error
模型是否根据 tool result 继续修正
最终是否自然停止
13.3 看任务级错误
Benchmark 环境常见错误:
text
timeout
no_image
test verification failed
sandbox cleanup error
tool execution failed
unknown tool
invalid JSON arguments
这些错误不一定是模型能力问题,也可能是数据、sandbox、依赖、并发或 verifier 配置问题。
14. 自己写一个 environment:最小设计模板
如果你要做自己的任务集,不要先写复杂框架。先回答五个问题:
text
1. 数据从哪里来?
2. 模型看到什么 prompt?
3. 模型能用哪些工具?
4. reward 怎么自动判断?
5. 环境怎么清理资源?
最小结构:
python
from environments.hermes_base_env import HermesAgentBaseEnv, HermesAgentEnvConfig
class MyEnvConfig(HermesAgentEnvConfig):
pass
class MyEnv(HermesAgentBaseEnv):
name = "my-env"
env_config_cls = MyEnvConfig
async def setup(self):
self.dataset = [...]
self.iter = 0
async def get_next_item(self):
item = self.dataset[self.iter % len(self.dataset)]
self.iter += 1
return item
def format_prompt(self, item):
return item["instruction"]
async def compute_reward(self, item, result, ctx):
test = ctx.terminal("pytest -q", timeout=120)
return 1.0 if test["exit_code"] == 0 else 0.0
async def evaluate(self, *args, **kwargs):
...
if __name__ == "__main__":
MyEnv.cli()
最小数据可以长这样:
json
{
"instruction": "Create /workspace/out.txt with the text hello.",
"expected_path": "/workspace/out.txt",
"expected_content": "hello"
}
对应 reward:
text
ctx.read_file(expected_path)
内容匹配 → 1.0
否则 → 0.0
15. 最短路径总结
如果你现在就想用:
第一步:安装
bash
uv venv venv --python 3.11
source venv/bin/activate
uv pip install -e ".[rl,dev,modal]"
第二步:配置 key
bash
cp .env.example .env
# 填 OPENROUTER_API_KEY
第三步:Modal 认证
bash
modal setup
第四步:跑最小环境
bash
python environments/terminal_test_env/terminal_test_env.py process \
--config environments/terminal_test_env/default.yaml \
--env.use_wandb false \
--env.data_path_to_save_groups terminal_test_output.jsonl
第五步:看输出
bash
head -n 1 terminal_test_output.jsonl
你要看到:
text
有 scores
有 messages
messages 里有 tool_calls
reward 能反映任务成功/失败
第六步:跑小 benchmark
bash
python environments/benchmarks/tblite/tblite_env.py evaluate \
--config environments/benchmarks/tblite/default.yaml \
--env.task_filter "broken-python,pandas-etl" \
--env.max_concurrent_tasks 2 \
--env.use_wandb false
再往后才考虑:
text
Terminal-Bench 2 全量评测
HermesSweEnv 代码任务
自定义 environment
SFT trajectory 生成
完整 RL training
最终可以这样理解 Hermes 的 RL / Evaluation Environment:
text
它不是聊天功能。
它是一套把 agent 放进自动考场的实验系统。
使用上,它提供 process / evaluate / serve 三种运行模式。
实现上,它用 HermesAgentBaseEnv 管环境,
用 HermesAgentLoop 跑工具调用,
用 ToolContext 在同一个 sandbox 中判分,
用 ScoredDataItem 把 trajectory + reward 交给 Atropos。