用 Litefuse 追踪 Hermes Agent
Hermes Agent 是 Nous Research 的终端 AI 助手,采用可插拔的工具调用和网关架构。本集成以 Hermes 插件 形式安装到 ~/.hermes/plugins/litefuse/。插件在 Hermes 的 Python 解释器中以同进程方式运行,订阅生命周期 hook 事件(pre_llm_call、post_api_request、pre_tool_call、post_tool_call、post_llm_call 等),为每个用户回合生成一条 Litefuse trace,使用真实的 wall-clock 逐事件时间戳。
该插件适用于 Hermes 的所有界面 —— CLI(hermes chat -q)、Gateway(飞书、Discord、Slack、Telegram、WhatsApp、IRC),以及(在合并了 PR #24237 之后的)TUI。
给 AI —— 自动安装
如果你正在和 Hermes Agent 对话,把下面这段 prompt 粘贴过去,Agent 会端到端完成整个安装:
Read https://litefuse.ai/SKILL.md and follow the instructions to install and configure Litefuse for Hermes Agent.
skill 会向你索取 Litefuse 的 API Key(如果还没有账号,会引导你注册),然后在本地完成全部配置。如果你想手工一步步配置,请继续往下看。
会捕获哪些数据
| 数据 | 捕获方式 | 备注 |
|---|---|---|
| 用户 prompt | trace input + user message event | 在回合开始时刷新,让 Litefuse 立刻显示 trace 名称 / session / input |
| 每次 LLM API 调用 | api: <model> #N generation observation | 单次 API 调用的延迟 + token 用量 + provider + base_url + finish_reason |
token 用量(input_tokens、output_tokens、cache 读/写) | 每个 api generation 的 usage_details | 来自 post_api_request.usage;使用 Anthropic 风格 key,让 Litefuse 成本映射可用 |
| 工具调用 | tool: <name> (#N) tool observation | input = 工具参数,output = 工具结果,duration_ms |
| 工具错误 | tool observation,level=ERROR | 启发式判断:结果开头出现 error / "error": / "success": false |
| 助手最终回复 | assistant response generation observation | 同时传播到 trace 级别的 output |
| 模型名称 | 每个 generation 上的 model,trace tag model:<name> | Litefuse 用它来计算成本 |
| 会话分组 | trace 的 session_id | Hermes 的 YYYYMMDD_HHMMSS_<6or8hex> session id |
| 用户身份 | trace 的 user_id | $LITEFUSE_USER_ID,回退到 $USER |
| 回合编号 | trace 的 name(Hermes Agent — Turn N)+ hermes_agent.turn_number | 从 1 开始,按会话单调递增 |
| Hermes 专属 metadata | metadata.hermes_agent.* | provider / base_url / api_mode / api_duration / finish_reason / message_count / step_index / platform / is_first_turn / history_messages |
Trace 结构
一个典型的多工具回合产生的 trace 形如:
Hermes Agent — Turn 7 (SPAN, root, real duration)
├── user message (EVENT, flushes trace metadata immediately)
├── api: MiniMax-M2.7 #1 (GENERATION, usage_details, real latency)
├── tool: web_search (#1) (TOOL, real duration)
├── api: MiniMax-M2.7 #2 (GENERATION, usage_details)
├── tool: web_extract (#2) (TOOL, real duration)
├── api: MiniMax-M2.7 #3 (GENERATION, usage_details)
└── assistant response (GENERATION, final answer)设计说明:
- 真实 wall-clock 时间戳。 每个 observation 的 start/end 都来自 hook 回调触发的那一刻,所以 Litefuse 时间线反映真实的 LLM 延迟、工具执行时间和调用之间的间隔 —— 没有合成网格。
- 唯一根父节点。 容器 span 是唯一的 trace 根;每个 api / tool / response observation 都嵌套在它下面。即便回合超过 50 步,时间线视图也保持整洁。
- Trace header 稳定。 Trace 名称 / input / session_id 在回合 START 时就刷新到 Litefuse(通过带真实 wall-clock end 的
user messageevent +lf.flush()),并且不会在新 observation 到达时被中途覆盖。 - 工具编号。
tool:observation 名称上的(#N)后缀消除同一个工具在一回合内被多次调用的歧义。 - 命名空间化的 metadata。 所有 Hermes 专属字段都放在
metadata.hermes_agent.*下,让顶层 metadata 字典只保留 Litefuse 标准 key。
快速开始
前置条件
- 在 https://litefuse.cloud 创建一个 Litefuse 项目,拿到 public + secret key。
- 已安装 Hermes Agent —— 用
hermes --version检查。建议使用合并了 PR #24237 的最新版本,这样插件 hook 在 TUI 中也能触发;否则 CLI + Gateway 也能完整工作。
把 Langfuse SDK v4 安装到 Hermes 自己的 venv
插件在 Hermes 的 Python 解释器中以同进程方式运行,所以 SDK 必须装在 Hermes 的 venv 中(不能放到单独的 venv):
~/.hermes/hermes-agent/venv/bin/pip install 'langfuse>=4,<5'
# Verify
~/.hermes/hermes-agent/venv/bin/python3 -c "import langfuse; print(langfuse.__version__)"
# Expect: 4.x.y把插件文件放进 ~/.hermes/plugins/litefuse/
mkdir -p ~/.hermes/plugins/litefuse
curl -fsSL https://litefuse.ai/integrations/hermes-agent/plugin.yaml \
-o ~/.hermes/plugins/litefuse/plugin.yaml
curl -fsSL https://litefuse.ai/integrations/hermes-agent/__init__.py \
-o ~/.hermes/plugins/litefuse/__init__.py插件源码也在同一 URL 上 —— 部署前可以先读一遍。
把 Litefuse 凭据加到 ~/.hermes/.env
插件从 Hermes 自己的 .env 文件读取凭据(Hermes 启动时会自动加载):
cat >> ~/.hermes/.env <<'EOF'
# Litefuse observability
LANGFUSE_PUBLIC_KEY=pk-lf-xxx
LANGFUSE_SECRET_KEY=sk-lf-xxx
LANGFUSE_HOST=https://litefuse.cloud
EOF把占位值替换成真实值。为了和其他 Litefuse 集成兼容,插件也接受 LANGFUSE_BASE_URL 作为 LANGFUSE_HOST 的别名。
启用插件
需要在 Hermes 中显式开启:
hermes plugins enable litefuse
hermes plugins list # confirm: status = enabled重启正在运行的 gateway
gateway 守护进程在启动时会缓存自己的插件管理器,因此需要重启来加载新插件:
hermes gateway restart # only if you have `hermes gateway` runningCLI 调用(hermes chat -q "...")每次运行都会重新加载插件 —— 不用重启。
验证
hermes chat -q "say hello in five words exactly"
tail -3 ~/.hermes/state/litefuse_plugin.log
# Expected: "turn complete session=YYYYMMDD_HHMMSS_xxxxxx turn=1 api_calls=1 tool_calls=0"打开 https://litefuse.cloud,看名为 Hermes Agent — Turn 1 的最新 trace。它应当包含:
- 立即填充的正确
name/sessionId/input - 一个携带用户 prompt 的子
[EVENT] user message [GENERATION] api: <model> #N,已填好 token 用量- (如果你的 prompt 用到了工具)
[TOOL] tool: <name> (#1),带 input 参数和 output 结果 - 带最终回答的
[GENERATION] assistant response
环境变量
| 变量 | 必填 | 说明 |
|---|---|---|
LANGFUSE_PUBLIC_KEY | 是 | Litefuse 项目 public key(pk-lf-...)。 |
LANGFUSE_SECRET_KEY | 是 | Litefuse 项目 secret key(sk-lf-...)。 |
LANGFUSE_HOST | 否 | 默认 https://cloud.langfuse.com。设为 https://litefuse.cloud(或你的自托管 URL)。别名 LANGFUSE_BASE_URL。 |
LITEFUSE_USER_ID | 否 | 覆盖 trace 的 user_id。回退到 $USER,再回退到 "hermes-user"。 |
HERMES_LITEFUSE_DEBUG | 否 | 设为 "true" 启用 ~/.hermes/state/litefuse_plugin.log 中的详细插件日志。 |
HERMES_LITEFUSE_MAX_CHARS | 否 | span 输入/输出的截断阈值(字符数)。默认 1000000(约 1MB 文本)。 |
工作原理
插件通过 ctx.register_hook(...) 订阅九个 Hermes 插件 hook 事件:
| Hook | 作用 |
|---|---|
on_session_start | 缓存 session 的 model / platform 元数据。 |
pre_llm_call | 为本回合开启长生命周期的容器 span。发出一个 user message event,立即把 trace 元数据(name / session / user / input / tags)刷新到 Litefuse,让 trace header 不必等到回合结束就显示出来。 |
post_api_request | 为每次 LLM API 调用发出一个 api: <model> #N generation,携带 usage_details(input_tokens / output_tokens / cache tokens)以便 Litefuse 进行成本映射。 |
pre_tool_call | 在容器下打开一个 tool: <name> (#N) span。 |
post_tool_call | 用 output + duration_ms 关闭对应的 tool span。由于 Hermes v0.12 在 run_agent.py 中调用 pre_tool_call 时不传 session_id / tool_call_id,只传 task_id,所以使用了一个按 session 分隔的 FIFO 队列。 |
post_llm_call | 发出 assistant response generation 并用最终输出关闭容器。 |
on_session_end | 防御性地清理被中断的回合(Hermes 在每个回合结束时都会触发,而不仅在 session 结束时)。 |
on_session_reset / on_session_finalize | 在 session 真正销毁时清空内存状态。 |
该插件是 fail-open 的:任何意外错误都会写入 ~/.hermes/state/litefuse_plugin.log,回调静默返回,所以永远不会阻塞 Hermes 的主循环。一个 Langfuse 客户端在模块级状态中跨 Hermes 进程整个生命周期保留(gateway 守护进程、CLI 调用、TUI 子进程),并由线程锁保护,多个并发的 gateway 会话可以安全共享。
Trace metadata 参考
Trace 级 metadata(位于 metadata.hermes_agent.*):
turn_number—— 从 1 开始,按 session 生命周期单调递增platform——cli、gateway、tui、feishu等(由 Hermes 设置)model—— 回合开始时的模型名称is_first_turn、history_messages—— 回合在 session 中的位置
Generation observation 元数据(api: ...,位于 metadata.hermes_agent.*):
provider、base_url、api_mode、response_model—— provider 配置api_call_count、api_duration、finish_reason、message_count—— 单次调用的统计assistant_content_chars、assistant_tool_call_count—— 输出形态step_index——(#N)步骤计数
Tool observation 元数据(位于 metadata.hermes_agent.*):
tool_name、task_id、tool_call_idduration_ms、is_errorstep_index
故障排查
Litefuse 中没有出现 trace。 用 tail 查看 ~/.hermes/state/litefuse_plugin.log:
tail -20 ~/.hermes/state/litefuse_plugin.log期望:启动时出现 "litefuse plugin registered (9 hooks)",每个回合出现 "Litefuse client ready" 和 "turn complete session=... turn=N api_calls=N tool_calls=N"。如果文件是空的,说明插件没加载。
hermes plugins list # confirm: litefuse → enabled
hermes plugins enable litefuse # if not enabled
hermes gateway restart # if gateway is running插件日志显示 Litefuse credentials not set。 插件没在 os.environ 中找到 LANGFUSE_PUBLIC_KEY / LANGFUSE_SECRET_KEY。把它们加到 ~/.hermes/.env:
cat >> ~/.hermes/.env <<'EOF'
LANGFUSE_PUBLIC_KEY=pk-lf-...
LANGFUSE_SECRET_KEY=sk-lf-...
LANGFUSE_HOST=https://litefuse.cloud
EOF然后重新执行任何 hermes chat -q "..." 或重启 gateway。
插件日志显示 langfuse SDK not importable。 Langfuse SDK 没装在 Hermes 的 venv 中:
~/.hermes/hermes-agent/venv/bin/pip install --upgrade 'langfuse>=4,<5'长回合中 trace 名称 / session / input 没出现。 这是我们修复过的真实 bug,办法是发出一个小的 user message observation(类型为 event,结构上像一个 span,让 Langfuse 传播 AS_ROOT + TRACE_* 属性),并在回合开始时强制 flush。如果你看到这种现象,很可能在用旧版本的 __init__.py —— 从 https://litefuse.ai/integrations/hermes-agent/__init__.py 重新拉取。
TUI 会话不产生 trace。 Hermes v0.12 在 TUI 进程中不加载插件(tui_gateway/entry.py)。可以选择:
- 升级到合并了 PR #24237 的 Hermes 版本,或
- 在本地给
~/.hermes/hermes-agent/tui_gateway/entry.py打一个三行的补丁(hermes update时会被覆盖 —— 每次更新后再打一次)。
CLI(hermes chat -q、hermes -z)和 Gateway(飞书、Slack、Discord、Telegram 等)不打补丁也能工作。
hermes -z "..."(oneshot 模式)也不产生 trace。 同样的根因 —— oneshot 的入口没有调用 discover_plugins。请改用 hermes chat -q "..."(完整的 CLI 路径,会加载插件),或者给 hermes_cli/oneshot.py 打同样的三行补丁。我们会为此再提一个配套 PR。
局限
- 不会捕获助手的
reasoning。 Hermes 插件 hook 回调不直接暴露模型的 reasoning / chain-of-thought 文本 ——post_api_request只给我们assistant_content_chars(字符数)。思考文本存在于 Hermes 的对话历史中,但要采集它需要订阅当前还不可用的逐消息事件。 - 不汇总图片 block。 如果回合涉及图片输入,插件会把它们以 JSON 扁平化的文本形式写入 trace 输入;不会单独把媒体类型或数量作为 metadata 暴露出来。
资源
- Hermes Agent hooks 用户指南
- Hermes Agent 插件参考
- Langfuse Python SDK v4
- Litefuse Cloud
- 插件源码:
plugin.yaml·__init__.py - TUI 插件发现的上游 Hermes Agent PR:NousResearch/hermes-agent#24237