9.1. 日志解读能力是定位问题的首要技能
日志解读能力是定位问题的首要技能
场景还原
时间:周三下午 3:10,你的 Slack 被一条告警打穿——“Agent 不回消息了,客户在等。”你打开终端,tail -f hermes.log刷出一屏又一屏的混合日志,第一时间却不知道该盯哪一行。十分钟后你才意识到:问题不在代码,而在你从未真正“看懂”过这些日志。在 Agent 研发的日常里,日志是唯一能从外部观测内部决策过程的窗口。没有日志解读能力,每一次故障都是猜谜。本章将带你拆解 Hermes Agent 的日志格式与关键字段,让你能在 30 分钟内从“日志恐惧”过渡到“定位问题只需 3 行日志”。
你需要什么
| 资源 | 说明 |
|---|---|
| 一个运行中的 Hermes Agent 实例 | 版本 ≥ v0.12,启用调试日志 |
| 终端工具 | less、grep、jq(可选,方便结构化过滤) |
| 预计时间 | 约 30 分钟 |
请在启动 Agent 时设置环境变量 LOG_LEVEL=DEBUG,或者直接在 config.toml 中启用详细日志:
[logging]
level = "DEBUG"
output = "file"
file_path = "logs/hermes-agent.log"
重新启动 Agent 后,确认日志文件已经开始写入。本章所有操作均在此环境下完成。
最终成果
学完本章后,你将能够:
- 看懂任意一条 Herman Agent 日志的五个组成要素
- 追踪一次完整对话的执行循环,定位任一环节的耗时与卡点
- 从异常堆栈中快速判断错误类型,并知道下一步排查方向
为什么必须掌握这门技能?因为 Hermes Agent 的定位是“可自进化的 Agent 操作系统”,其内部并发管线、工具调度、记忆读写全部异步化。一旦出问题,表面症状与实际故障点往往隔着三层调用栈。只有通过日志还原执行路径,才能一击命中。
步骤一:拆解日志格式——五个维度看懂一条日志
1.1 Hermes Agent 日志的统一格式
Hermes Agent 的日志输出遵循固定的结构,无论来自哪个子系统,都用同一套格式。打开日志文件,你会看到这样的行:
2026-06-14T09:12:35.421Z INFO app.core.loop [req_8f3a] Outer loop iteration 3: dispatching user message
每一项的含义如下:
| 位置 | 字段 | 说明 | 示例 |
|---|---|---|---|
| 1 | 时间戳 | ISO 8601 格式,精确到毫秒 | 2026-06-14T09:12:35.421Z |
| 2 | 日志级别 | DEBUG / INFO / WARNING / ERROR | INFO |
| 3 | 模块标识 | 用点分隔的层级命名,精确定位代码来源 | app.core.loop |
| 4 | 请求 ID | 方括号包裹,唯一标识一次用户交互或任务 | [req_8f3a] |
| 5 | 消息内容 | 人类可读的描述或结构化数据 | Outer loop iteration 3... |
⚠️ 注意
如果你的日志中没有出现[req_xxx]这样的请求 ID,说明你当前使用的是简化模式(LOG_FORMAT=simple)。务必切换为detailed格式,否则后续所有步骤都无法完成跨行追踪。
1.2 常见模块标识速查表
日志里的模块前缀直接告诉你“这段逻辑是谁打的”。以下是在日常调试中出现频率最高的模块:
| 模块前缀 | 职责 | 出现时的含义 |
|---|---|---|
app.core.loop |
Agent 主循环 | 每一轮决策、工具调用、反思的调度入口 |
tool.dispatch |
工具注册与分发 | 正在查找或执行某个工具 |
prompt.build |
提示词组装 | 正在将上下文、记忆、工具描述拼成最终 Prompt |
memory.store |
记忆持久化 | 写入或读取短期/长期记忆 |
gateway.http |
HTTP 网关 | 接收用户请求或向上游 API 发起调用 |
llm.invoke |
LLM 调用 | 实际向模型发起的请求与响应 |
skill.exec |
Skill 执行 | 代码技能的执行入口 |
现在我们来做第一项练习:用 grep 筛选出过去 5 分钟内所有 ERROR 日志,并观察模块分布。
grep "ERROR" logs/hermes-agent.log | tail -20
预期结果:你应该能看到错误来自哪些模块——如果 80% 的 ERROR 集中在 tool.dispatch,那问题大概率是工具注册缺失或名称拼写错误。
步骤二:追踪一条完整的执行循环
2.1 从用户消息到最终回复的日志链
现在我们追踪一条真实请求的完整日志。假设用户在 9:12:35 发送了消息“帮我查一下上海明天天气”。我们提取它的执行路径。
2026-06-14T09:12:35.410Z INFO gateway.http [req_8f3a] Received POST /chat {"message":"帮我查一下上海明天天气"}
2026-06-14T09:12:35.412Z DEBUG app.core.loop [req_8f3a] Entering outer loop, iteration=0
2026-06-14T09:12:35.415Z DEBUG prompt.build [req_8f3a] Assembling system prompt with 3 memories, 5 tools
2026-06-14T09:12:35.420Z DEBUG tool.dispatch [req_8f3a] Intent classified as: weather_query (confidence=0.97)
2026-06-14T09:12:35.421Z INFO app.core.loop [req_8f3a] Outer loop iteration 1: dispatching user message
2026-06-14T09:12:35.425Z DEBUG tool.dispatch [req_8f3a] Tool matched: get_weather (source=skill_registry)
2026-06-14T09:12:35.430Z DEBUG skill.exec [req_8f3a] Executing skill 'get_weather' with params {"city":"上海","date":"2026-06-15"}
2026-06-14T09:12:35.480Z INFO llm.invoke [req_8f3a] LLM request sent (model=gpt-4o, tokens=1234)
2026-06-14T09:12:37.112Z INFO llm.invoke [req_8f3a] LLM response received (tokens=89, latency=1632ms)
2026-06-14T09:12:37.120Z DEBUG memory.store [req_8f3a] Storing conversation turn (short-term, ttl=3600)
2026-06-14T09:12:37.125Z INFO gateway.http [req_8f3a] Response sent (status=200, total_latency=1715ms)
逐行解读:
gateway.http收到请求,分配 IDreq_8f3a。后续所有日志都带着这个 ID,像一条金线串起整个处理流程。app.core.loop进入主循环,iteration=0表示这是一次全新对话的第一轮。prompt.build组装系统提示词,此时已将 3 条记忆和 5 个可用工具注入。tool.dispatch先做意图分类,识别为weather_query,置信度 0.97。- 主循环第二次迭代 (
iteration=1) 开始实际分发:工具get_weather被匹配成功。 skill.exec执行技能,传入城市和日期参数。llm.invoke发出模型请求,耗时 1632ms。memory.store将本轮对话写入短期记忆 (TTL 1 小时)。gateway.http返回 200 响应,总延迟 1715ms。
2.2 提取性能瓶颈
使用 grep + awk 快速统计每个模块的平均耗时。以上面日志为例,llm.invoke 耗时 1632ms,占整个处理时间的 95% 以上——这是典型情况,属于正常范围。如果某天这个值突然飙升到 10 秒,你就应该去检查模型 API 的可用区或限流策略。
grep "req_8f3a" logs/hermes-agent.log | grep "latency"
预期结果:能直接看到每一步的耗时,并绘制出简单的时序图(脑子里的即可)。
步骤三:异常堆栈分析——一眼看穿错误类型
Hermes Agent 的异常日志具有极强的特征性,熟悉三类高频错误,可以让你在故障前 10 秒内就打开正确的文档。
3.1 错误类型一:ToolNotFound
2026-06-14T09:15:01.033Z ERROR tool.dispatch [req_9b2c] Tool 'get_stock_price' not found in local or remote registry.
Traceback (most recent call last):
File "hermes/tool/dispatcher.py", line 142, in resolve_tool
tool = self.registry[tool_name]
KeyError: 'get_stock_price'
含义:Agent 尝试调用一个不存在的工具 get_stock_price。原因通常是 Skill 文件未部署、工具名拼写错误,或者注册了但未重启。
应对策略:
- 检查
skills/目录下是否有对应 Python 文件。 - 确认
skills/manifest.toml中已注册该工具名。 - 重启 Agent 使注册生效。
3.2 错误类型二:MemoryFull
2026-06-14T10:22:18.771Z WARNING memory.store [req_d7e4] Short-term memory buffer full (200/200 entries). Evicting oldest entry.
2026-06-14T10:22:18.772Z ERROR memory.store [req_d7e4] Failed to store new memory: MemoryStoreQuotaExceeded("quota 'short_term' reached, eviction policy disabled")
含义:短期记忆缓冲区已满(默认 200 条),且未启用自动淘汰策略,导致写入失败。
应对策略:
- 检查
memory.short_term.max_entries配置项。 - 启用淘汰策略:
memory.short_term.eviction_policy = "LRU"。 - 或者增加配额至更大值(如 1000),但注意内存占用。
3.3 错误类型三:API 超时或限流
2026-06-14T11:05:44.002Z ERROR llm.invoke [req_f12a] Request to llm.openai failed after 3 retries.
Traceback (most recent call last):
File "hermes/llm/http_client.py", line 89, in _invoke
response = await session.post(url, json=payload, timeout=30)
asyncio.TimeoutError
含义:调用 LLM API 时连续三次重试均超时或返回 429/503。
应对策略:
- 使用
curl单独测试 API 端点是否可达。 - 检查 API 密钥配额是否耗尽。
- 降低请求并发度,或在网关层增加退避逻辑。
⚠️ 踩坑经验
很多开发者在遇到TimeoutError后会立刻翻代码,但实际上日志里已经提示了after 3 retries——这说明完全是网络侧的问题,和你的业务逻辑无关。直接查网络/代理/API 状态页,不要浪费时间在代码中找 bug。
回顾
在这次 30 分钟的实战中,你完成以下动作:
- 拆解了 Hermes Agent 日志的五个关键字段,记住了主要模块前缀的含义。
- 追踪了一条从“用户输入”到“最终回复”的完整日志链,并学会了如何定位性能瓶颈。
- 分析了三种最常见的异常日志(ToolNotFound、MemoryFull、API 超时),知道了它们的直接含义和排查方向。
现在,你在看到任何一条日志时,都能迅速提取出“谁在什么时间、哪个模块、执行什么操作、结果如何”这一完整信息。这是调试 Hermes Agent 的元技能。
行动清单
- [ ] 将
LOG_LEVEL=DEBUG和LOG_FORMAT=detailed设置为开发环境的默认配置 - [ ] 为你的项目创建一个“日志模块速查卡片”,列出团队定义的 5 个核心模块及其含义
- [ ] 用
grep提取最近 10 次请求的日志,画出其中一条的时序图(纸笔即可) - [ ] 针对
ToolNotFound、MemoryFull、TimeoutError三种错误,建立团队的内部处理 SOP - [ ] 将本章用到的
grep/awk/jq命令保存为脚本hermes-log-analyzer.sh,加入项目根目录
一旦你学会了用日志“透视” Agent 内部,你很快会发现一些更深层的问题:为什么 Agent 会反复使用过期的用户偏好?为什么对话历史越来越长,响应反而越来越离谱?这正是下一章的主题——记忆过期与污染是持久化 Agent 的常见顽疾,我们将直接从日志中的 memory.store 异常切入,教你诊断与清理被污染的记忆。
Hermes Agent 系统设计与工程落地
关于 LearnKu