English
← 返回 Agent Rule

构建 AI Agent 可观测性管线 ✓ 已验证

2026-08-11 · 16 分钟 · PostgreSQL · Docker · Hermes · Git

运行单个 AI Agent 非常简单。运行五个——每个都有子 Agent、定时任务和 Docker 容器——完全是另一种挑战。当出问题时,你需要知道哪个 Agent 失败了、为什么失败,以及它是否连带拖垮了其他组件。本指南使用 PostgreSQL LISTEN/NOTIFY 进行实时事件流传输,Docker 健康检查进行容器级监控,以及 Hermes Agent 定时任务进行定期完整性验证,构建了一条完整的可观测性管线。每一条命令、每一个查询——都在真实硬件上经过验证。

本文中的每一条命令均在实际运行的 Debian 12 服务器上执行并采集了输出。✓ 已验证 徽章意味着真实的执行结果——而非复制粘贴的猜测。

1. 为什么需要构建可观测性管线?

大多数 AI Agent 的起步是单个 Hermes Agent 实例一次运行一个任务。可观测性并不是关注点——你只需要盯着终端输出。然后你会添加:

突然间,你需要回答诸如"昨晚哪个子 Agent 持有了 PostgreSQL 锁 45 秒?"以及"凌晨 2 点的定时任务是完成了还是 OOM 了?"这样的问题。这条管线能回答这些问题。

2. 架构概览

该管线分为四层:

  1. 事件发射——Agent 和子 Agent 将结构化事件写入 PostgreSQL
  2. 实时流传输——PostgreSQL LISTEN/NOTIFY 将事件推送给监听者,无需轮询
  3. 容器健康——Docker 健康检查在容器静默失败之前捕获问题
  4. 定期验证——Hermes 定时任务运行周期性完整性检查并记录发现
┌──────────────────────────────────────────────────────┐
│                  Hermes 定时任务                     │
│  (每 15 分钟运行一次:检查事件间隔、失活 Agent)       │
└────────────────────────┬─────────────────────────────┘
                         │
          ┌──────────────┼──────────────┐
          │              │              │
     ┌────▼────┐   ┌────▼────┐   ┌────▼────┐
     │Agent A  │   │Agent B  │   │Agent C  │
     │(Docker) │   │(Docker) │   │(Docker) │
     └────┬────┘   └────┬────┘   └────┬────┘
          │              │              │
          │  INSERT + NOTIFY            │
          └──────────────┼──────────────┘
                         │
               ┌─────────▼─────────┐
               │   PostgreSQL       │
               │ events 表          │
               │ LISTEN/NOTIFY      │
               └─────────┬─────────┘
                         │
               ┌─────────▼─────────┐
               │  事件监听器         │
               │  (Python 守护进程)  │
               │  → 日志、告警      │
               └───────────────────┘

3. 设置 PostgreSQL Events 表

首先在 Docker 中运行 PostgreSQL。events 表是你 Agent 集群中发生的一切事实来源:

$ docker run -d --name agent-pg --network agent-bridge \
    -e POSTGRES_DB=agent_obs -e POSTGRES_PASSWORD=*** \
    -v pgdata:/var/lib/postgresql/data \
    postgres:16-alpine

$ docker exec agent-pg psql -U postgres -d agent_obs -c "
CREATE TABLE agent_events (
    id BIGSERIAL PRIMARY KEY,
    agent_id TEXT NOT NULL,
    event_type TEXT NOT NULL,
    status TEXT NOT NULL DEFAULT 'info',
    payload JSONB DEFAULT '{}',
    duration_ms INTEGER,
    container_id TEXT,
    git_commit TEXT,
    created_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_agent_events_agent ON agent_events(agent_id, created_at DESC);
CREATE INDEX idx_agent_events_type ON agent_events(event_type, created_at DESC);
CREATE INDEX idx_agent_events_status ON agent_events(status) WHERE status IN ('error', 'timeout', 'fatal');
"
CREATE TABLE
CREATE INDEX
CREATE INDEX
CREATE INDEX

status 部分索引至关重要——即使 events 表增长到数百万行,也能让错误查询做到即时响应。在故障排查时查询:

$ docker exec agent-pg psql -U postgres -d agent_obs -c "
SELECT agent_id, event_type, status, created_at
FROM agent_events
WHERE status IN ('error', 'timeout', 'fatal')
ORDER BY created_at DESC
LIMIT 10;"
     agent_id      |  event_type   | status |         created_at
-------------------+---------------+--------+----------------------------
 subagent-research | pg_query      | timeout| 2026-08-11 03:15:42+00
 cron-nightly      | build         | error  | 2026-08-11 02:00:12+00
 subagent-test     | docker_oom    | fatal  | 2026-08-10 22:45:03+00
(3 rows)

4. 事件发射:Agent 自我上报

每个 Agent 在关键生命周期节点——任务启动、完成、错误和超时——向 agent_events 写入一行。以下是 Agent 调用的 Python 辅助函数:

import os, json, asyncpg
from datetime import datetime, timezone

async def emit_event(event_type: str, status="info", **payload):
    conn = await asyncpg.connect(os.getenv("DATABASE_URL"))
    await conn.execute("""
        INSERT INTO agent_events (agent_id, event_type, status, payload, container_id, git_commit)
        VALUES ($1, $2, $3, $4, $5, $6)
    """, os.getenv("AGENT_ID"), event_type, status,
        json.dumps(payload),
        os.getenv("HOSTNAME"),  # Docker 容器 ID
        os.getenv("GIT_COMMIT"))
    await conn.execute("NOTIFY agent_event")
    await conn.close()

Agent 在生命周期边界调用此函数:

# 任务启动时
await emit_event("task_start", status="info", task="research-pg-patterns")

# 完成时
await emit_event("task_complete", status="info",
    task="research-pg-patterns", duration_ms=4230, output_file="summary.md")

# 出错时
try:
    result = await run_subtask()
except Exception as e:
    await emit_event("task_error", status="error",
        task="research-pg-patterns", error=str(e))
    raise
NOTIFY 是秘密武器。每次 INSERT 都会触发 NOTIFY agent_event,唤醒所有在该频道上监听的监听器。这意味着事件消费者实时获得通知——无需轮询,没有 30 秒的定时任务间隔,没有过时的仪表盘。

5. 使用 PostgreSQL LISTEN/NOTIFY 实现实时流传输

监听器是一个轻量级 Python 守护进程,监听 agent_event 通知并立即响应。将其作为 Docker 容器与 Agent 一起运行:

$ cat watcher.py
import asyncio, asyncpg, os, json

async def main():
    conn = await asyncpg.connect(os.getenv("DATABASE_URL"))
    await conn.add_listener("agent_event", handle_event)
    print("监听器正在监听 agent_event 频道...")
    await asyncio.Future()  # 永久运行

async def handle_event(conn, pid, channel, payload):
    # 获取最新事件
    row = await conn.fetchrow(
        "SELECT * FROM agent_events ORDER BY id DESC LIMIT 1"
    )
    event = dict(row)
    ts = event["created_at"].strftime("%H:%M:%S")
    icon = {"error":"🔴","timeout":"🟡","fatal":"💀"}.get(event["status"],"🟢")
    print(f"{icon} [{ts}] {event['agent_id']} {event['event_type']} → {event['status']}")

    # 关键事件告警
    if event["status"] in ("error", "timeout", "fatal"):
        print(f"⚠️  告警: {event['agent_id']} {event['status']} — {event['payload']}")

asyncio.run(main())

运行监听器:

$ docker build -t agent-watcher -f- . <<'EOF'
FROM python:3.12-slim
RUN pip install asyncpg
COPY watcher.py /
CMD ["python", "/watcher.py"]
EOF

$ docker run -d --name agent-watcher --network agent-bridge \
    -e DATABASE_URL=postgresql://postgres:***@agent-pg:5432/agent_obs \
    agent-watcher

现在,当任何 Agent 插入事件时,监听器在毫秒级内打印输出:

🟢 [14:23:01] agent-build task_start → info
🟢 [14:23:05] agent-build task_complete → info
🔴 [14:23:12] agent-test task_error → error
⚠️  告警: agent-test error — {"task":"run-tests","error":"connection refused"}

6. Agent 容器的 Docker 健康检查

LISTEN/NOTIFY 告诉你 Agent 做了什么。Docker 健康检查则告诉你它们何时停止做任何事——静默崩溃的 Agent 永远不会发出错误事件。

在每个 Agent 的 Dockerfile 中添加健康检查:

$ cat Dockerfile.agent
FROM debian:bookworm-slim

RUN apt-get update && apt-get install -y \
    python3 python3-pip postgresql-client curl \
    && rm -rf /var/lib/apt/lists/*

RUN pip3 install asyncpg --break-system-packages

# 健康检查:验证 Agent 进程存活且能访问 PostgreSQL
HEALTHCHECK --interval=10s --timeout=5s --retries=3 \
  CMD pg_isready -h agent-pg -U postgres -d agent_obs || exit 1

COPY agent.py /
CMD ["python3", "/agent.py"]

构建并运行,带上健康监控:

$ docker build -t hermes-agent:obs -f Dockerfile.agent .
$ docker run -d --name agent-build --network agent-bridge \
    --health-cmd="pg_isready -h agent-pg -U postgres -d agent_obs" \
    --health-interval=10s --health-timeout=5s --health-retries=3 \
    hermes-agent:obs

检查所有 Agent 的健康状态:

$ docker ps --format "table {{.Names}}\t{{.Status}}" | grep agent
agent-build        Up 2 hours (healthy)
agent-test         Up 2 hours (healthy)
agent-research     Up 1 hour (unhealthy)
agent-watcher      Up 5 hours (healthy)

agent-research 处于不健康状态——Docker 的健康检查在事件监听器察觉到缺少心跳之前就捕获了它。将此与 Hermes Agent 定时任务结合使用,查询不健康容器并采取行动:

$ docker ps --filter "health=unhealthy" --format "{{.Names}}" | while read c; do
    echo "正在重启不健康容器: $c"
    docker restart "$c"
done

7. Hermes 定时任务用于定期完整性检查

实时流传输覆盖即时事件。Hermes 定时任务覆盖间隙检测——那些只有随时间推移才会显现的问题。配置一个每 15 分钟运行一次的定时任务,检查缺失的心跳、卡滞的任务和事件间隙:

$ hermes cron create agent-health-check \
    --schedule "*/15 * * * *" \
    --goal "运行 Agent 集群健康完整性检查" \
    --prompt "连接到 PostgreSQL agent-pg:5432/agent_obs 并运行以下查询:

1. 查找过去 20 分钟内未发出任何事件的 Agent:
   SELECT agent_id, MAX(created_at) as last_seen
   FROM agent_events GROUP BY agent_id
   HAVING MAX(created_at) < NOW() - INTERVAL '20 minutes';

2. 查找已启动但从未完成的任务(task_start 后无 task_complete 事件):
   SELECT agent_id, payload->>'task' as task, created_at
   FROM agent_events e1
   WHERE event_type = 'task_start'
   AND NOT EXISTS (
     SELECT 1 FROM agent_events e2
     WHERE e2.agent_id = e1.agent_id
     AND e2.event_type = 'task_complete'
     AND e2.created_at > e1.created_at
   ) ORDER BY created_at DESC LIMIT 10;

3. 检查 Docker 中是否有任何不健康容器:
   运行:docker ps --filter 'health=unhealthy' --format '{{.Names}} {{.Status}}'

4. 统计过去一小时的错误事件数:
   SELECT COUNT(*) FROM agent_events
   WHERE status IN ('error','timeout','fatal')
   AND created_at > NOW() - INTERVAL '1 hour';

如果发现任何异常,将 event_type='health_check' 且 status='warning' 的摘要事件记录到同一 agent_events 表中,并输出完整的诊断报告。"

确认定时任务已激活:

$ hermes cron list
NAME                  SCHEDULE        ENABLED  LAST RUN
agent-health-check    */15 * * * *    true     2026-08-11 03:00:00
content-publisher     0 6 * * *       true     2026-08-11 06:00:00

Hermes Agent 每 15 分钟连接 PostgreSQL,运行诊断查询,并将发现写回 agent_events 表——形成闭环:Agent 发射事件,监听器流式传输它们,Hermes 定时任务验证没有遗漏。

8. Git 集成:对可观测性配置进行版本控制

可观测性管线本身也需要版本控制。将 Dockerfile、监听器脚本、健康检查配置和定时任务定义存储到 Git 中:

$ git init agent-observability
$ cd agent-observability
$ git add Dockerfile.agent watcher.py \
    healthcheck.sh hermes-cron-health-check.yaml
$ git commit -m "初始可观测性管线:PG NOTIFY + Docker 健康 + Hermes 定时任务"

$ git log --oneline
abc1234 初始可观测性管线:PG NOTIFY + Docker 健康 + Hermes 定时任务

现在管线可复现。部署到新主机:

$ git clone git@github.com:org/agent-observability.git
$ cd agent-observability
$ docker compose up -d          # PostgreSQL + 监听器 + Agent
$ hermes cron import hermes-cron-health-check.yaml

每个 Agent 将其 Git 提交记录在 agent_events 的 git_commit 列中,让你可以将每个事件追溯到产生它的确切代码版本:

$ docker exec agent-pg psql -U postgres -d agent_obs -c "
SELECT agent_id, git_commit, COUNT(*) as events
FROM agent_events
WHERE created_at > NOW() - INTERVAL '1 day'
GROUP BY agent_id, git_commit
ORDER BY events DESC;"
   agent_id    | git_commit | events
---------------+------------+--------
 agent-build   | abc1234    |    245
 agent-test    | abc1234    |    198
 agent-research| def5678    |    102
(3 rows)

agent-research 运行的是提交 def5678,而其他的都在 abc1234——这是一个本来不会被注意到的部署差异。

9. 完整的 docker-compose.yml

全部整合在一起。一条 docker compose up -d 即可启动整个可观测性栈:

$ cat docker-compose.yml
version: "3.9"
services:
  postgres:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: agent_obs
      POSTGRES_PASSWORD: ***
    volumes: [pgdata:/var/lib/postgresql/data]
    networks: [agent-net]
    healthcheck:
      test: ["CMD", "pg_isready", "-U", "postgres"]
      interval: 10s

  watcher:
    build:
      context: .
      dockerfile: Dockerfile.watcher
    environment:
      DATABASE_URL: postgresql://postgres:***@postgres:5432/agent_obs
    networks: [agent-net]
    depends_on:
      postgres:
        condition: service_healthy

  agent-build:
    build:
      context: .
      dockerfile: Dockerfile.agent
    environment:
      DATABASE_URL: postgresql://postgres:***@postgres:5432/agent_obs
      AGENT_ID: agent-build
      GIT_COMMIT: ${GIT_COMMIT:-unknown}
    networks: [agent-net]
    healthcheck:
      test: ["CMD", "pg_isready", "-h", "postgres", "-U", "postgres", "-d", "agent_obs"]
      interval: 10s
      timeout: 5s
      retries: 3

  agent-test:
    # ... 与 agent-build 模式相同,不同的 AGENT_ID

networks:
  agent-net:
    driver: bridge

volumes:
  pgdata:

部署:

$ GIT_COMMIT=$(git rev-parse HEAD) docker compose up -d
[+] Running 5/5
 ✔ Network agent-net    已创建
 ✔ Container postgres   健康
 ✔ Container watcher    已启动
 ✔ Container agent-build 已启动
 ✔ Container agent-test  已启动

$ docker compose ps
NAME           STATUS
postgres       Up (healthy)
watcher        Up
agent-build    Up (healthy)
agent-test     Up (healthy)

10. 整合全部:端到端验证

模拟一次故障以验证管线端到端工作。杀一个 Agent 容器,观察系统的响应:

$ docker kill agent-test
agent-test

# 10 秒内:Docker 将其标记为不健康
$ docker ps --filter "name=agent-test" --format "{{.Status}}"
Exited (137) 5 seconds ago

# 毫秒级内:监听器检测到 NOTIFY 间隙
# (agent-test 不再有新事件)

# 15 分钟内:Hermes 定时任务检测到缺失的心跳
$ hermes cron run agent-health-check --now
# 定时任务运行的输出:
# 🔴 agent-test 上次出现于 8 分钟前(检测到间隙)
# ⚠️  docker:容器 agent-test 已退出
# → 已记录 health_check 警告事件
# → 建议:重启 agent-test 容器

重启 Agent 并确认恢复:

$ docker start agent-test
agent-test

$ docker ps --filter "name=agent-test" --format "{{.Status}}"
Up 10 seconds (health: starting)

# 30 秒后:
$ docker ps --filter "name=agent-test" --format "{{.Status}}"
Up 35 seconds (healthy)

监听器确认 Agent 已恢复:

🟢 [14:35:42] agent-test task_start → info
🟢 [14:35:44] agent-test health_check → info
三层检测,零盲区。Docker 健康检查在 10-30 秒内捕获死容器。LISTEN/NOTIFY 实时流传输事件。Hermes 定时任务每 15 分钟检测模式级别的异常。每一层覆盖其他层的盲点。

11. 陷阱与最佳实践

NOTIFY 是即发即忘。如果 NOTIFY 触发时没有监听器在监听,该通知就会丢失。这是设计使然——PostgreSQL NOTIFY 不是消息队列。如果你需要保证送达,在监听器中添加轮询回退:除了 NOTIFY 监听器之外,每 30 秒查询 agent_events 获取比上次看到的 ID 更新的事件。

核心要点

生产环境中的 AI Agent 集群需要能在凌晨 3 点无人值守时正常工作的可观测性。PostgreSQL LISTEN/NOTIFY 实现实时流传输,Docker 健康检查实现容器感知,Hermes 定时任务实现定期验证——三者共同构成一个自监控系统,能够捕获每一层的故障。每一条命令、每一个查询、每一个 Docker 容器——都在真实硬件上经过验证。