AI推理服务对延迟和稳定性极其敏感。一次模型加载异常、一批坏数据、一个下游依赖抖动,都可能让线上接口的P99延迟从200ms冲到5秒,错误率瞬间翻倍。如果没有一套直观的监控大盘,运维同学只能等用户投诉后才开始排查,定位成本极高。Grafana配合Prometheus是目前最主流的可视化监控方案,这篇文章就以一个典型的AI推理服务为例,手把手演示如何绘制Latency、P99、Error Rate三类核心图表,并配置对应的告警规则。

一、监控指标设计与Prometheus数据源对接
画图之前先解决数据从哪来的问题。AI推理服务推荐暴露以下几类指标:HTTP请求的耗时直方图(histogram)、请求总数计数器(counter)、错误请求计数器、GPU利用率和显存占用、以及模型推理阶段的分段耗时。以Python服务为例,用prometheus_client暴露指标非常简单:
from prometheus_client import Histogram, Counter, start_http_server
# 请求耗时直方图,buckets决定了能算出的分位数精度
REQUEST_LATENCY = Histogram(
'ai_request_latency_seconds',
'AI推理请求耗时',
['model', 'endpoint'],
buckets=(0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0)
)
REQUEST_TOTAL = Counter(
'ai_request_total',
'请求总数',
['model', 'endpoint', 'status']
)
@REQUEST_LATENCY.time()
def handle_inference(model, endpoint):
result = run_model(model)
REQUEST_TOTAL.labels(model=model, endpoint=endpoint, status='success').inc()
return result
start_http_server(9091)
这里有一个容易被忽视的细节:histogram的buckets必须覆盖真实的延迟分布。如果AI服务的正常延迟在1到3秒之间,而buckets最大只到1.0,那P99的计算结果会被截断,图上永远是一条平线,完全失去监控意义。建议先观察一段时间真实流量分布,再回过头调整bucket边界。
服务暴露指标后,在Prometheus的prometheus.yml中配置抓取任务,然后在Grafana的Connections菜单里添加Prometheus数据源,填入Prometheus地址保存即可。测试连接通过后,就可以开始建面板了。
二、Latency趋势图与P99分位数面板的绘制
Latency面板建议用Time series类型。平均延迟能反映整体趋势,但它会掩盖长尾问题,所以均值和P99一定要放在同一张图里对比。对应的核心查询语句如下:
# 平均延迟,按模型分组 rate(ai_request_latency_seconds_sum[5m]) / rate(ai_request_latency_seconds_count[5m]) # P99延迟 histogram_quantile(0.99, sum(rate(ai_request_latency_seconds_bucket[5m])) by (le, model) )
面板调优方面有几个实用技巧。第一,Legend字段写成{{model}}可以按标签自动生成图例,多模型场景下非常清晰。第二,把平均值和P99分别用不同的Unit(seconds)配置,并开启Graph styles里的Fill opacity为10左右,均值填充淡色、P99只画线,视觉上立刻能区分。第三,如果多个模型延迟量级差异大(比如embedding模型几十毫秒、大模型几秒),建议用Overrides给不同序列单独设置Y轴,否则小量级的曲线会被压成一条贴地的线。
P99面板还可以加一条SLO阈值线做参考。在Panel options的Thresholds里设置目标值,比如1.5,超过阈值的区域会自动标红。这样值班同学看一眼颜色就知道服务是否健康,不用逐个数值去比对。除了P99,建议再加一个P50和P95面板,P50反映典型用户体验,P95用来观察长尾恶化的早期信号,三者结合才能完整刻画延迟分布。
另一个值得推荐的做法是把Latency按推理阶段拆分。在业务代码里用label区分preprocess、inference、postprocess三个阶段,Grafana里用sum by (le, stage)分别出曲线,一旦延迟上升就能立刻判断是预处理排队还是GPU推理本身变慢,排查范围直接缩小三分之二。
三、Error Rate图表绘制与状态码下钻分析
错误率面板的查询语句核心是错误请求数除以总请求数。假设失败请求的status标签值为error:
# 错误率百分比
100 * sum(rate(ai_request_total{status="error"}[5m])) by (model)
/
sum(rate(ai_request_total[5m])) by (model)
面板类型推荐Time series,Unit选Percent,上限设为0-100。Max data points不用设太大,默认750已经足够。这个面板建议同时叠加一个Stat面板放在大盘顶部,用大号数字显示最近5分钟的整体错误率,配合Thresholds配置绿色小于0.1、黄色小于1、红色大于1,作为大盘的"一眼健康度"指标。
光有总错误率还不够,出问题时需要知道错误的具体构成。可以做一个状态码分布表格面板,查询sum(increase(ai_request_total[15m])) by (status, model),用Table类型展示,按数值降序排列。这样能看到错误是超时、模型加载失败还是下游依赖异常,避免拿到告警后还要登录机器翻日志。对于AI服务,还可以额外统计GPU OOM、队列积压深度等指标,和错误率放在同一行,方便关联分析。
时窗选择也有讲究。错误率用5分钟窗口对突发抖动敏感,适合告警;但看周报或趋势时建议切到1小时窗口,曲线平滑后才容易发现缓慢劣化的问题。Grafana支持在查询里写两个不同窗口的表达式画在同一面板,比如同时展示5m和1h错误率,短期波动和长期趋势一目了然。
四、Grafana Alerting告警规则配置
图表只是被动展示,告警才是主动防御。进入Alerting菜单创建告警规则,以P99延迟告警为例,查询语句复用面板里的P99表达式,条件设置为IS ABOVE 2,持续时长(For)填5m,也就是P99连续5分钟超过2秒才触发,避免一次抖动就发告警造成疲劳。
# P99延迟告警查询
histogram_quantile(0.99,
sum(rate(ai_request_latency_seconds_bucket[5m])) by (le, model)
) > 2
# 错误率告警查询:5分钟窗口错误率超过1%
(
100 * sum(rate(ai_request_total{status="error"}[5m])) by (model)
/
sum(rate(ai_request_total[5m])) by (model)
) > 1
告警分级建议至少分两层。Warning级别用于P99超过SLO的80%、错误率超过0.5%这类预警信号,发给值班群即可;Critical级别用于服务不可用、错误率超过5%、P99超过5秒这类严重故障,配置电话或短信通知。Grafana的contact points支持钉钉、企业微信、Slack、邮件等多种渠道,国内团队用钉钉webhook最常见,配置时注意把消息模板里的告警标签和值都带上,否则收到通知还要去开大盘查原因。
还有两个实战经验值得分享。第一,AI服务常有批处理任务导致的规律性延迟尖峰,可以在告警规则里加unless子句排除特定label的流量,或者使用静默时段功能,否则每天定时任务一跑告警就刷屏,很快大家就会把通知免打扰。第二,一定要配置No Data告警:如果Prometheus抓不到指标,所有图表会变空白,但普通阈值告警不会触发。单独加一条规则监控absent(ai_request_latency_seconds_count),数据断流时立即通知,这种"监控的监控"往往比业务告警更关键。
最后,大盘布局建议遵循从上到下的漏斗结构:顶部放错误率、请求QPS、P99三个大号Stat指标,中部放Latency和P99趋势图,底部放GPU资源和阶段耗时明细。这样无论是日常巡检还是故障应急,视线动线都符合排查逻辑。搭好之后记得用Grafana的导出JSON功能把大盘备份到代码仓库,团队成员共享一份基线配置,后续迭代也方便做版本管理。