OpenClaw 巡检从入门到生产:三个踩坑经验,让你的 AI 巡检真正能用
我上个月在 300+ 服务的生产集群上把 OpenClaw 巡检跑通了,从”能用”到”好用”,中间踩了三个大坑。
今天把这三个坑和你讲清楚。不讲概念,只讲我在生产环境上真刀真枪干出来的东西。
坑一:没接 OTel,你的巡检就是空中楼阁
先说结论:OpenClaw 巡检想要做好,企业必须接入 OpenTelemetry。没有例外。
我见过太多团队上来就在 OpenClaw 里写 Spec、配 Cron,搞了一周发现巡检结果跟垃圾没区别。不是 OpenClaw 不行,是你喂给它的数据就是垃圾。
巡检的本质是什么?是让 AI Agent 帮你回答一个核心问题:”我的服务现在健不健康?”
那 Agent 怎么判断健不健康?它得看到三样东西:
-
指标(Metrics):CPU、内存、QPS、错误率、P99 延迟 -
日志(Logs):ERROR/WARN 级别的结构化日志 -
链路(Traces):完整的请求调用链
这三样东西散落在三个系统里——Prometheus 里有指标,Elasticsearch 里有日志,SkyWalking 里有链路。三个系统各说各话,服务名不统一,trace ID 关联不上。你让 Agent 拿着一堆互相矛盾的数据做判断,它不是在分析,是在猜。
OTel 解决的就是这个问题——用一套 SDK、一套 Collector、一套协议,把三种信号统一起来,通过 trace_id 串在一起。
接入 OTel 之后,Agent 拿到的数据长这样:
一条指标异常(order-service 错误率飙升到 15%)
→ 通过 trace_id 跳到具体链路(第 4 跳 redis.get 命令耗时异常)
→ 通过 trace_id 查到对应日志("connection pool exhausted")
→ 通过指标佐证(redis_pool_active_connections 达到上限)
三秒钟,证据链完整了。没接 OTel 的时候,这种分析人工要 8 分钟。
具体怎么接
K8s 环境下最省事的方式是用 OTel Operator 自动注入。Java、Python、Node.js、.NET 的服务加一行 Pod 注解就行,业务代码零改动:
metadata:
annotations:
instrumentation.opentelemetry.io/inject-java:"true"
Go 服务只能手动接 SDK,这个没捷径,但工作量可控——做一个内部模板,业务 copy 就行。
关键的一步:部署 OTel Collector,作为所有遥测数据的统一采集枢纽。一份基础配置:
receivers:
otlp:
protocols:
grpc:
endpoint:0.0.0.0:4317
http:
endpoint:0.0.0.0:4318
processors:
batch:
timeout:5s
send_batch_size:1024
resource:
attributes:
-key:deployment.environment
value:"prod"
action:upsert
exporters:
otlp_grpc:
endpoint:tempo:4317
prometheusremotewrite:
endpoint:prometheus:9090
elasticsearch:
endpoint:es:9200
service:
pipelines:
traces:
receivers:[otlp]
processors:[batch,resource]
exporters:[otlp_grpc]
metrics:
receivers:[otlp]
processors:[batch,resource]
exporters:[prometheusremotewrite]
logs:
receivers:[otlp]
processors:[batch,resource]
exporters:[elasticsearch]
不要让业务服务直连后端。Collector 是你的数据治理层,所有字段清洗、采样、脱敏都在这一层做。
坑二:OpenClaw 怎么知道该巡检哪些服务?service.project 这个字段救了我的命
OTel 接好了,数据流进来了,下一个问题来了:OpenClaw 怎么知道该巡检哪些服务?
一个 300+ 服务的集群,不可能每次全量巡检。有些服务属于交易链路,有些属于用户中心,有些属于内部工具。你需要按”项目”维度把服务分组,OpenClaw 按项目做巡检。
这就是 OTel Resource Attributes 里 service.project 这个字段的作用。
什么是 Resource Attributes
OTel 里每条遥测数据都有一组 Resource Attributes,用来标识”这条数据是从哪来的”。标准字段包括 service.name、service.version、deployment.environment 等。但 OTel 允许你加自定义字段。
我在 Collector 的 resource processor 里加了一个关键配置:
processors:
resource:
attributes:
-key:service.project
value:"trade-platform"
action:upsert
这样一来,所有流过这个 Collector 的数据都带上了 service.project=trade-platform 这个标签。Prometheus 里的指标、Tempo 里的链路、ES 里的日志,全都有了项目归属。
实际上怎么做分组
更合理的做法是按 namespace 或服务名前缀做映射,而不是所有服务硬编码一个值。用 OTel Collector 的 transform processor:
processors:
transform:
error_mode:ignore
metric_statements:
-context:resource
statements:
# 按 namespace 映射到不同的 project
-set(attributes["service.project"],"trade-platform")whereattributes["k8s.namespace.name"]=="trade"
-set(attributes["service.project"],"user-center")whereattributes["k8s.namespace.name"]=="user"
-set(attributes["service.project"],"payment")whereattributes["k8s.namespace.name"]=="payment"
-set(attributes["service.project"],"infra")whereattributes["k8s.namespace.name"]=="monitoring"orattributes["k8s.namespace.name"]=="logging"
然后在 OpenClaw 的 Spec 文件里,按 service.project 定义巡检范围:
## 巡检范围
按项目分组:
- trade-platform: order-service, cart-service, inventory-service
- payment: payment-service, refund-service, settlement-service
- user-center: user-service, auth-service, profile-service
## 执行策略
- trade-platform: 每小时巡检一次(P0 业务)
- payment: 每 30 分钟巡检一次(P0 业务)
- user-center: 每 2 小时巡检一次
- infra: 每天巡检一次
OpenClaw 查询 Prometheus 的时候,用 service.project="trade-platform" 做 label selector,只拉属于这个项目的服务指标。不是全量扫描,是精准巡检。
这个设计解决了我一个很痛的问题:以前每次新增服务都要手动更新巡检列表,漏了就巡检不到。现在只要服务接了 OTel 并且配了 service.project,自动就会被纳入对应的巡检范围。新增服务不再需要人工登记。
坑三:巡检报告一定要变成图片,没人愿意看一坨文字
这一坑,是我自己犯的蠢,说出来你别笑。
我第一版巡检报告是这样的——OpenClaw 跑完 Spec,直接把 Markdown 文本甩到企业微信群。一段密密麻麻的文字,带几个表格,没人看。运维同学的原话是:”你这比我直接看 Grafana 还费劲。”
后来我想明白了一件事:巡检报告的受众不是机器,是人。人更容易接受图片。
一张排版精良的巡检报告图片,比一屏文字的信息密度高 10 倍。你扫一眼就知道哪些服务有问题,不用去表格里找数字。
具体怎么做:Markdown → HTML → PNG
整个 pipeline 分三步:
第一步:用 Template 控制输出结构。
在 OpenClaw 的 Spec 里引用一个 Template 文件,确保每次巡检报告的结构一致:
## 巡检报告模板
整体健康度: {{绿色 / 黄色 / 红色}}
### 指标概览
| 服务 | CPU | 内存 | QPS | 错误率 | P99延迟 | 状态 |
|------|-----|------|-----|--------|---------|------|
| {{service}} | {{cpu}}% | {{mem}}% | {{qps}} | {{err_rate}}% | {{p99}}ms | {{status}} |
### K8s 状态
| 命名空间 | Pod 总数 | 正常 | 异常 | 异常详情 |
|----------|---------|------|------|---------|
| {{ns}} | {{total}} | {{healthy}} | {{unhealthy}} | {{detail}} |
### 行动建议
| 优先级 | 问题 | 建议操作 |
|--------|------|---------|
| P0 | {{issue}} | {{action}} |
第二步:写一个 Skill 把结构化数据渲染成 HTML。
这一步用代码做,不要让 LLM 生成 HTML。大模型在确定性渲染上永远不如代码。做一个 report-renderer Skill,里面放一个 Python 脚本,读入巡检 JSON 数据 + HTML 模板 + CSS 样式,输出一份完整的 HTML 文件。
HTML 模板的设计要点:
-
宽度定 440px,适配手机屏幕 -
用 CSS Grid 做卡片布局 -
健康度用颜色区分(绿/黄/红) -
指标异常的行加背景高亮 -
字体用系统字体,不依赖外部加载
第三步:HTML 转 PNG。
用 Playwright 做无头截图:
from playwright.sync_api import sync_playwright
defhtml_to_png(html_path, png_path):
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page(
viewport={'width': 440, 'height': 800},
device_scale_factor=2# 二倍图,微信里放大不糊
)
page.goto(f'file://{html_path}')
page.wait_for_load_state('networkidle')
page.screenshot(path=png_path, full_page=True)
browser.close()
三个关键参数:viewport 宽度 440 对应移动端、device_scale_factor=2 保证清晰度、full_page=True 做长截图。
如果环境没装 Playwright,做三级降级——Playwright → Selenium → wkhtmltoimage,哪个能用就用哪个。
最后把 PNG 图片推送到飞书或企微群。图片比文字的阅读完成率高太多,我们上线图片报告之后,运维团队对巡检结果的关注度从”偶尔扫一眼”变成了”每天主动看”。
一个关键补充:基础指标缺失的时候,必须明确告诉用户
我在跑巡检的过程中还碰到过一种情况:OpenClaw 开始巡检了,查 Prometheus 的时候发现某些服务的基础指标根本没上报。CPU、内存、K8s Pod 状态全是空的。
这个时候 OpenClaw 不能假装没看到。我在 Spec 里加了一条硬性规则:
## 前置检查(必须第一个执行)
在执行任何巡检之前,先验证基础指标是否完整。对每个服务检查以下指标是否存在:
1. CPU 使用率:container_cpu_usage_seconds_total
2. 内存使用率:container_memory_working_set_bytes
3. K8s Pod 状态:kube_pod_status_phase
4. Pod 重启次数:kube_pod_container_status_restarts_total
如果任何一个服务的上述指标缺失,在报告顶部用醒目样式标注:
"警告:以下服务的基础 OTel 上报数据缺失,巡检结果可能不完整:
- xxx-service:缺失 CPU、内存指标(疑似未接入 kubelet cAdvisor 或 OTel Host Metrics Receiver)
- yyy-service:缺失 Pod 状态指标(疑似未部署 kube-state-metrics)"
缺失基础指标的服务,后续巡检步骤自动跳过,避免用不完整的数据得出错误结论。
这不是一个可选的功能,是必须做的。基础指标缺失意味着你的观测面有盲区,Agent 在盲区里做推理,得出的结论不可信。宁可明确告诉用户”这些服务我看不到”,也不要用不完整的数据编一个看起来合理的结论。
这两种做法的区别,就是”专业”和”业余”的区别。
整体架构长这样
把上面三件事拼在一起,完整的巡检架构:
业务服务(300+)
│ OTel SDK / Operator 自动注入
│ 携带 resource attributes: service.name, service.project, deployment.environment
▼
OTel Collector
│ transform processor: 按 namespace 映射 service.project
│ resource processor: 补齐环境信息
│ batch processor: 批量发送
▼
┌──────────┬──────────┬──────────┐
│ Tempo │Prometheus│ ES │
│ Traces │ Metrics │ Logs │
└────┬─────┴────┬─────┴────┬────┘
│ │ │
└──────────┴──────────┘
│
▼
OpenClaw Agent Runtime
┌─────────────────────────────┐
│ Spec: 定义巡检任务流 │
│ Template: 控制报告输出格式 │
│ Skill: 封装数据查询能力 │
│ Cron: 定时触发巡检 │
└──────────┬──────────────────┘
│
▼
巡检 JSON → HTML 渲染 → PNG 截图
│
▼
推送到飞书 / 企微 / 钉钉
写在最后
OpenClaw 巡检想要跑好,核心就三件事:
-
接 OTel。数据质量决定了巡检准确率的上限。没接 OTel 的巡检,等于让一个盲人给你做体检。 -
用 service.project 分组。让 Agent 知道哪些服务该一起巡检,新增服务自动纳入,不用手动维护列表。 -
报告变图片。人更容易接受图片。一张排版好的巡检 PNG,比一屏 Markdown 文字的阅读完成率高 10 倍。
这三件事我都踩过坑,都是在生产环境上跑出来的经验。巡检不是一个工具能解决的事,是数据层、编排层、呈现层三件事拼在一起才能做好。
如果你对 AI Agent 在运维场景的落地感兴趣——不只是巡检,还包括根因分析、自动修复、多 Agent 编排——我正在做一个「Agent 架构师训练营」,手把手带你从 0 搭建一套生产级的 AI Agent 运维系统。从 OTel 数据层到 Agent 编排到报告生成,全链路实战。
训练营第二期已经在筹备中了,感兴趣的同学可以关注后续动态。
夜雨聆风