运维 Subagent

让 AI 帮你巡检系统、写运维笔记、复盘问题 -- 24/7 不休息的运维助手


你将学到

  • 理解运维 Subagent 的概念和价值
  • 编写 Agent 配置文件定义运维职责
  • 创建巡检脚本自动检查服务状态
  • 配置 macOS LaunchAgent 定时执行
  • 利用 Agent 自动记录运维笔记和复盘

前置条件:已完成 Claude Code 配置,了解基础 shell 脚本

预计时间:45 分钟


一、什么是运维 Subagent

问题场景

你部署了多个 AI 服务 -- MLX 推理引擎、OpenClaw 网关、监控面板、Telegram Bot......

每天你需要:

  • 检查每个服务是否正常运行
  • 翻看日志找异常
  • 发现问题后排查修复
  • 记录发生了什么、怎么修的

服务少的时候手动搞没问题。但当你有 5 个、10 个服务时,这些重复工作就变成了负担。

解决方案

运维 Subagent = 专门负责系统巡检和维护的 AI Agent

Claude Code 支持 Agent 模式,可以自主执行复杂任务链 -- 读文件、跑命令、分析结果、做决策、写报告。你可以把它训练成一个"首席运维官":

code
你(老板)
  |
  v
运维 Subagent(7x24 在线的运维工程师)
  |
  +-- 定时巡检所有服务
  +-- 分析日志发现异常
  +-- 写运维笔记
  +-- 复盘历史问题
  +-- 提出优化建议

类比:你雇了一个 24 小时在线的运维工程师。他不会累、不会忘、不会漏检。你只需要定义好他该做什么、怎么做。


二、Agent 配置文件

文件位置

Claude Code 的 Agent 定义文件放在 ~/.claude/agents/ 目录:

code
mkdir -p ~/.claude/agents

配置框架

创建 ~/.claude/agents/ops-agent.md,这是你的运维 Agent 的"岗位说明书":

code
# ops-agent.md
 
## 身份
 
你是系统运维助手,负责监控和维护本机所有 AI 服务。
你的工作目标是:确保所有服务健康运行,发现问题及时报告。
 
## 服务清单
 
| 服务 | 端口 | 检查方式 | 重要性 |
|------|------|----------|--------|
| MLX 推理引擎 | 8000 | curl /v1/models | 核心 |
| OpenClaw 网关 | 18789 | curl /api/health | 核心 |
| 监控面板 API | 3940 | curl /api/v1/status | 重要 |
| 监控面板前端 | 3939 | curl / | 重要 |
| Open WebUI | 3000 | curl / | 普通 |
 
## 巡检流程
 
### Phase 1: 服务存活
对服务清单中的每个端口执行 HTTP 检查,超时 3 秒。
标记状态:正常 / 不可达 / 响应异常
 
### Phase 2: 资源检查
- 内存使用率(vm_stat 解析)
- 磁盘使用率(df -h)
- MLX 模型内存占用
 
### Phase 3: 日志分析
检查以下日志文件最近 1 小时的 ERROR / FATAL:
- ~/logs/mlx-server.log
- ~/logs/openclaw.log
 
### Phase 4: 汇总报告
按以下格式输出:
 
#### 巡检报告 YYYY-MM-DD HH:mm
- 故障数:X
- 警告数:X
- 服务状态:[列表]
- 发现的问题:[详情]
- 建议操作:[列表]
 
## 安全规则
 
- 绝不自行重启任何服务
- 发现需要重启的情况,报告给用户,由用户手动执行
- 不修改任何配置文件,只读取和分析

关键设计原则

  1. 服务清单要完整 -- 遗漏一个服务就等于巡检盲区
  2. 巡检流程要明确 -- 每个 Phase 的输入、检查项、输出都要写清楚
  3. 安全边界要严格 -- Agent 只读不写,只报告不操作
  4. 输出格式要规范 -- 统一格式方便后续自动化处理

调用 Agent

code
# 在 Claude Code 中调用自定义 Agent
claude --agent ops-agent
 
# 或者用 /agent 命令
# 进入 Claude Code 后输入:
# /agent ops-agent

三、巡检脚本

Agent 配置文件定义了"做什么",巡检脚本则提供了"怎么做"的基础工具。

基础巡检脚本

创建 ~/scripts/patrol.sh

code
#!/bin/bash
# patrol.sh - 服务巡检脚本
# 用法: bash ~/scripts/patrol.sh
 
set -euo pipefail
 
# ===== 配置 =====
TIMEOUT=3  # curl 超时秒数
REPORT=""
FAILURES=0
WARNINGS=0
 
# 服务列表:名称|端口|路径
SERVICES=(
  "MLX推理引擎|8000|/v1/models"
  "OpenClaw网关|18789|/api/health"
  "监控面板API|3940|/api/v1/status"
  "监控面板前端|3939|/"
  "OpenWebUI|3000|/"
)
 
# ===== 函数 =====
 
check_service() {
  local name="$1"
  local port="$2"
  local path="$3"
 
  local http_code
  http_code=$(curl -s -o /dev/null -w "%{http_code}" \
    --connect-timeout "$TIMEOUT" \
    "http://localhost:${port}${path}" 2>/dev/null || echo "000")
 
  if [ "$http_code" = "200" ]; then
    echo "  [OK]  $name (:$port)"
  elif [ "$http_code" = "000" ]; then
    echo "  [FAIL] $name (:$port) - 不可达"
    FAILURES=$((FAILURES + 1))
  else
    echo "  [WARN] $name (:$port) - HTTP $http_code"
    WARNINGS=$((WARNINGS + 1))
  fi
}
 
check_memory() {
  local mem_pressure
  mem_pressure=$(memory_pressure 2>/dev/null | head -1 || echo "unknown")
  echo "  内存压力: $mem_pressure"
 
  # 磁盘使用
  local disk_usage
  disk_usage=$(df -h / | tail -1 | awk '{print $5}')
  echo "  磁盘使用: $disk_usage"
}
 
check_launchagents() {
  echo "  LaunchAgent 状态:"
  for plist in ~/Library/LaunchAgents/ai.*.plist; do
    [ -f "$plist" ] || continue
    local label
    label=$(basename "$plist" .plist)
    local status
    status=$(launchctl list | grep "$label" || echo "未加载")
    if echo "$status" | grep -q "$label"; then
      echo "    [OK]  $label"
    else
      echo "    [--]  $label (未运行)"
    fi
  done
}
 
check_logs() {
  local log_dir="${1:-$HOME/logs}"
  local hours="${2:-1}"
  local cutoff
  cutoff=$(date -v-${hours}H +%Y-%m-%d\ %H:%M 2>/dev/null || date +%Y-%m-%d\ %H:%M)
 
  echo "  最近 ${hours}h 错误日志:"
  for logfile in "$log_dir"/*.log; do
    [ -f "$logfile" ] || continue
    local errors
    errors=$(grep -ci "error\|fatal\|panic" "$logfile" 2>/dev/null || echo "0")
    if [ "$errors" -gt 0 ]; then
      echo "    [!] $(basename "$logfile"): $errors 条错误"
      WARNINGS=$((WARNINGS + 1))
    fi
  done
}
 
# ===== 执行 =====
 
echo "=============================="
echo "  巡检报告 $(date '+%Y-%m-%d %H:%M')"
echo "=============================="
echo ""
 
echo "[Phase 1] 服务存活检查"
for svc in "${SERVICES[@]}"; do
  IFS='|' read -r name port path <<< "$svc"
  check_service "$name" "$port" "$path"
done
echo ""
 
echo "[Phase 2] 系统资源"
check_memory
echo ""
 
echo "[Phase 3] LaunchAgent"
check_launchagents
echo ""
 
echo "[Phase 4] 日志分析"
check_logs "$HOME/logs" 1
echo ""
 
echo "=============================="
echo "  故障: $FAILURES | 警告: $WARNINGS"
echo "=============================="

使用

code
# 赋予执行权限
chmod +x ~/scripts/patrol.sh
 
# 运行巡检
bash ~/scripts/patrol.sh

输出示例:

code
==============================
  巡检报告 2026-03-07 14:30
==============================

[Phase 1] 服务存活检查
  [OK]  MLX推理引擎 (:8000)
  [OK]  OpenClaw网关 (:18789)
  [OK]  监控面板API (:3940)
  [OK]  监控面板前端 (:3939)
  [OK]  OpenWebUI (:3000)

[Phase 2] 系统资源
  内存压力: The system is under no memory pressure.
  磁盘使用: 1%

[Phase 3] LaunchAgent
  LaunchAgent 状态:
    [OK]  ai.mlx-lm-server
    [OK]  ai.openclaw.gateway
    [OK]  ai.neowatch-backend

[Phase 4] 日志分析
  最近 1h 错误日志:

==============================
  故障: 0 | 警告: 0
==============================

脚本设计要点

  • 超时必须设置 -- 服务卡死时 curl 不会一直等
  • 错误处理要完善 -- set -euo pipefail|| echo 兜底
  • 输出格式要规范 -- 方便 Agent 解析,也方便人类阅读
  • 服务列表要可扩展 -- 数组结构,增删服务只改一行

四、定时执行

巡检不能全靠手动。macOS 的 LaunchAgent 可以让脚本定时自动运行。

创建 LaunchAgent

创建 ~/Library/LaunchAgents/ai.patrol.plist

code
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
  "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>ai.patrol</string>
 
    <key>ProgramArguments</key>
    <array>
        <string>/bin/bash</string>
        <string>/Users/你的用户名/scripts/patrol.sh</string>
    </array>
 
    <!-- 每 2 小时执行一次(偶数小时的第 10 分钟) -->
    <key>StartCalendarInterval</key>
    <array>
        <dict>
            <key>Minute</key>
            <integer>10</integer>
            <key>Hour</key>
            <integer>0</integer>
        </dict>
        <dict>
            <key>Minute</key>
            <integer>10</integer>
            <key>Hour</key>
            <integer>2</integer>
        </dict>
        <dict>
            <key>Minute</key>
            <integer>10</integer>
            <key>Hour</key>
            <integer>4</integer>
        </dict>
        <!-- 继续添加 6, 8, 10, 12, 14, 16, 18, 20, 22 -->
    </array>
 
    <key>StandardOutPath</key>
    <string>/Users/你的用户名/logs/patrol.out.log</string>
    <key>StandardErrorPath</key>
    <string>/Users/你的用户名/logs/patrol.err.log</string>
 
    <key>EnvironmentVariables</key>
    <dict>
        <key>PATH</key>
        <string>/usr/local/bin:/usr/bin:/bin:/usr/sbin</string>
    </dict>
</dict>
</plist>

加载与管理

code
# 加载(开机自启)
launchctl load ~/Library/LaunchAgents/ai.patrol.plist
 
# 手动触发一次(测试用)
launchctl start ai.patrol
 
# 查看状态
launchctl list | grep ai.patrol
 
# 卸载(停止定时执行)
launchctl unload ~/Library/LaunchAgents/ai.patrol.plist

LaunchAgent vs Cron

特性LaunchAgentCron
macOS 原生
错过执行后补偿支持不支持
日志管理内置需自行配置
环境变量可在 plist 中定义继承用户环境
推荐度推荐简单任务可用

LaunchAgent 的优势在于:如果定时触发时电脑处于睡眠状态,唤醒后会自动补执行。Cron 错过就错过了。

注意事项

PATH 环境变量

LaunchAgent 的 PATH 和你终端里的不同。如果脚本里用了 brew 安装的工具(如 jq), 必须在 plist 的 EnvironmentVariables 中显式设置 PATH,包含 /usr/local/bin。 同理,sysctl 等系统命令在 /usr/sbin,也要包含。


五、笔记与复盘

自动运维笔记

运维 Agent 最有价值的能力之一是自动记录。每次巡检、每次故障排查,Agent 都可以写笔记。

在 Agent 配置中添加笔记规则:

code
## 笔记规则
 
每次巡检后,在 ~/Desktop/笔记/ 目录创建运维笔记:
 
### 文件名格式
运维-YYYY-MM-DD.md
 
### 笔记结构
 
# 运维: [日期]
> 巡检时间: HH:mm | 故障: X | 警告: X
 
## 服务状态
[表格]
 
## 发现的问题
### 问题 1: [标题]
- 症状: ...
- 原因: ...
- 修复: ...
- 教训: ...
 
## 系统快照
| 指标 | 值 |
|------|-----|
 
## 运维建议
### 短期
- [ ] ...
### 长期
- [ ] ...

复盘流程

Agent 不仅记录当次巡检,还可以复盘历史问题:

code
## 复盘流程
 
当用户说"复盘"或"recap"时:
 
1. 读取最近 7 天的运维笔记
2. 统计:
   - 故障总数和分类
   - 重复出现的问题
   - 平均修复时间
3. 分析趋势:
   - 哪些服务最不稳定
   - 哪些问题反复出现
   - 资源使用趋势
4. 输出复盘报告,包含:
   - 本周运维总结
   - Top 3 问题及根因
   - 改进建议
   - 更新到记忆文件

知识库积累

运维笔记长期积累后,就成了你的运维知识库

code
~/Desktop/笔记/
  运维-2026-03-01.md    # NEO运维升级复盘
  运维-2026-03-02.md    # 六宝事件驱动刷新
  运维-2026-03-03.md    # 日常巡检
  ...

Agent 每次巡检时都会参考历史笔记,避免重复犯错。比如上次某个服务挂了是因为内存不足,Agent 会记住这个模式,下次看到内存接近阈值时提前预警。


六、实际案例:NEO运维的实践

从 5 个服务到 10 个服务

AINEOS 的运维 Agent 从最初的 5 个服务起步,经历了一次完整的扩展过程:

初始阶段(5 个服务)

code
MLX 推理引擎 (:8000)
OpenClaw 二宝 (:18789)
NeoWatch 后端 (:3940)
NeoWatch 前端 (:3939)
Open WebUI (:3000)

扩展后(10 个端口)

code
MLX 推理引擎 (:8000)           # 核心 - 模型推理
OpenClaw 二宝 (:18789)         # 管家 - 日报、心跳
OpenClaw 三宝 (:18790)         # 交易员 - 加密货币分析
四宝引擎 (:3721)               # 量化 - 宝藏发现
四宝大脑 (:18796)              # 量化 - 决策中心
六宝引擎 (:6789)               # 预测市场 - 交易执行
六宝大脑 (:18795)              # 预测市场 - 策略分析
NeoWatch 后端 (:3940)          # 监控 - API
NeoWatch 前端 (:3939)          # 监控 - 仪表盘
Open WebUI (:3000)             # 聊天界面

扩展过程中的教训

这次扩展涉及 9 个文件变更,包括 Agent 配置、巡检脚本、服务管理脚本等。以下是几个关键教训:

1. 服务清单必须同步更新

新增服务后,所有相关的配置都要更新 -- Agent 定义、巡检脚本、监控采集器、文档。遗漏任何一个都会产生巡检盲区。

2. 日志路径要覆盖所有实例

初始版本只检查 3 个日志文件,扩展后需要覆盖 8 个。4 个 OpenClaw 实例各有独立的日志目录。

3. 定时巡检的误报处理

有些服务是周期性运行的(比如 cron 触发的分析任务),巡检时可能正好处于空闲状态。脚本需要维护一个"周期性服务白名单",避免误报。

4. Agent 安全边界要严格

运维 Agent 绝不自行重启服务。特别是 MLX 推理引擎,重启极易导致 GPU 卡死。Agent 只负责发现问题和报告,由人类决定是否重启。

巡检效果

定时巡检部署后(每 2 小时一次,每天 12 次):

  • 首次巡检发现 1 个配置缺失问题(auth 文件未复制)
  • 日志分析发现 3 个非紧急但需关注的模式
  • 系统状态快照为后续排障提供了基线数据

总结

核心要点

  1. Agent 配置文件 -- 定义运维职责、服务清单、巡检流程
  2. 巡检脚本 -- 自动化的健康检查工具
  3. 定时执行 -- LaunchAgent 保证 7x24 覆盖
  4. 笔记与复盘 -- 积累运维知识库,避免重复犯错

推荐的起步路径

code
第 1 天: 写 Agent 配置 + 基础巡检脚本
第 2 天: 配置 LaunchAgent 定时执行
第 3 天: 添加笔记规则,开始积累知识库
第 7 天: 第一次复盘,优化巡检流程

从 3-5 个服务开始,随着基础设施增长逐步扩展。不要一开始就追求完美 -- 先跑起来,再持续改进。


下一步 OpenClaw 进阶 -->