Appearance
Hermes 的 Atropos 集成解决了一个核心问题:传统 RL 训练只能验证"答案对不对",但对 Agent 来说更重要的是"工具调用的结果对不对"。Hermes 把整个工具调用系统(终端执行、文件读写、网页搜索、浏览器自动化)接入 Atropos 训练循环,让奖励函数能直接在模型用过的 sandbox 环境里运行测试、验证文件、执行命令——这是真实 Agent 能力评估,不是猜答案。
Hermes Agent Atropos RL 训练集成:把工具调用加入强化学习训练循环
为什么需要工具调用 RL
标准 RL 训练(如 GRPO/PPO)对 AI 助手的训练信号来自固定答案对比:模型输出 → 和正确答案比较 → 得分。这对数学题有效,但对 Agent 类任务失效:
- "完成这个编程任务"没有固定"正确答案"
- 模型可能走错路但最终代码可以运行
- 需要执行代码才能知道对不对
Hermes 的解法:把工具执行环境引入奖励函数——模型用终端执行了哪些命令、创建了哪些文件,奖励函数可以在相同 sandbox 里继续用这些工具做验证。
架构总览
Atropos 框架 (atroposlib)
└── BaseEnv(Server 管理、Worker 调度、Wandb 日志)
└── HermesAgentBaseEnv(hermes_base_env.py)
│ ├── Terminal 后端配置
│ ├── 工具集分配(per-group)
│ ├── 代理循环执行(HermesAgentLoop)
│ └── ToolContext(奖励函数工具访问)
│
├── TerminalTestEnv(堆栈验证)
├── HermesSweEnv(SWE-bench 风格训练)
└── benchmarks/
├── TerminalBench2EvalEnv(89 个终端任务)
├── TBLiteEnv(100 个快速任务)
└── YCBenchEnv(长期战略任务)两阶段操作模式
Hermes 的 Atropos 集成支持两种运行模式,适用于不同目的:
Phase 1 — OpenAI 服务器模式(评估 / SFT 数据生成)
使用标准 chat_completions API,服务器(VLLM/SGLang/OpenRouter/OpenAI)原生处理工具调用解析,返回结构化的 tool_calls 对象。
model → /v1/chat/completions (tools=) → server → tool_calls → 执行 → 下一轮适用场景:评估模型能力、生成 SFT 训练数据、用 OpenRouter 跑现有模型。
Phase 2 — VLLM ManagedServer(完整 RL 训练)
使用 ManagedServer 的 /generate 端点获取原始 token + logprobs,客户端侧工具调用解析器(tool_call_parsers/)从原始文本重建结构化 tool_calls。
model → /generate (raw tokens) → client-side parser → tool_calls → 执行 → 下一轮
↓
tokens/masks/logprobs → GRPO/PPO适用场景:完整 RL 训练,需要精确 token 序列和 logprobs。
不用在代码里选择阶段:HermesAgentBaseEnv._use_managed_server() 自动检测——如果挂的是 VLLM 服务器就用 Phase 2,否则用 Phase 1。
工具调用解析器
Phase 2 需要客户端侧解析器,Hermes 内置了 10+ 种主流模型的解析器:
| 解析器 | 格式 | 适用模型 |
|---|---|---|
hermes | ChatML <tool_call> XML | NousResearch Hermes 系列 |
mistral | [TOOL_CALLS] | Mistral 系列 |
llama3_json | JSON tool calling | Llama 3 系列 |
qwen / qwen3_coder | Qwen 格式 | 通义千问系列 |
deepseek_v3 / deepseek_v3_1 | DeepSeek 格式 | DeepSeek 系列 |
kimi_k2 | Kimi K2 格式 | 月之暗面 Kimi |
glm45 / glm47 | GLM 格式 | 智谱 GLM 系列 |
配置(在 HermesAgentEnvConfig 里):
python
tool_call_parser: str = "hermes" # 或 "qwen3_coder", "deepseek_v3_1" 等核心组件详解
HermesAgentLoop — 可复用多轮代理引擎
HermesAgentLoop 和 Hermes CLI 里的 run_agent.py 是同一套逻辑的 RL 版:
python
loop = HermesAgentLoop(
server=managed,
tool_schemas=tools, # OpenAI 格式工具定义
valid_tool_names=valid_names, # 允许调用的工具名集合
max_turns=30, # 最多 30 轮 LLM 调用
task_id=task_id, # 终端/浏览器会话隔离 ID
temperature=1.0, # RL 训练推荐 temperature=1.0
budget_config=budget_cfg, # 工具输出大小预算
)
result: AgentResult = await loop.run(messages)AgentResult 包含:
messages:完整对话历史(OpenAI 格式)turns_used:实际用了多少轮 LLM 调用finished_naturally:模型自然停止(vs 撞上 max_turns)reasoning_per_turn:每轮的推理过程(支持 extended thinking)tool_errors:工具执行错误记录(用于 wandb 日志)managed_state:Phase 2 的 token/logprobs 数据
工具调用在独立线程池里执行(run_in_executor),避免使用 asyncio.run() 的工具(Modal、Docker 后端)在 Atropos 事件循环里死锁。
ToolContext — 奖励函数的工具访问接口
ToolContext 是 RL 训练里最关键的设计:让奖励函数能在和模型相同的 sandbox里执行任意工具。
python
async def compute_reward(self, item, result, ctx: ToolContext) -> float:
# 在模型用过的终端里跑测试
test_result = ctx.terminal("pytest tests/ -v")
if test_result["exit_code"] == 0:
return 1.0
# 检查模型是否创建了预期文件
file = ctx.read_file("/workspace/solution.py")
if file.get("content") and "def solve(" in file["content"]:
return 0.5
# 从 sandbox 下载文件到本地做二进制验证
ctx.download_file("/remote/output.bin", "/local/output.bin")
# ...本地验证逻辑...
return 0.0ctx 可用的方法:
| 方法 | 功能 |
|---|---|
terminal(cmd, timeout) | 在 sandbox 里执行 shell 命令 |
read_file(path) | 读取文件内容 |
write_file(path, content) | 写入文件 |
search(query, path) | 文件内容搜索 |
upload_file/dir() | 上传文件到 sandbox |
download_file/dir() | 从 sandbox 下载文件 |
web_search(query) | 执行网络搜索 |
web_extract(urls) | 抓取网页内容 |
browser_navigate(url) | 浏览器导航 |
browser_snapshot() | 截取浏览器状态 |
call_tool(name, args) | 调用任意工具 |
cleanup() | 释放 sandbox 资源 |
关键设计:task_id 是模型 rollout 和 ToolContext 共享的唯一标识符,保证它们操作同一个 sandbox——模型创建的文件、跑过的进程,都对奖励函数可见。
工具集分配——每个 Group 独立采样
在 Atropos 训练中,一个 Group 包含多个并行 rollout。Hermes 在 Group 级别(不是 rollout 级别)解析工具集,所有 rollout 共享同一组工具:
python
async def collect_trajectories(self, item):
# Group 开始时解析一次工具集
self._current_group_tools = self._resolve_tools_for_group()
# 所有并行 rollout 共用
return await super().collect_trajectories(item)工具集解析策略:
python
# 明确指定
enabled_toolsets=["terminal", "file", "web"]
# 概率采样(training diversity)
distribution="development" # 每个 Group 随机从 distribution 配置里采样Distribution 让不同 Group 训练不同工具组合,防止模型只学某几个工具的用法。
内置环境示例
TerminalTestEnv — 堆栈验证
最简单的环境,内置任务,不需要外部数据集:
bash
# 验证整个工具调用链是否工作
run-api
python environments/terminal_test_env/terminal_test_env.py serve每个任务要求模型在特定路径创建文件,奖励函数读文件验证内容。用来确认"从 API 调用到 sandbox 执行到奖励计算"全链路通畅。
HermesSweEnv — SWE-bench 风格训练
bash
python environments/hermes_swe_env/hermes_swe_env.py serve \
--openai.model_name YourModel \
--env.dataset_name bigcode/humanevalpack \
--env.terminal_backend modal \ # 生产环境用 Modal 隔离
--env.max_agent_turns 30模型收到编程任务,用 terminal/file/web 工具完成,奖励函数在相同 sandbox 运行测试套件。
TerminalBench2EvalEnv — 89 任务 Terminal 基准测试
bash
# 完整跑 89 个任务
python environments/benchmarks/terminalbench_2/terminalbench2_env.py evaluate \
--openai.model_name anthropic/claude-opus-4.6
# 只跑特定任务(调试用)
python environments/benchmarks/terminalbench_2/terminalbench2_env.py evaluate \
--openai.model_name anthropic/claude-opus-4.6 \
--env.task_filter fix-git,git-multibranch
# 跳过特定任务
python environments/benchmarks/terminalbench_2/terminalbench2_env.py evaluate \
--env.skip_tasks heavy-task,slow-task每个任务有预构建的 Docker 镜像、自然语言指令和测试套件。验证结果会下载到本地后计算奖励(避免沙箱内网络访问不稳定)。
自定义训练环境
只需要继承 HermesAgentBaseEnv 并实现 4 个方法:
python
from environments.hermes_base_env import HermesAgentBaseEnv, HermesAgentEnvConfig
class MyEnvConfig(HermesAgentEnvConfig):
# 继承所有标准配置字段
# 可以加自定义字段
pass
class MyEnv(HermesAgentBaseEnv):
name = "my-env"
env_config_cls = MyEnvConfig
@classmethod
def config_init(cls):
# 返回 (env_config, server_configs) 元组
env_config = MyEnvConfig(
enabled_toolsets=["terminal", "file"],
terminal_backend="modal", # 生产环境用 modal/daytona
max_agent_turns=25,
agent_temperature=1.0, # RL 训练保持 1.0
)
server_configs = [APIServerConfig(
base_url="http://localhost:8000/v1",
model="YourModel",
)]
return env_config, server_configs
async def setup(self):
# 加载数据集
self.dataset = load_dataset("your-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):
# 把数据集条目转成 user message
return f"请完成以下任务:{item['task_description']}"
async def compute_reward(self, item, result, ctx: ToolContext) -> float:
# 核心:用 ToolContext 验证结果
output = ctx.terminal("python solution.py")
if output["exit_code"] == 0 and item["expected_output"] in output["stdout"]:
return 1.0
elif output["exit_code"] == 0:
return 0.3 # 运行了但结果不对
return 0.0
async def evaluate(self, *args, **kwargs):
# 定期评估逻辑
pass
if __name__ == "__main__":
MyEnv.cli()运行:
bash
# Phase 1:OpenAI 服务器
python my_env.py serve --openai.model_name anthropic/claude-opus-4.6
# Phase 2:VLLM RL 训练
run-api # 启动 VLLM ManagedServer
python my_env.py serve关键配置参数
| 参数 | 说明 | 推荐值 |
|---|---|---|
terminal_backend | 沙箱后端:local/docker/modal/daytona/ssh/singularity | modal(生产) |
max_agent_turns | 每次 rollout 最多 LLM 调用次数 | 20~30 |
agent_temperature | 采样温度 | 1.0(RL 训练) |
tool_pool_size | 工具执行线程池大小 | ≥ 并发 rollout 数 |
distribution | 工具集分布名(概率采样多样性) | "development" |
tool_call_parser | Phase 2 工具调用解析器名 | 按模型选 |
terminal_timeout | 单条命令超时(秒) | 120(编译任务更长) |
default_result_size_chars | 工具输出裁剪阈值 | 50000 |
tool_pool_size 是个容易忽视的参数:89 个并发 TB2 评估任务各需一个线程做工具调用,池子太小会导致任务排队等线程,看起来像"模型在思考"其实是在等 IO。
FAQ
Q: Hermes 的 Atropos 集成和 verl、RLVR 这些框架有什么不同?
verl 等框架解决的是"奖励计算"问题(给定模型输出,计算分数),Hermes 解决的是"工具调用验证"问题——模型在 rollout 里用了哪些工具、工具执行结果如何,奖励函数可以访问同一个环境来验证。两者互补,Hermes 的 ToolContext 可以作为 verl/Atropos 的奖励函数后端。
Q: Modal 后端和 local 后端有什么区别?
local 后端直接在当前机器执行命令,多个并发 rollout 共享同一个文件系统,容易互相干扰。Modal 后端每个 rollout 启动独立的云容器,文件系统完全隔离,训练数据更干净。terminal_lifetime 参数控制容器空闲多久后销毁(默认 1 小时)。
Q: HermesAgentLoop 和 CLI 里的 run_agent.py 有什么区别?
功能上相同(都是多轮工具调用循环),但 HermesAgentLoop 是 async 的,适合 Atropos 的 asyncio 事件循环,而 run_agent.py 是 sync 的,适合 CLI 交互场景。两者共享 handle_function_call() 工具分发逻辑。
Q: 能在 RL 训练时使用 Hermes 的 Skills 系统吗?
可以,通过 enabled_toolsets 包含 skills 工具集,或直接在 tool_schemas 里加入 skill 工具定义。不过 RL 训练时通常更关注核心工具(terminal/file/web),Skills 更多是推理/写作辅助,不常用于 Agent RL 训练。
本系列文章
Provider 与成本优化
能力扩展
- Skills 系统详解:用斜杠命令扩展 AI 能力的完整教程
- 工具系统:内置 30+ 工具全解析与自定义工具开发教程
- 多实例 Profile 隔离:一台机器跑多个完全独立的 AI 助手
- Skin 主题系统:用 YAML 定制 CLI 视觉风格
部署与集成
- 消息网关部署:把 AI 助手接入 Telegram、Discord 和 Slack
- ACP 集成:在 VS Code 和 Zed 编辑器里使用 Hermes
- MCP Server 模式:让 Claude Code 读取你的 Telegram / Discord 消息记录