如何调试 Hermes Agent:日志、追踪与盲点
Hermes Agent 调试实战指南:日志在哪里、先看哪一份、如何阅读追踪树,以及可观测性目前仍然欠缺的部分。
你的智能体行为怪异,该去哪里看?
Hermes Agent 有两种令人头疼的失败模式。第一种很吵:抛出带堆栈的异常,或启动即崩溃。第二种很安静:智能体给出一段看似连贯却错误的回复,调用了错误的工具,或在工具返回后径直沉默。吵的那种会出现在 errors.log 里。安静的那种才是真正的难题,它藏在那一次翻车会话的审计日志里。
本文是一份实用地图:日志在哪里、哪个文件对应哪种症状,以及周围那些能把 800 行 JSONL 变成人类可读内容的小工具。它同时点名当前仍然存在的盲点,让你清楚今天 Hermes 不会告诉你什么。
日志的位置
Hermes 写出的所有日志都落在你的 Hermes 主目录里,默认是 ~/.hermes/logs/(非默认 profile 则在 <profile>/logs/)。四个文件值得关注:
| 文件 | 级别 | 存放内容 |
|---|---|---|
agent.log |
INFO+ | 智能体、工具与会话主活动。默认入口。 |
errors.log |
WARNING+ | 仅告警和错误。用于快速定位"出事了"。 |
gateway.log |
INFO+ | 仅 gateway 事件,Telegram/Discord/Slack 中每个用户的会话生命周期。 |
gui.log |
INFO+ | 控制台、websocket 和 TUI-gateway 事件。 |
四个文件都由 Python 的 RotatingFileHandler 写入。当某个文件达到大小上限时,会滚动为 agent.log.1、agent.log.2,直到配置的 backup_count。当前活跃文件永远是没有后缀名的那个。当你追查昨天的 bug 时,这一点很关键,因为"昨天"可能已经被滚动出去了。请把编号文件也一起拿走,不要只看当前的。
所有这一切的入口是 hermes_logging.setup_logging()。gateway 启动时以 mode="gateway" 调用它,只挂接文件 handler,从不挂控制台 handler。所以 hermes gateway start 按设计就是安静的。如果 gateway 看上去没反应,其实并没有。请对 gateway.log 做 tail。
先打开哪一份日志
由症状决定文件,而不是反过来。一个粗略的决策树:
- 智能体启动崩溃,或请求返回 500。 用
hermes logs errors --since 30m -f打开errors.log。堆栈最先落在这里。 - 智能体回了话,但答案是错的。 跳过
errors.log。产生这条错回复的工具调用都在那次会话的 JSONL 会话转录里(见下一节的 trace-tree)。 - Telegram 或 Discord 用户说"它不出声了"。 打开
gateway.log,按其会话过滤。hermes logs gateway --session abc123可以收敛范围。 - 控制台不刷新。
gui.log。websocket 掉线和 TUI-gateway 同步错误会最先在这里显现。 - 完全不知道发生了什么。 对
agent.log执行hermes logs -f,另开一个窗口盯errors.log。绝大多数"我的智能体在做什么"的答案,都在一次tail -f之内。
hermes logs 这个 CLI 是你的伙伴。在实时调试时,下面这些 flag 物有所值:
hermes logs # agent.log 的最后 50 行
hermes logs -f # 实时跟踪 agent.log
hermes logs gateway -n 100 # gateway.log 的最后 100 行
hermes logs --level WARNING --since 1h # 最近 1 小时的告警与错误
hermes logs --session abc123 # 按会话 id 收敛
hermes logs errors --since 30m -f # 从 30 分钟前开始跟踪 errors.log
hermes logs list # 列出文件清单与大小
把会话读成一棵树,而不是一堵 JSONL 墙
会话结束后,它的完整轨迹会以每行一条 JSON 的形式写入会话转录文件。这是调试"看似连贯但错误"这一类 bug 最有用的产物,因为每一次模型调用、每一次工具调用及其结果都按顺序连带参数一起被记录下来。而它的原始形态也确实无法阅读。一个中等复杂度的会话产生 800 行审计日志是常态。
社区工具 trace-tree(参见 Mukunda Katta 在 dev.to 的文章)读取这份 JSONL,然后在终端打印一棵树。会话变成根节点,每次工具调用是子节点,被拒绝的调用作为子节点出现,并附带其错误信息。打开它,读完这棵树,然后关闭。无需登录,无需上传,无供应商锁定。把它指向某个会话文件即可:
trace-tree ~/.hermes/logs/sessions/2026-07-21T09-42-11.jsonl
需要更深入的诊断时,你也可以把同一份 JSONL 管道传给 jq,按工具名、耗时或错误状态做过滤。会话转录在版本之间的稳定性比 agent.log 好得多,所以做临时查询时请针对转录,而不是针对人类可读日志做 grep。
对于"智能体没声,是不是卡住了"这个消息渠道相关的排查,我们的 Telegram 排障指南 会先带你走投递侧的症状(bot token、webhook、群组权限),这些常常就是真正的根因,甚至根本用不到追踪树。
提高日志级别而不泄露密钥
verbose 模式只差一个 flag。hermes chat --verbose(或 -v)会把 AIAgent 上的 verbose_logging 置为 True,随后调用 setup_verbose_logging(),在文件 handler 之上再加一个 DEBUG 级别的控制台 StreamHandler。你能实时看到智能体所看到的一切。
关键细节是:每一条日志记录,无论级别,都会先经过 agent/redact.py 中的 RedactingFormatter 再落盘。这个 formatter 能识别已知的凭据形态(sk-、sk-or-、sk-ant-、常见的 OAuth 模式,以及环境变量形态的秘密),并就地替换其值。实践上这意味着你可以在生产环境里提高日志级别,或把脱敏后的 agent.log 粘进 bug 报告,而不会泄露你的 OpenRouter 密钥。
有一个坑值得点名。如果你写了自己的 logger 或自己的 formatter 而跳过了这条流水线,脱敏就不生效。作为 issue #8090 报告的 gateway 启动崩溃 NameError: name 'RedactingFormatter' is not defined,其实是同一类错误的反面版本。请把 formatter 视为承重的组件,不要绕过它;如果一定要写自定义日志,请通过 hermes_logging.setup_logging() 包裹进去,而不是绕着它走。
目前仍然存在的可观测性盲点
Hermes 对自己现阶段做不到的事很诚实。两个开放的 feature request 描述了当前上限:
- 带起止时间戳的结构化 span。 目前大多数日志行只带一个时间戳,部分工具输出里带有临时的
duration_seconds。整条轨迹上没有稳定的start_ts、end_ts、duration_ms和parent_id模式。这是 issue #6741,会话变慢时你想要的那种清爽的"按工具看延迟"仪表盘因此被挡住。 - 对进行中的 gateway 会话做实时 attach。 在当前版本,一旦某个 gateway 会话已经在跑,你就无法从外部实时观察它。
agent.log会在会话结束时补上,但没有"边发生边看这个用户会话"的钩子。这是 issue #18127,也是把 Hermes 当作共享服务运行的团队面临的最大缺口。
在此期间有两种可以填补部分缺口的绕行方案。第一种是把 OpenTelemetry 风格的追踪送到 SigNoz 这样的后端,即便 Hermes 没有原生 span 发射,也可以在下游把它的活动翻译成 span。第二种是 Langfuse(issue #1501),一些团队按每一轮把它作为手动埋点层接进去。两者目前都不是官方一等公民,但今天都在某处的生产环境里跑着。
如果你干脆不想拥有这套日志层
以上都建立在"你自己在跑智能体"这个前提上。如果这一部分正是你想外包出去的,Hermify 会在 Telegram 上为你运行一个托管的 Hermes Agent,底层容器上的同款日志与审计跟踪同样具备。你能拿到持久化记忆、会话转录,以及把某个具体问题升级给我们的通道,而无需在自己的 VPS 上一直挂着 hermes logs -f。如果你在自托管和托管方案之间摇摆,其中一部分理由是可观测性带来的运维负担,我们那篇 托管 Hermes 与自托管 Hermes 对比 把利弊讲得很完整。
从 Hermify 开始,把日志轮转与可观测性工作整块省掉。或者继续保留本地日志,下次智能体沉默时把这份指南翻出来对照。两条路都成立,且同一份审计跟踪在两条路上都存在。
Sources
- Chapter 9: Observability and Debugging (Claude Code vs. Hermes Agent) - Ken Huang
- Put a Microscope on Hermes: Full Visibility into Agent Execution - Alibaba Cloud
- I had 800 lines of Hermes agent audit log. trace-tree turned it into a tree I could read.
- hermes-agent/hermes_logging.py source
- Issue #18127: Observability for in-flight gateway sessions
- Issue #6741: Structured session tracing with start/end timestamps
- Hermes Monitoring and Observability with OpenTelemetry - SigNoz