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_idmodel_backendrequest_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 页面应能看到状态为 UPhermes-agent 端点。
同时可以在 Grafana 中添加 Prometheus 数据源,使用 agent_execution_loop_duration_seconds_bucket 等指标构建初步面板。

1.4 预期结果

  • 每个 Pod 的 /metrics 端点返回 Prometheus 格式数据。
  • Prometheus 成功抓取所有 Pod 的指标。
  • Grafana 可以查询到 http_requests_totalagent_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 名称和量化数值,直接定位问题。

回顾

本章你完成了一个从“盲飞”到“全观测”的飞跃:

  1. 启用了 Hermes Agent 的 Prometheus 指标端点,让每个 Pod 暴露内部运行时状态。
  2. 配置了 ServiceMonitor,使 Prometheus 自动发现并采集指标;同时搭建了 Grafana 数据源。
  3. 将日志输出改为结构化 JSON,并通过 Loki + Promtail 实现集中检索与分析。
  4. 编写了针对执行循环延迟和记忆写入失败的 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 一致性和安全性的关键。

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
讨论数量: 0
发起讨论 只看当前版本


暂无话题~