3.4. 监控与日志体系确保 Agent 在生产环境可观测
现在你的 Hermes Agent 已经稳定运行在 Kubernetes 集群中,各个 Pod 顺利挂载了 PVC,无论重启多少次都不会再丢失记忆文件。
但真正的考验刚刚开始:当自动扩缩容将 Pod 数量从 3 个提升到 10 个时,你怎样知道每条对话请求走了哪个模型后端、延迟分布如何、记忆写入是否正常?
这一章的目标,就是为你的生产级 Agent 接入 Prometheus 指标、Grafana 可视化面板以及结构化的日志聚合管道——让你在控制台前轻点几下,就能看清整个 Agent 集群的呼吸与心跳。
预测耗时:45 分钟(不含等待 Pod 启动的时间)
前置条件:Kubernetes 集群已安装 Prometheus Operator(或 Prometheus + Grafana 独立部署),Loki + Promtail(或 ELK)作为日志聚合后端。
你需要什么
| 工具 / 环境 | 用途 | 说明 |
|---|---|---|
| Kubernetes 集群 (v1.24+) | 运行 Hermes Agent 与监控组件 | 上一章已完成的部署环境 |
| Prometheus Operator | 通过 ServiceMonitor/PodMonitor 自动发现指标端点 | 可选,也可手动配置 scrape |
| Grafana (8.x+) | 可视化仪表板与告警通知 | 与 Prometheus、Loki 数据源联动 |
| Loki + Promtail | 采集结构化日志并构建可搜索的时间序列日志流 | 替代方案:Elasticsearch + Filebeat |
| Hermes Agent 实例 | 提供指标端点和日志输出 | 已通过 Deployment 运行 |
最终成果
完成本章后你将得到:
- 一个在 Grafana 中实时刷新的 Hermes Agent 集群仪表板,展示执行循环延迟、模型调用分布、记忆读写成功率等核心指标。
- 所有 Agent 日志以 JSON 格式输出,并按
agent_id、model_backend、request_id等字段聚合,可在 Grafana Explore 中快速检索。 - 当执行循环延迟超过 5 秒或记忆写入连续失败时,Prometheus 告警规则会触发通知(例如发送到 Slack/钉钉)。
这么做不是为了炫技,而是让你在 10 个 Pod 并行处理数千个对话请求时,依然能精准定位慢请求、异常后端和记忆系统的隐患。
步骤一:启用 Hermes Agent 的内置指标端点
Hermes Agent 默认在应用内部集成了一个 Prometheus 指标端点,但出于安全考量,生产环境中并不会自动向外部开放。我们需要在 Deployment 中显式开启它,并调整绑定地址。
1.1 理解默认指标
Hermes Agent 暴露的关键指标大致可分为三类(详细定义见其 /metrics 端点输出):
| 指标名示例 | 类型 | 含义 |
|---|---|---|
agent_execution_loop_duration_seconds |
Histogram | 单次执行循环(感知-决策-行动)消耗的时间 |
model_invocation_duration_seconds |
Histogram | 请求 LLM 后端的耗时,带 model 标签区分后端 |
memory_write_errors_total |
Counter | 记忆写入失败的累计次数 |
http_requests_total |
Counter | 接收到的 HTTP 请求总数 |
active_conversations |
Gauge | 当前正在进行的对话数 |
注意:上述指标名称基于 Nous Research 公开的设计理念提炼。实际部署前请先访问
<pod-ip>:9090/metrics确认你版本中的具体命名,不同发行版可能略有差异。
1.2 修改 Deployment 暴露端点
编辑 Hermes Agent 的 Deployment YAML,在容器环境变量中添加指标配置,并确保端口声明正确:
apiVersion: apps/v1
kind: Deployment
metadata:
name: hermes-agent
spec:
template:
spec:
containers:
- name: hermes
image: your-registry/hermes-agent:latest
env:
- name: METRICS_ENABLED
value: "true"
- name: METRICS_PORT
value: "9090"
- name: METRICS_HOST
value: "0.0.0.0" # 关键:绑定到所有接口,否则 Service 抓取不到
ports:
- containerPort: 9090
name: metrics
踩坑经验:默认情况下 Hermes Agent 可能只监听
127.0.0.1,导致 Prometheus 无法通过 Pod IP 抓取。务必通过METRICS_HOST=0.0.0.0覆盖。
1.3 创建 Service 与 ServiceMonitor
为了让 Prometheus 发现这个指标端点,我们创建一个 Service,并再通过 Prometheus Operator 的 ServiceMonitor 声明抓取规则。
# service.yaml
apiVersion: v1
kind: Service
metadata:
name: hermes-agent-metrics
labels:
app: hermes-agent
spec:
selector:
app: hermes-agent
ports:
- name: metrics
port: 9090
targetPort: 9090
接着创建 ServiceMonitor(若使用 Prometheus Operator):
# servicemonitor.yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: hermes-agent-sm
labels:
release: prometheus # 需与 Prometheus Operator 的 serviceMonitorSelector 匹配
spec:
selector:
matchLabels:
app: hermes-agent
endpoints:
- port: metrics
interval: 30s
path: /metrics
应用后等待 1 分钟左右,在 Prometheus UI 的 Targets 页面应能看到状态为 UP 的 hermes-agent 端点。
同时可以在 Grafana 中添加 Prometheus 数据源,使用 agent_execution_loop_duration_seconds_bucket 等指标构建初步面板。
1.4 预期结果
- 每个 Pod 的
/metrics端点返回 Prometheus 格式数据。 - Prometheus 成功抓取所有 Pod 的指标。
- Grafana 可以查询到
http_requests_total、agent_execution_loop_duration_seconds_sum等时间序列。
步骤二:日志结构与非结构化输出处理
Hermes Agent 的默认日志输出是面向人类的非结构化文本,这在单节点调试时很友好,但在容器化集群中会变成灾难——你无法快速按模型后端过滤,也很难统计某一类错误的出现频率。
因此,我们需要将日志格式化为 JSON,并接入 Loki + Promtail(或 ELK)进行聚合。
2.1 配置 Agent 输出结构化 JSON 日志
Hermes Agent 底层使用 Python 标准 logging 库,我们只需在配置中指定一个 JSON 格式化器。常见做法是通过环境变量注入日志配置路径,或直接在代码中使用 python-json-logger 库。以下示例展示了通过环境变量指定一个自定义日志配置文件:
# log_config.py – 存放在 ConfigMap 中
import os
from pythonjsonlogger import jsonlogger
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'json': {
'()': jsonlogger.JsonFormatter,
'fmt': '%(asctime)s %(name)s %(levelname)s %(message)s',
'datefmt': '%Y-%m-%d %H:%M:%S'
}
},
'handlers': {
'console': {
'class': 'logging.StreamHandler',
'formatter': 'json',
'stream': 'ext://sys.stdout'
}
},
'root': {
'handlers': ['console'],
'level': os.getenv('LOG_LEVEL', 'INFO')
}
}
在 Deployment 中挂载这个 ConfigMap 并设置 LOG_CFG 环境变量指向它:
env:
- name: LOG_CFG
value: "/etc/hermes/log_config.py"
volumeMounts:
- name: log-config
mountPath: /etc/hermes
这样一来,每行日志都会变成类似这样的 JSON:
{
"asctime": "2026-06-15 10:23:45",
"name": "hermes.agent",
"levelname": "INFO",
"message": "Invoking model backend",
"agent_id": "agent-01",
"request_id": "req-5678",
"model_backend": "gpt-4o-mini",
"latency_ms": 320
}
注意:确保你的日志框架支持自定义字段注入。如果没有自动带上
agent_id等字段,可以在应用代码中显式logger.info("message", extra={"agent_id": ...})。
2.2 用 Loki + Promtail 收集日志
Promtail 作为 DaemonSet 运行在每个节点上,会自动采集容器 stdout/stderr 日志。默认情况下它会将文本作为一行非结构化日志发送给 Loki。为了享受结构化查询,我们需要配置 Promtail 的 pipeline 来解析 JSON 并提取字段。
创建一个 promtail-config.yaml(在 Loki 的 Helm Chart 中可覆盖):
scrape_configs:
- job_name: kubernetes-pods
pipeline_stages:
- docker: {}
- json:
expressions:
levelname: levelname
agent_id: agent_id
request_id: request_id
model_backend: model_backend
latency_ms: latency_ms
- labels:
agent_id:
model_backend:
levelname:
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels: [__meta_kubernetes_pod_label_app]
action: keep
regex: hermes-agent
部署后,Loki 就会将日志标签化为 {agent_id="agent-01", model_backend="gpt-4o-mini"} 这样的序列,Grafana 中通过 LogQL 查询:
{app="hermes-agent"} | json | latency_ms > 500
即可列出所有延迟超过 500ms 的调用日志。
2.3 构建 Grafana 日志面板
在 Grafana 中添加一个 Loki 数据源,然后在仪表板中使用 `Logs` 面板,输入查询 {app="hermes-agent"} | json | line_format "{{.levelname}} [{{.model_backend}}] {{.message}} ({{.latency_ms}}ms)",就能得到一个漂亮的结构化日志流,支持按时间、模型后端实时过滤。
2.4 预期结果
- 所有 Hermes Agent 日志以 JSON 格式输出,被 Promtail 采集并推送到 Loki。
- Grafana
Explore中可基于任意字段(如model_backend,request_id)快速检索日志。 - 当某个模型后端响应变慢时,你能在 5 秒内从日志中找出对应请求的完整上下文。
步骤三:告警规则示例——执行循环延迟与记忆写入失败
有了指标和日志,下一步是让系统在人不看仪表板时也能发出警报。我们基于 Prometheus 定义两条关键的告警规则。
3.1 定义 PrometheusRule 资源
如果你使用 Prometheus Operator,直接创建 PrometheusRule 即可;如果是传统独立 Prometheus,则编辑 alert.rules 文件。
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: hermes-agent-alerts
labels:
release: prometheus
spec:
groups:
- name: hermes-agent
rules:
- alert: HighExecutionLoopLatency
expr: |
histogram_quantile(0.99, rate(agent_execution_loop_duration_seconds_bucket[5m])) > 5
for: 2m
labels:
severity: warning
annotations:
summary: "执行循环延迟 P99 > 5 秒"
description: "Hermes Agent {{ $labels.pod }} 的 99% 执行循环延迟已达到 {{ $value | humanizeDuration }},可能意味着模型后端响应慢或内部逻辑阻塞。"
- alert: MemoryWriteFailing
expr: rate(memory_write_errors_total[5m]) > 0
for: 1m
labels:
severity: critical
annotations:
summary: "记忆写入失败"
description: "Pod {{ $labels.pod }} 在过去 5 分钟内记忆写入失败率为 {{ $value | humanize }},请立即检查存储后端或磁盘空间。"
解释:
histogram_quantile(0.99, ...)用于计算执行循环耗时分布的 99 分位。如果持续 2 分钟超过 5 秒,说明系统整体变慢。rate(memory_write_errors_total[5m]) > 0——只要出现一次记忆写入失败就触发 critical 级别告警,因为记忆丢失会直接影响 Agent 的长期表现。
3.2 配置告警通知渠道
在 Alertmanager 中添加接收方,例如 Slack webhook 或钉钉机器人。简单示例如下:
receivers:
- name: 'slack-hermes'
slack_configs:
- channel: '#hermes-alerts'
send_resolved: true
text: "{{ .CommonAnnotations.description }}"
部署后,通过故意触发高延迟或模拟存储不可用来验证告警能否发出。
3.3 可选的日志告警(Loki Ruler)
如果希望基于日志内容触发告警——例如日志中连续出现 levelname=ERROR 且包含 “Memory write timeout” ——可以使用 Loki 的 Ruler 组件。但这超出了 Prometheus 告警范围,此处不展开,你可以参考 Loki 文档自行扩展。
3.4 预期结果
- Prometheus 规则生效,Alertmanager 可见。
- 当 P99 延迟超限或记忆写入失败时,你的消息通道收到通知。
- 你能在告警信息中看到具体 Pod 名称和量化数值,直接定位问题。
回顾
本章你完成了一个从“盲飞”到“全观测”的飞跃:
- 启用了 Hermes Agent 的 Prometheus 指标端点,让每个 Pod 暴露内部运行时状态。
- 配置了 ServiceMonitor,使 Prometheus 自动发现并采集指标;同时搭建了 Grafana 数据源。
- 将日志输出改为结构化 JSON,并通过 Loki + Promtail 实现集中检索与分析。
- 编写了针对执行循环延迟和记忆写入失败的 Prometheus 告警规则,确保问题能主动推送到你的通信工具。
整条链路接通后,你可以在 Grafana 中同时查看指标面板和日志面板,例如:点击延迟曲线的波峰,直接跳转到该时间段的慢请求日志,查看触发了哪个模型后端、具体耗时多少毫秒。
耗时估算:熟练操作约需 30 分钟,初次上手请预留 1 小时调试时间。
行动清单
- [ ] 在 Deployment 中添加
METRICS_ENABLED等环境变量,确保/metrics可被 Prometheus 访问。 - [ ] 创建 Service 和 ServiceMonitor(或 PodMonitor),验证 Prometheus Targets 状态正常。
- [ ] 配置 JSON 格式日志输出,部署 Promtail 采集并转发到 Loki,在 Grafana 中建立日志查询。
- [ ] 加入执行循环延迟和记忆写入失败的告警规则,配置 Alertmanager 通知。
- [ ] 在 Grafana 中构建一个综合仪表板,至少包含:
P99 循环延迟、请求速率、错误数、日志流四个面板。
在下一章《陈述性记忆通过双文件结构分离了环境事实与用户偏好》中,我们将深入 Hermes Agent 记忆最精妙的设计:为什么“MEMORY.md”和“USER.md”要分开存储?这种双文件结构如何让 Agent 在不混淆环境事实与用户偏好的前提下,实现长期的个性化记忆?这些问题的答案,会成为你进一步调优 Agent 一致性和安全性的关键。
Hermes Agent 系统设计与工程落地
关于 LearnKu