Hermes Agent RL / Evaluation Environment 使用与实现分析

先说一个最重要的边界:

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 里的 scoresmessages
快速看模型会不会用 terminal/file 工具 TerminalTestEnvTBLite 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,不要先用 serveprocess 会直接跑 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。
相关推荐
eastyuxiao1 小时前
第六章 AI+数字孪生融合技术
大数据·人工智能·数字孪生
CS创新实验室1 小时前
OpenAI GPT-5.5 技术深度报告
人工智能·gpt·大模型·llm
dhashdoia1 小时前
2026年深度体验:OpenAI Codex App如何重塑AI辅助编程工作流
人工智能·gpt·深度学习·claude
zhangfeng11332 小时前
CodeBuddy ai对话框上面的git docs terminal Rulds 干嘛用的,以thinkphp fastadmin 为例,插件市场
人工智能·git·编程
dfsj660112 小时前
第六章:炼丹师的内功
人工智能
AIoT科技物语2 小时前
包邮168元!无须编程,AI 驱动,ESP-Claw 物联网 OpenClaw 智能体套件,打通智能家居本地「感知、推理、决策」完整闭环
人工智能·物联网·智能家居
wzl202612132 小时前
从精细化运营视角,基于企销宝实现企微私域提速增效的技术实践
人工智能·自动化·企业微信
云天AI实战派2 小时前
ChatGPT/AI 常见故障排查指南:从 Realtime API、Codex 到智能体的全流程修复手册
人工智能·chatgpt
ptc学习者2 小时前
huggingface下载模型
人工智能