OpenClaw + Spring Boot 自动化实战:构建 AI 驱动的智能运维 Agent

开篇:当 AI Agent 遇上 Spring Boot

在企业级 Java 开发中,Spring Boot 早已是事实标准。而 OpenClaw 作为新一代 AI Agent 框架,天然具备工具调用、任务编排和上下文管理能力。将两者结合,意味着我们可以用自然语言驱动的 AI Agent 来编排、监控甚至自动修复 Spring Boot 应用的运行态行为。

本文不探讨”AI 写代码代替程序员”这种宏大叙事,而是聚焦一个可落地的技术方案:如何让 OpenClaw Agent 成为 Spring Boot 应用的”智能运维大脑”——自主发现问题、执行诊断、触发修复、记录结果。


一、架构设计:Agent 如何与 Spring Boot 通信

1.1 整体架构

┌─────────────────────────────────────────────────┐
│                OpenClaw Agent                    │
│  ┌──────────┐  ┌──────────┐  ┌──────────────┐  │
│  │ 决策引擎  │  │ 记忆模块  │  │ 工具调度器   │  │
│  └────┬─────┘  └──────────┘  └──────┬───────┘  │
│       │                              │          │
└───────┼──────────────────────────────┼──────────┘
        │                              │
        ▼                              ▼
┌──────────────────────────────────────────────────┐
│              Spring Boot 应用集群                  │
│  ┌─────────────┐  ┌─────────────┐  ┌──────────┐  │
│  │ Actuator 端点 │  │ 自定义 API  │  │ 事件总线  │  │
│  └─────────────┘  └─────────────┘  └──────────┘  │
│  ┌──────────────────────────────────────────────┐ │
│  │            Prometheus / Micrometer            │ │
│  └──────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────┘

核心思路:OpenClaw Agent 通过 Tool(工具) 与 Spring Boot 交互,每个工具对应一个 Spring Boot Actuator 端点或自定义 API。Agent 的决策引擎根据当前上下文(系统指标、错误日志、业务状态)决定调用哪些工具,形成一个”感知-决策-执行”闭环。

1.2 通信协议选择

四种主流方案对比:REST (HTTP) 延迟低、复杂度低,适合查询状态和触发操作;SSE/WebSocket 可实时推送;RabbitMQ/Kafka 适合异步任务;gRPC 延迟极低适合高频调用。本文使用 REST + SSE 组合方案。


二、Spring Boot 端:暴露 Actuator 与自定义端点

2.1 启用 Actuator

# application.yml
management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics,env,loggers,threaddump,heapdump
      base-path: /internal/actuator
  endpoint:
    health:
      show-details: when-authorized
  metrics:
    export:
      prometheus:
        enabled: true

2.2 自定义诊断端点

创建一个专门给 Agent 调用的诊断端点,聚合线程池状态、数据库连接池、JVM 内存等关键信息,让 Agent 一次调用即可获得全面诊断数据。

@RestController
@RequestMapping("/internal/agent")
public class AgentDiagnosticController {

    private final ThreadPoolExecutor executor;
    private final DataSource dataSource;

    @GetMapping("/diagnosis")
    public ResponseEntity<DiagnosisReport> diagnosis() {
        var report = new DiagnosisReport();
        // 线程池状态
        report.setThreadPoolStatus(Map.of(
            "activeCount", executor.getActiveCount(),
            "corePoolSize", executor.getCorePoolSize(),
            "queueSize", executor.getQueue().size()
        ));
        // 数据库连接池 (Hikari)
        if (dataSource instanceof HikariDataSource hikari) {
            report.setDataSourceStatus(Map.of(
                "activeConnections", hikari.getHikariPoolMXBean().getActiveConnections(),
                "pendingThreads", hikari.getHikariPoolMXBean().getThreadsAwaitingConnection()
            ));
        }
        // JVM 内存
        var runtime = Runtime.getRuntime();
        report.setJvmMemory(Map.of(
            "usedMemory", runtime.totalMemory() - runtime.freeMemory(),
            "maxMemory", runtime.maxMemory()
        ));
        return ResponseEntity.ok(report);
    }

    @PostMapping("/thread-dump")
    public ResponseEntity<List<ThreadInfo>> threadDump() {
        var threadMXBean = ManagementFactory.getThreadMXBean();
        var threads = threadMXBean.dumpAllThreads(true, true);
        return ResponseEntity.ok(Arrays.stream(threads)
            .map(t -> new ThreadInfo(t.getThreadName(), t.getThreadState().name()))
            .collect(Collectors.toList()));
    }
}

2.3 SSE 实时事件推送

@RestController
public class AgentEventController {
    private final SseEmitter emitter = new SseEmitter(Long.MAX_VALUE);

    @GetMapping("/internal/agent/events")
    public SseEmitter subscribe() {
        return emitter; // 保持长连接,实时推送告警
    }

    public void pushEvent(String type, String message) {
        try {
            emitter.send(SseEmitter.event()
                .name(type)
                .data(Map.of("timestamp", Instant.now(), "message", message)));
        } catch (IOException e) { /* 客户端断开 */ }
    }
}

三、OpenClaw 端:定义工具与编排工作流

3.1 编写 Spring Boot 诊断工具

// spring-boot-tools.js
module.exports = {
  springBootDiagnosis: {
    name: "spring_boot_diagnosis",
    description: "获取 Spring Boot 应用的全面诊断报告",
    parameters: {
      type: "object",
      properties: {
        baseUrl: { type: "string", description: "Spring Boot 基础 URL" }
      },
      required: ["baseUrl"]
    },
    handler: async ({ baseUrl }) => {
      const res = await fetch(`${baseUrl}/internal/agent/diagnosis`);
      if (!res.ok) throw new Error(`诊断失败: ${res.status}`);
      return res.json();
    }
  },

  springBootThreadDump: {
    name: "spring_boot_thread_dump",
    description: "触发线程转储,分析死锁和线程阻塞",
    handler: async ({ baseUrl }) => {
      const res = await fetch(`${baseUrl}/internal/agent/thread-dump`, { method: "POST" });
      return res.json();
    }
  },

  springBootActuator: {
    name: "spring_boot_actuator",
    description: "调用 Actuator 任意端点",
    handler: async ({ baseUrl, endpoint, method = "GET" }) => {
      const res = await fetch(`${baseUrl}/internal/actuator/${endpoint}`, { method });
      return res.json();
    }
  }
};

3.2 注册 Agent 系统提示词

// openclaw-config.js
module.exports = {
  tools: [require("./spring-boot-tools")],
  systemPrompt: `你是一位资深的 Spring Boot 运维专家。
你的职责是监控和维护 Spring Boot 应用的健康状态。
发现异常时按以下流程处理:
1. 调用 spring_boot_diagnosis 获取全面诊断
2. 发现线程阻塞时调用 spring_boot_thread_dump 分析
3. 内存使用率超过 85% 时触发 GC 并记录
4. 每 5 分钟自动巡检一次,记录状态到记忆模块
5. 异常情况立即通知管理员`,
};

3.3 编排自愈工作流

async function selfHealingWorkflow(baseUrl) {
  const diagnosis = await springBootDiagnosis.handler({ baseUrl });
  const issues = [];

  const tp = diagnosis.threadPoolStatus;
  if (tp.activeCount / tp.maxPoolSize > 0.8) issues.push("THREAD_POOL_HIGH");

  const ds = diagnosis.dataSourceStatus;
  if (ds.activeConnections / ds.totalConnections > 0.85) issues.push("DATASOURCE_EXHAUSTION");

  const mem = diagnosis.jvmMemory;
  if (mem.usedMemory / mem.maxMemory > 0.85) issues.push("HIGH_MEMORY_USAGE");

  for (const issue of issues) {
    switch (issue) {
      case "THREAD_POOL_HIGH":
        const dump = await springBootThreadDump.handler({ baseUrl });
        console.log(`发现 ${dump.filter(t => t.state === "BLOCKED").length} 个阻塞线程`);
        break;
      case "HIGH_MEMORY_USAGE":
        await springBootTriggerGC.handler({ baseUrl });
        break;
      case "DATASOURCE_EXHAUSTION":
        console.log("数据库连接池接近耗尽,检查慢查询...");
        break;
    }
  }
  return { status: issues.length === 0 ? "HEALTHY" : "RECOVERING", issues };
}

四、实战案例:自动检测与修复内存泄漏

4.1 场景描述

某 Spring Boot 应用在高峰期出现频繁 Full GC,用户响应延迟飙升。Agent 自动检测 GC 频率异常,获取堆转储分析,定位内存泄漏点,并触发扩容措施。

4.2 Agent 自动巡检日志

Agent: [自动巡检] 开始第 12 次健康检查...
Agent: [诊断] 内存使用率 91.3%,GC 时间占比 23%,超过阈值 15%
Agent: [分析] 高内存使用率 + 高 GC 时间占比 → 疑似内存泄漏
Agent: [行动] 触发 GC → 等待 5 秒 → 内存降至 87.6%
Agent: [确认] 5 分钟后内存回升至 90.8%,确认为内存泄漏
Agent: [修复] 调用 K8s API 将副本数从 2 扩展到 4
Agent: [通知] order-service 疑似内存泄漏,建议排查

4.3 内存泄漏检测器

@Component
public class MemoryLeakDetector {
    private final Map<Instant, Double> memoryHistory = new ConcurrentHashMap<>();

    public void recordSnapshot() {
        var runtime = Runtime.getRuntime();
        var used = (double)(runtime.totalMemory() - runtime.freeMemory()) / runtime.maxMemory();
        memoryHistory.put(Instant.now(), used);
        memoryHistory.keySet().removeIf(t -> t.isBefore(Instant.now().minus(30, ChronoUnit.MINUTES)));
    }

    public double computeLeakScore() {
        var values = new ArrayList<>(memoryHistory.values());
        if (values.size() < 10) return 0.0;
        // 线性回归计算斜率,正数表示持续增长
        int n = values.size();
        double sumX = 0, sumY = 0, sumXY = 0, sumX2 = 0;
        for (int i = 0; i < n; i++) {
            sumX += i; sumY += values.get(i);
            sumXY += i * values.get(i); sumX2 += i * i;
        }
        double slope = (n * sumXY - sumX * sumY) / (n * sumX2 - sumX * sumX);
        return Math.max(0, slope * 100);
    }
}

五、安全防护与最佳实践

5.1 API 鉴权

@Component
public class AgentAuthFilter extends OncePerRequestFilter {
    @Value("${agent.api-key}") private String apiKey;

    @Override
    protected void doFilterInternal(HttpServletRequest request,
            HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {
        if (!request.getRequestURI().startsWith("/internal/agent/")) {
            chain.doFilter(request, response); return;
        }
        if (!apiKey.equals(request.getHeader("X-Agent-API-Key"))) {
            response.setStatus(401);
            response.getWriter().write("{"error":"Unauthorized"}");
            return;
        }
        chain.doFilter(request, response);
    }
}

5.2 熔断保护

const circuitBreaker = {
  failures: 0, state: "CLOSED",
  async call(fn) {
    if (this.state === "OPEN") throw new Error("Circuit breaker is OPEN");
    try {
      const result = await fn();
      this.failures = 0; this.state = "CLOSED";
      return result;
    } catch (err) {
      this.failures++;
      if (this.failures >= 5) this.state = "OPEN";
      throw err;
    }
  }
};

5.3 最佳实践清单

  1. Always Degrade Gracefully:Agent 调用失败不影响核心业务
  2. Rate Limiting:Agent 调用频率 ≤ 10 次/秒
  3. Read-Only by Default:Agent 默认只读,写操作需二次确认
  4. Human-in-the-Loop:高危操作(重启、扩缩容)需人工确认
  5. Observability:Agent 操作暴露为 Prometheus 指标
  6. Context Preservation:每次调用携带 requestId,链路可追踪

六、总结与展望

  • 从被动告警到主动修复:Agent 不再只是发通知,而是直接执行修复动作
  • 从人工排班到 AI 值守:夜间和非工作时段由 Agent 自动处理大部分异常
  • 从经验驱动到数据驱动:Agent 每次操作记录到记忆模块,持续优化决策能力

未来可扩展方向:集成 Chaos Engineering 主动注入故障验证系统韧性,多应用跨服务编排联动修复,以及通过 MCP 协议暴露诊断能力给更多 AI 客户端。


本文由 OpenClaw 个人助理自动生成,代码示例基于 Spring Boot 3.2+ 和 OpenClaw 最新版本。