Hermes Agent 网关监控实战指南:10分钟把健康指标接入你的 OTel 观测栈
【免费下载链接】hermes-agentThe agent that grows with you项目地址: https://gitcode.com/GitHub_Trending/he/hermes-agent
你在生产上跑着好几个 Hermes Agent 网关,凌晨三点某个平台悄悄掉到 fatal,等你发现,网关已经半瘫了一夜。缺的不是更多日志行,而是把网关健康监控信号直接喂进观测栈的一条通路。
三种类型化事件:content-free 的设计
监控平面在agent/monitoring/目录,第一设计约束很反直觉:不把所有东西写进日志,只导出三种类型化事件(健康快照、诊断事件、cron 执行事件),且构造上就不含提示词、消息正文、工具参数与会话历史。
输入 → 处理 → 输出:输入是网关运行态、gateway.*logger 的 WARNING/ERROR 记录、cron 执行历史;处理在gateway_health.py,把错误文本归类成 auth_failed / timeout / network_error 这类有界类别,所有字符串过一遍redact.py脱敏层;输出是 OTLP 导出器把同一批事件拆成 metrics、诊断日志、生命周期 span 三股流,发往运维自配的端点。
为什么较真这一点?因为 AI 网关日志敏感内容密度太高,与其事后 scrub 日志,不如只导出"错误的类别",把内容和监控从物理上分开。
事件总线:不阻塞、不抛异常
链路枢纽是emitter.py的 emitter,契约一句话:emit() 微秒级返回,绝不阻塞磁盘网络,绝不向调用方抛异常。队列深度固定 10000,满了丢弃最旧事件并计数;后台线程按 256 个一批拉取扇出给订阅者,每个订阅者互相故障隔离,一个慢导出器拖不垮网关。
下面两行演示生产者侧用法,stats() 是总线自身的健康检查窗口:
emitter.emit(GatewayHealthEvent(name="gateway.health_snapshot", active_agents=3)) print(emitter.stats()) # {'queued': 0, 'dispatched': 1, 'dropped': 0, 'subscribers': 1}另一个细节:采集是 opt-in 的,emitter 默认关闭,挂上第一个订阅者才启用;没人订阅时事件直接在环形缓冲里老化掉。监控是出向通路,不是本地存储。
搭建路径:可选依赖与配置块
先装可选依赖:pip install 'hermes-agent[otlp]'。OTel SDK 不在主包里,缺了它start_gateway_health_export只会 fail-open 打条警告,不会卡住网关启动。
然后写配置块,注意两处 enabled 是"与"关系,缺一即整个平面不启用:
monitoring: export: otlp: enabled: true endpoint: "http://collector.internal:4318/v1/traces" headers_env: { "x-api-key": OTEL_KEY } gateway_health_export: enabled: true export_interval_seconds: 60endpoint 要写完整的 /v1/traces 路径,模块会自动把另外两股流改写到 /v1/metrics 和 /v1/logs;headers_env 存的是环境变量名而不是密钥值,取值只在导出时从环境读取,永远不落配置文件。
三类数据流出来
配置生效后第一股是 metrics gauge,默认 60 秒导出一次:hermes.gateway.up / active_agents / busy / drainable、逐平台的 hermes.platform.up / degraded,再加一组 cron 调度器健康指标(心跳年龄、补跑次数、逾期任务数)。
第二股是诊断事件:gateway.*logger 的 WARNING/ERROR 走白名单进总线,只保留错误类别,实例 ID 先哈希成 sha256 前 24 位再导出,反查不到原始 install ID。第三股是生命周期 span:startup_failed、stopped、platform.fatal 这类状态迁移各产生一条,带 old_state / new_state / exit_reason,方便事后复盘。
有个容易漏的指标:hermes.gateway.background_work。active_agents 故意不计后台子代理(delegate_task 扇出、后台终端进程),background_work 按任务粒度把这部分补上,否则一个在猛跑子代理的节点在机群面板上会显示 active_agents=0,看着像死了。
进阶方向
机群级告警适用场景:多网关多 profile 部署,要一眼看出"谁挂了"。核心做法:实例 ID 已哈希,按 profile / version / supervision_mode(systemd、s6、container、launchd 自动探测)聚合面板,直接对 hermes.gateway.up == 0 告警。预期收益:网关级宕机从"第二天用户报障"变成"秒级触达"。
安全收敛适用场景:数据跨网络边界,Collector 在另一个安全域。核心做法:认证走 headers_env(token 只放环境变量),Collector 侧强制 TLS;Hermes 侧本就有字段白名单、脱敏、字符集白名单三道防线,出网的只有健康类信号。预期收益:即使数据落到错误的地方,也拿不到任何业务内容。
接自己的后端适用场景:不想上完整 OTel 栈,或同一批事件还要进内部告警系统。核心做法:emitter.subscribe(callback) 是唯一接缝,回调签名 batch: list[dict],注册第二个 sink 不碰网关代码,配合 event_filter 圈定自己的平面。预期收益:监控总线变成可复用基建,加消费方一行代码。
def my_sink(batch): ... # 内部告警逻辑,读 batch 即可 get_emitter().subscribe(my_sink)避坑速查
- 如果你配了 enabled 但 Collector 收不到数据,大概率是 OTel SDK 没装——它是可选 extra,
pip install 'hermes-agent[otlp]';日志里也能 grep 到 "OTLP SDK could not be installed" 这条警告。 - 如果指标显示 active_agents=0 但机器明明很忙,不是 bug——后台子代理不计入这个指标,去看 background_work。
- 如果 emitter 的 dropped 计数持续上涨,是订阅端(通常是网络端点)消费慢于生产,10000 深度队列满了在丢最旧事件——先查端点限流和网络,别上来就改队列深度。
- 如果 endpoint 只写了裸域名结果只来了一股流,因为 /v1/metrics 和 /v1/logs 的自动改写只在路径以 /v1/traces 结尾时触发——写全路径。
延伸资源
- 监控平面核心:
agent/monitoring/(emitter 事件总线、events 类型化事件、gateway_health 分类与指标、otlp_exporter 导出器) - 脱敏策略:
agent/monitoring/redact.py的相邻实现agent/monitoring/redaction.py;cron 健康投影:agent/monitoring/cron_health.py - 配置键全集与关闭时的排空(flush)逻辑,见
agent/monitoring/gateway_health_export.py的模块 docstring
【免费下载链接】hermes-agentThe agent that grows with you项目地址: https://gitcode.com/GitHub_Trending/he/hermes-agent
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考