首页 / 资讯中心 / 文章详情

Hermes Agent 中的两套 Agent Loop:从配置骨架到运行验证

Hermes Agent 中的两套 Agent Loop:从配置骨架到运行验证 ★ FEATURED ARTICLE
1. 为什么 Hermes Agent 里会有两套 Agent Loop如果你最近在本地跑 Hermes Agent大概率会在源码里撞见两个名字很像、职责却完全不同的循环体AIAgent和HermesAgentLoop。前者服务 CLI、Gateway、Telegram、Discord 这类真人入口后者被 Atropos 拉起来做 RL rollout。它们都叫 Agent Loop但目标函数根本不是一回事。AIAgent这条链路要兜住的是交互过程本身流式输出、Provider 容错、上下文压缩、用户中断、预算耗尽后的 Grace Call、子 Agent 委派、插件钩子基本都堆在这里。它的复杂度不来自“调模型”那一步而来自调模型失败以后怎么办、用户半路打断怎么办、上下文塞不下了怎么办。所以这个循环体膨胀到数千行它已经不是单纯的推理循环而是一条完整的交互控制链。HermesAgentLoop则完全是另一回事。它不面向用户没有人盯着屏幕也不需要跨 Provider 兜底。训练场景真正看重的是必须是 async 才能并发跑大量 rollout必须拿到真实 token、logprobs、masks 供 GRPO 训练使用必须把工具执行和 reward 验证放在同一个 sandbox 上下文里必须保持循环本身足够轻避免把交互系统里的复杂分支带进训练路径。这篇就按“配置骨架 → 触发条件 → 启动验证 → 报错排查”的顺序把两套 Loop 怎么配、怎么切、怎么确认它真的按预期在跑讲清楚。适合已经在本地跑 AI Agent、准备接 RL 训练链路的开发者。2. 前置准备TaoToken 接入与目录约定在动config.toml之前先把模型侧的通路准备好。Hermes Agent 本身不绑定某一家 Provider但两套 Loop 都需要一个稳定的 chat completion 端点。我本地统一走 TaoToken 的 API原因是它在 OpenAI 兼容格式上比较省心AIAgent的流式和HermesAgentLoop的 async 调用都能直接复用同一套 base_url。先去控制台拿一个 Key地址是 https://taotoken.net/api-keys 创建后复制出来。注意这个 Key 只在创建时完整显示一次丢了就重新建。模型侧的基础信息如下后面config.toml里会直接引用项目值Base URLhttps://taotoken.net/api鉴权方式Bearer TokenHeader: Authorization兼容协议OpenAI Chat Completions控制台https://taotoken.net/console接入文档https://taotoken.net/doc目录上建议这样组织两套 Loop 的配置分开存放避免互相污染hermes-agent/ ├── config/ │ ├── config.toml # 主配置含 AIAgent 段 │ └── settings.json # HermesAgentLoop / rollout 段 ├── logs/ │ ├── aiagent.log │ └── rollout.log └── run/环境变量先导出别把 Key 硬编码进配置文件export TAOTOKEN_API_KEYsk-你的key export TAOTOKEN_BASE_URLhttps://taotoken.net/api注意config.toml里用${TAOTOKEN_API_KEY}这种占位引用Hermes 启动时会做一次环境变量展开。如果你直接写明文记得别把配置文件提交到仓库。3. 可复制配置config.toml 与 settings.json 骨架3.1 config.toml —— AIAgent 交互链路AIAgent段的关键是流式、容错和上下文压缩这三块。下面这份骨架可以直接抄字段名按你本地 Hermes 版本微调[provider] base_url ${TAOTOKEN_BASE_URL} api_key ${TAOTOKEN_API_KEY} model claude-sonnet-4-20250514 timeout 120 [aiagent] # 交互链路面向 CLI / Gateway / Telegram / Discord enable_stream true # 流式输出前台体验依赖它 max_turns 40 # 单次会话最大循环轮数 context_compress_at 0.75 # 上下文占用超过 75% 触发压缩 grace_call_on_budget true # 预算耗尽后补一次 Grace Call provider_fallback [taotoken-primary, taotoken-backup] interrupt_enabled true # 允许用户 CtrlC 打断 subagent_delegate true # 允许子 Agent 委派 plugin_hooks [logging, budget_guard] [aiagent.retry] max_attempts 3 backoff_ms 800 on_empty_response retry # 空响应恢复策略这里几个字段值得单独说。enable_stream打开后AIAgent走的是流式分支和HermesAgentLoop的非流式路径是两条代码。context_compress_at是压缩阈值设太低会频繁压缩拖慢响应设太高容易撞上下文上限0.7 到 0.8 之间比较稳。grace_call_on_budget是预算耗尽后的兜底调用训练链路里没有这个逻辑。3.2 settings.json —— HermesAgentLoop rollout 链路rollout 段的关键词是 async、token 级数据和 sandbox。它不关心流式也不做 Provider 轮转{ hermes_agent_loop: { mode: rollout, async: true, max_concurrency: 32, capture_logprobs: true, capture_masks: true, sandbox: { enabled: true, reward_in_sandbox: true, tool_context: shared }, loop: { max_steps: 20, stop_on_no_tool_call: true, emit_managed_state: true }, atropos: { endpoint: http://127.0.0.1:8000, batch_size: 16 } } }capture_logprobs和capture_masks必须为 true否则 GRPO 训练拿不到 token 级信号rollout 白跑。reward_in_sandbox保证工具执行和 reward 验证在同一个 sandbox 上下文里完成这是HermesAgentLoop和AIAgent在工具调度层复用的关键点。stop_on_no_tool_call对应 excerpt 里那四步流程的最后一步没有工具调用就认为任务完成退出循环。3.3 两套 Loop 的触发条件与切换方式配置写完后怎么决定跑哪套Hermes 的入口是分开的不是运行时动态切换入口触发的 Loop典型场景hermes chat/ CLIAIAgent本地对话、调试Gateway / Telegram / DiscordAIAgent面向真人的产品入口Atropos rollout 调度HermesAgentLoopRL 训练数据生产benchmark 脚本HermesAgentLoop批量评测也就是说切换不是改一个 flag而是走不同入口。你如果想让交互链路跑 rollout那是用错了入口AIAgent不会产出managed_state和 token 级数据。4. 启动与验证日志和请求回显怎么确认 Loop 在跑4.1 启动 AIAgent 并观察日志hermes chat --config config/config.toml --log-level debug 21 | tee logs/aiagent.log启动后你应该在日志里看到类似这样的行确认走的是交互链路[aiagent] loopAIAgent streamtrue max_turns40 [aiagent] providertaotoken-primary modelclaude-sonnet-4-20250514 [aiagent] context_compress_at0.75 grace_calltrue [aiagent] turn1 - chat_completion(stream)发一句会触发工具调用的话比如让它读一个本地文件。日志里会出现工具执行和结果回填[aiagent] tool_call nameread_file args{path:./README.md} [aiagent] tool_result oktrue bytes2048 [aiagent] turn2 - chat_completion(stream) [aiagent] no_tool_call - finish最后那行no_tool_call - finish就是循环退出的信号和 excerpt 里描述的四步流程一致。4.2 启动 HermesAgentLoop rollout 并验证rollout 一般由 Atropos 拉起本地手动验证可以这样跑python -m hermes.rollout \ --settings config/settings.json \ --dataset ./data/sample.jsonl \ --log logs/rollout.log日志里要重点确认三件事async 并发是否生效、token 级数据是否产出、reward 是否在 sandbox 里算出来。[rollout] loopHermesAgentLoop asynctrue concurrency32 [rollout] item0 format_prompt ok [rollout] item0 run() steps3 tool_calls2 [rollout] item0 managed_state emitted tokens512 logprobstrue maskstrue [rollout] item0 compute_reward in_sandboxtrue reward0.83 [rollout] ScoredDataItem - GRPO trainer看到managed_state emitted和compute_reward in_sandboxtrue说明这条 rollout 链路是通的。如果logprobsfalse回去检查capture_logprobs是不是被覆盖了。4.3 请求回显验证想确认请求真的打到了 TaoToken可以在 debug 日志里看回显的 base_url 和 model[provider] POST https://taotoken.net/api/v1/chat/completions [provider] modelclaude-sonnet-4-20250514 streamtrue [provider] status200 first_token_ms420rollout 侧是非流式回显里streamfalse并且会带logprobs字段。两边回显的 base_url 应该一致都是https://taotoken.net/api。5. 本篇常见错排查5.1 报错managed_state is None这是 rollout 侧最典型的错。原因通常是emit_managed_state没开或者你误用了AIAgent入口跑 rollout。检查settings.json里loop.emit_managed_state是否为 true并确认启动命令走的是hermes.rollout而不是hermes chat。5.2 报错logprobs missing in response训练侧拿不到 logprobs多半是 Provider 侧没返回。先确认capture_logprobstrue再确认请求里带了logprobs和top_logprobs参数。如果走的是流式分支logprobs 可能不完整rollout 必须用非流式。5.3 AIAgent 卡在turnN不退出循环不退出一般是max_turns设太大或者模型一直返回工具调用。先看日志里tool_call是不是在重复同一个工具同一个参数如果是说明工具结果没被正确回填。检查handle_function_call()那一层的返回格式工具结果必须追加回消息列表。5.4 上下文压缩触发过于频繁日志里频繁出现context_compress说明context_compress_at设太低。调到 0.75 到 0.8 之间同时确认压缩后消息列表长度确实下降了而不是压缩完又立刻涨回去。5.5 rollout 并发上不去max_concurrency32但实际只有个位数在跑检查asynctrue是否生效以及 Atropos 的batch_size是否和并发匹配。另外 sandbox 如果串行执行工具也会成为瓶颈tool_contextshared能缓解一部分。6. 继续往下走配置和验证跑通之后下一步通常是把它接进真实的训练或产品链路。如果你还在调交互链路的流式和容错可以先用模型对话入口快速验证模型侧是否正常https://taotoken.net/models 。如果准备长期跑编码类 Agent、需要稳定的额度和并发可以看 Coding Planhttps://taotoken.net/coding-plan 。接入细节和参数说明都在文档里https://taotoken.net/doc Key 管理在控制台https://taotoken.net/api-keys 。我自己的习惯是每次改完config.toml或settings.json先跑一遍最小验证交互侧发一句触发工具的话rollout 侧跑一条 dataset item两边日志都对上了再上量。两套 Loop 的边界清楚之后排错会快很多因为你知道该看哪份日志。
阅读完成 · 觉得有帮助?
咨询建站