Skip to content

实战案例(一):智能运维助手 ​

1. 本节产出 ​

一个可演示的运维助手:接收告警 → 自动查指标/日志/变更记录 → 给出诊断结论与处置建议 → 高危操作进审批。核心是工具集设计和诊断逻辑的 prompt 工程。

2. 前置依赖 ​

3. 为什么运维是 Agent 最好的落地场景 ​

特点为什么适合
信息分散在多个系统人查要开 5 个页面,Agent 一次搞定
有标准排查流程可编码为 prompt 工作流
只读操作为主风险可控(查指标、查日志、查变更)
故障有紧迫性减少 MTTR 的价值容易量化
结果可验证诊断对不对,很快能验证

关键:运维场景的「只读」特性让它成为最安全的 Agent 落地场景。 先做只读诊断,等信任建立后再逐步开放处置动作——这是一条稳妥的演进路径。

4. 核心原理 ​

4.1 工具集设计 ​

工具风险说明
queryMetrics(service, metric, range)READ_ONLY查 CPU/内存/QPS/错误率
searchLogs(service, keyword, range)READ_ONLY查日志(限流返回条数)
listRecentChanges(service, range)READ_ONLY查最近的发布/配置变更
queryTopology(service)READ_ONLY查依赖拓扑
queryAlerts(service, range)READ_ONLY查历史告警
restartService(service)NEED_APPROVAL重启(高危,必须审批)
scaleOut(service, replicas)NEED_APPROVAL扩容

六个只读 + 两个需审批。这个配比是刻意设计的:让 Agent 90% 的工作是安全的,只在真正要处置时才触发审批。

4.2 诊断流程的 prompt 设计 ​

系统提示(关键部分):

你是 SRE 助手,按以下流程诊断:

1. 确认影响面:查指标,确认是延迟、错误率还是资源问题
2. 定位变更:查最近 2 小时的发布与配置变更
   └─ 有变更 → 高度怀疑是变更引起,优先建议回滚
3. 定位依赖:查拓扑,确认是否上游/下游引起
4. 查日志:用错误关键词检索,找具体错误
5. 给结论:按「现象 / 根因推测 / 置信度 / 建议动作」输出

规则:
- 每步都要调用工具获取证据,不要凭常识推断
- 置信度低于 0.6 时,明确说「需要人工介入」
- 涉及重启/扩容,必须走审批,不要直接建议执行

「有变更 → 优先怀疑变更」这条经验规则是运维的核心知识,写进 prompt 能显著提升诊断准确率。这就是「把专家经验编码进 prompt」的实例。

4.3 置信度与人工介入 ​

输出格式:
  现象:订单服务 P99 从 200ms 涨到 3.2s,错误率 8%
  根因推测:14:32 发布的 v2.3.1 引入了慢查询(置信度 0.85)
  证据:[1] 变更记录 [2] 慢查询日志 [3] 数据库 CPU 曲线
  建议:回滚 v2.3.1(需审批)

必须输出置信度。低于阈值时明确说「需要人工介入」,而不是硬给一个低质量的结论。这是 Agent 产品化的重要细节:知道自己不知道。

4.4 与 RAG 的结合 ​

运维知识库(RAG)提供:
  - 历史故障案例(上次类似现象是怎么处理的)
  - 服务文档(这个服务的架构、依赖、负责人)
  - 应急预案(SOP)

Agent 流程中:
  诊断完成后 → 检索历史相似案例 → 作为参考并入结论

RAG + Agent 的组合:RAG 提供知识,Agent 提供行动。这是企业里最常见的组合形态。

5. 代码走查 ​

5.1 工具实现 ​

java
// ch03-agent/src/main/java/com/aitech/agent/caseops/OpsTools.java
@ToolComponent
public class OpsTools {

    private final MetricsClient metrics;
    private final LogClient logs;
    private final ChangeClient changes;

    @Tool(description = """
            查询指定服务的时间序列指标。
            指标名只能是:cpu、memory、qps、error_rate、p99_latency。
            时间范围用相对表示,如 30m、2h、1d。
            返回采样点摘要(均值、峰值、最新值),不返回全部原始点。
            """)
    @ToolMeta(name = "queryMetrics", risk = READ_ONLY,
              tags = {"ops", "metrics"}, timeout = "10s")
    public String queryMetrics(
            @ToolParam(description = "服务名,如 order-service")
            String service,
            @ToolParam(description = "指标名:cpu/memory/qps/error_rate/p99_latency")
            String metric,
            @ToolParam(description = "时间范围,如 2h、30m、1d")
            String range) {

        Series s = metrics.query(service, metric, range);
        return "服务 %s 的 %s(%s):均值 %.1f,峰值 %.1f,最新 %.1f"
                .formatted(service, metric, range, s.avg(), s.max(), s.latest());
    }

    @Tool(description = """
            检索服务日志中包含关键词的条目。
            关键词应是具体的错误特征,如 NullPointerException、timeout。
            最多返回 10 条,按时间倒序。没有匹配时返回 NOT_FOUND。
            """)
    @ToolMeta(name = "searchLogs", risk = READ_ONLY,
              tags = {"ops", "logs"}, timeout = "15s")
    public String searchLogs(
            @ToolParam(description = "服务名") String service,
            @ToolParam(description = "检索关键词,如具体的异常类名或错误码")
            String keyword,
            @ToolParam(description = "时间范围,如 30m、2h")
            String range) {

        List<LogEntry> hits = logs.search(service, keyword, range, 10);
        if (hits.isEmpty()) return "NOT_FOUND:未找到包含「%s」的日志".formatted(keyword);

        return hits.stream()
                .map(e -> "[%s] %s".formatted(e.time(), abbreviate(e.message(), 200)))
                .collect(Collectors.joining("\n"));
    }

    @Tool(description = """
            重启指定服务。此操作会造成短暂中断,必须人工审批后执行。
            执行前请确认:是否在低峰期、是否有其他处置方案。
            """)
    @ToolMeta(name = "restartService", risk = NEED_APPROVAL,
              tags = {"ops", "action"}, timeout = "60s")
    public String restartService(
            @ToolParam(description = "服务名") String service) {
        return opsApi.restart(service);
    }
}

5.2 运行配置 ​

yaml
agent:
  cases:
    ops:
      limits: { max-iterations: 12, budget-tokens: 120000, timeout: 240s }
      tools: [queryMetrics, searchLogs, listRecentChanges,
              queryTopology, queryAlerts, searchRunbook]
      approval-required: [restartService, scaleOut]

5.3 调用 ​

java
// ch03-agent/src/main/java/com/aitech/agent/caseops/OpsAgentService.java
@Service
public class OpsAgentService {

    private final AgentHarness harness;

    public Diagnosis diagnose(Alert alert) {
        AgentRequest req = AgentRequest.builder()
                .goal("""
                        收到告警:服务 %s,指标 %s 当前值 %s,阈值 %s。
                        请诊断可能的原因并给出处置建议。
                        """.formatted(alert.service(), alert.metric(),
                                alert.value(), alert.threshold()))
                .tenant(alert.tenantId())
                .tools("ops")                    // 只挂载运维工具
                .limits(props.limits("ops"))
                .build();

        AgentResult r = harness.run(req);
        return Diagnosis.from(r);
    }
}

只挂载运维工具是 03-03 动态挂载的实践:12 个候选里选 6 个,选择准确率更高。

6. 跑起来 ​

bash
git checkout ch03-14-ops-agent
docker compose up -d
mvn spring-boot:run
bash
curl -X POST http://localhost:8080/api/ops/diagnose -d '{
  "service":"order-service",
  "metric":"p99_latency",
  "value":"3200ms",
  "threshold":"500ms"
}'

期望输出(演示用 mock 数据):

轮次 1 | queryMetrics(order-service, p99_latency, 2h) → 均值 3100ms,峰值 3400ms
轮次 2 | listRecentChanges(order-service, 2h) → 14:32 发布 v2.3.1,改动:订单查询 SQL
轮次 3 | searchLogs(order-service, "slow query", 30m) → 找到 8 条慢查询日志
轮次 4 | searchRunbook("数据库慢查询") → 匹配到《慢查询应急 SOP》
轮次 5 | 给出结论

诊断结论:
  现象:订单服务 P99 延迟从 200ms 升至 3.2s
  根因推测:14:32 发布的 v2.3.1 引入慢查询(置信度 0.87)
  证据:[1] 指标曲线 [2] 变更记录 [3] 慢查询日志 [4] 历史案例
  建议:回滚 v2.3.1(需审批)→ 已生成审批单
检查项通过标准
多步诊断至少 4 步,每步有工具证据
结论结构化含现象/根因/置信度/建议
低置信度处理证据不足时说「需要人工介入」
高危审批建议重启时生成审批单而非执行
成本控制Token 在预算内

7. 生产避坑 ​

  1. 运维 Agent 必须从只读起步。先做诊断,等准确率被验证、团队建立信任后,再逐步开放处置动作。上来就给写权限,一次误操作就会让整个项目被叫停。
  2. 必须输出置信度并设阈值。不给置信度的话,低质量结论和高质量结论看起来一样,用户无法判断是否该信。低于阈值明确说「需要人工介入」——这是产品可信度的关键。
  3. 「有变更就先怀疑变更」这类经验规则要显式写进 prompt。这是 SRE 的老经验,但模型不会自己总结出来。把领域专家的排查顺序编码进系统提示,准确率提升非常明显。

8. 延伸与锚点 ​