ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Spring AI指标监控实战:从Actuator到Grafana的完整落地指南

Spring AI指标监控实战:从Actuator到Grafana的完整落地指南 Spring AI 2.x 出来之后我身边几乎把所有 AI 能力接进 Java 系统的人都在干同一件事把原来在 Dify、Langflow 这类画布工具里写好的工作流转成代码。转完之后他们才会发现一个尴尬的问题——Dify 自带日志和令牌统计点一下就知道今天花了多少钱换到 Spring AI 之后功能照样跑但没人知道每次对话消耗了多少 token、延迟是多少、哪个模型在烧钱。这就是我今天想聊的 Spring AI 指标监控。这篇文章主要面向两类人。一类是正在用 Spring AI 做生产和准生产系统的开发、运维另一类是从可视化 AI 平台迁到 Java 工程的团队。内容会围绕这套东西展开Spring AI 可观测性的技术选型、Actuator Micrometer Prometheus Grafana 的落地步骤、自定义业务指标成本、延迟、令牌的具体写法以及我实际踩过的坑。不废话下面进入正题。1. Spring AI指标监控到底要管什么从业务视角拆需求1.1 传统Web监控解决不了AI应用的三个问题做后端的老手都知道传统 Web 服务监控起来很简单看 QPS、RT、错误率再盯一下 CPU、内存、磁盘。但 AI 应用是另一套逻辑至少有三个维度传统监控完全覆盖不了。第一token 就是钱。每一次大模型调用都会同时消耗提示词和生成结果的 token。这些数字乘以模型单价就是你的真实成本。如果没有指标监控月底财务问 AI 服务花了多少钱你只能去模型平台控制台扒账单拿到账单也说不清是哪个业务线烧的。第二生成式接口的延迟体验不能只看总耗时。传统接口服务端返回一个完整 JSON总耗时差不多就是用户体验的上限。大模型是流式输出的用户从发出请求到看到第一个字的时间和从开始到全部生成完的时间完全是两个体验级别。这两段延迟都需要分开采集否则你没法回答为什么用户觉得慢。第三AI 服务对外部模型供应商的依赖程度极高。上游稍微限流或超时下游立刻变成页面转圈。这类问题往往不是我们自己的代码逻辑问题而是上游特征。想在监控上区分我的服务慢了和模型供应商慢了就必须在调用链里采集针对每次模型调用的耗时、状态、重试次数。也就是说Spring AI 指标监控不只是给运维看的它首先要解决的是三个业务问题成本控制、体验保障、故障定界。没有这些指标AI 应用跑得再欢你也是个盲人骑瞎马。1.2 从能不能用到值不值成本与质量指标怎么定义很多团队一开始问的是这个 AI 服务能不能用但上线一个月后一定会问值不值。值不值这个问题需要一套明确的指标口径来回答。我自己比较推荐把 Spring AI 的指标体系分成五组你先看这张表指标分组典型指标用途流量类请求总数、并发数、按模型拆分的调用量看业务规模、扩容依据性能类首 token 延迟、总耗时、TP50/TP99用户体感、模型质量资源类prompt token、completion token、上下文长度成本趋势、上下文泄漏排查成本类单次调用估算成本、日/周累计成本、按场景分摊给财务、给老板质量类重试率、超时率、空响应率、内容截断率判别模型服务健康这里有个容易忽略的点前两类指标大部分可以靠 Spring AI 自带的观测能力拿后三类往往需要自己做一层自定义埋点。尤其是成本指标模型单价是业务侧的商业信息框架不可能替你算好。举个例子。一个帮助中心机器人用户问一句我的订单多久能到后端起一个 Agent 流程可能调一次意图识别、一次知识库检索、再调用一次生成模型。这一条链路下来如果只在入口处打个埋点你看到的是这一次请求花了 3 块 2 毛但拆分不到底是意图识别贵还是生成贵。正确的做法是在每次调用 ChatModel 时都打点带上 model、provider、scenario 标签这样才能按场景维度统计成本也才能在模型供应商报价调整时快速算出影响。所以在动手配置之前先别急着装 Grafana。先把指标清单列出来想清楚每个指标给谁看、用来回答什么问题。这个准备过程远比后面的 yaml 配置值钱。2. 技术选型与核心方案基于Micrometer的Spring AI可观测性2.1 Spring AI 2.0对Observability的支持内置了什么没内置什么Spring AI 2.0 并不是要求你从零手写监控。它内部已经集成了基于 Micrometer Observation 的可观测性能力只要你走的是官方封装的 ChatModel、EmbeddingModel、ChatClient 这套接口框架会自动在合适的位置创建观测点。大概会帮你产出的东西包括大模型调用次数、prompt/completion token 数量、调用耗时等指标上通常会带模型名、供应商等基础标签。这些指标在/actuator/prometheus里形如spring_ai_*前缀不同小版本的命名细节有差异但一般都能看到调用量和 token 消耗的轮廓。不过内置能力只能算骨架它默认不会做三件事不会按你的业务场景打标签。比如一个系统里同时跑客服、摘要、翻译三个功能内置指标只会告诉你某个模型被调了一次不会告诉你这是哪个场景调的。不会算成本。框架不感知你从模型平台拿到的价格表。不会自动配置 Prometheus 的拉取端点和抓取任务。这部分要你自己接。这里我建议你先做一个明确判断如果公司里已有 Prometheus 和 Grafana那就直接复用这套链路如果完全没有监控体系也可以顺手搭一套。Spring AI 的官方观测层用的是 Micrometer天然可以对接 Prometheus、InfluxDB、OpenTelemetry 等多种后端以后想迁到其他监控平台也不会被锁死。2.2 为什么选择Actuator Micrometer Prometheus Grafana先聊聊我为什么推荐这套组合而不是另起炉灶。Actuator 是 Spring Boot 自带的能力加入依赖就能暴露端点零成本起步。Micrometer 是 Java 生态里事实标准的指标门面用一套 API 抽象各种监控后端。Prometheus 用 pull 模式周期性拉取指标对 Java 进程来说比 Agent 注入式的方案更轻量也更容易排查——抓不到的时候 curl 一下就知道端点有没有响应。Grafana 负责仪表盘和告警配置方便社区里现成的 Spring Boot 面板模板也不少。当然也有备选。如果团队已经在用 OpenTelemetry 做链路追踪可以把 Spring AI 的指标也接到 OTel Collector 里然后再往外转发到 Prometheus 或 ClickHouse。如果公司有统一 APM 平台比如 SkyWalking也能做但需要你额外写适配磨合成本要高一些。我的经验是对于大多数 Java 团队来说Actuator Micrometer Prometheus Grafana 是最短路径。这套组合有十足的文档积累遇到的坑基本都能搜到而且完全不需要在业务代码里侵入式地加一行行日志。最关键的是它能同时覆盖机器指标和业务指标两种需求不用两套系统并行。3. 端到端落地实操把Spring AI指标接到Prometheus和Grafana3.1 第一步依赖与配置让内置指标先跑起来这部分我给你一套可以直接抄的配置。先假设你有一个已经能正常调用大模型的 Spring Boot 3.x 工程接下来就三步。第一步在pom.xml里加两个依赖dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-actuator/artifactId /dependency dependency groupIdio.micrometer/groupId artifactIdmicrometer-registry-prometheus/artifactId /dependency如果你用的是 Spring AI 的 starter 依赖官方观测支持通常已经通过自动配置带进来了。但为了保险可以再确认一下你是否需要显式引入spring-ai-observability相关模块具体坐标以你当前 Spring AI 版本的官方文档为准。第二步在application.yml里打开 Prometheus 端点spring: application: name: ai-service management: endpoints: web: exposure: include: health,info,prometheus metrics: tags: application: ${spring.application.name} distribution: percentiles-histogram: http.server.requests: true这里的management.metrics.tags.application会自动给每条指标打上服务名标签多服务部署时特别有用。percentiles-histogram相关的配置表示让相关指标生成直方图方便 Grafana 直接算 TP99 之类的分位数。先做最小验证的话也可以先不配最后一段把基础指标跑通再慢慢加。第三步启动应用随便调用一次你的 AI 接口然后看 Prometheus 端点curl http://localhost:8080/actuator/prometheus如果输出里出现了与 AI 相关的指标比如指标名里带spring_ai或ai_的条目说明内置观测已经生效。如果看不到任何东西先别急着加代码去检查是不是依赖没引全或者调用 AI 时没有走 Spring AI 封装的接口。3.2 第二步用自定义指标补齐成本和场景维度内置指标跑起来后你会发现它少了业务维度。这时候就需要自己动手埋点。我的做法是在业务调用的 Service 层里包一层统一通过MeterRegistry记录请求计数、耗时和 token 消耗。下面是一个简化版的示意代码重点看思路API 细节以你用的 Spring AI 版本为准Service public class AiChatService { private final ChatClient chatClient; private final MeterRegistry meterRegistry; public AiChatService(ChatClient.Builder builder, MeterRegistry meterRegistry) { this.chatClient builder.build(); this.meterRegistry meterRegistry; } public String chat(String question, String scenario) { Timer.Sample sample Timer.start(meterRegistry); try { ChatResponse response chatClient.prompt(question).call(); String answer response.getResult().getOutput().getText(); TokenUsage usage response.getMetadata().getUsage(); String model response.getMetadata().getModel(); meterRegistry.counter(ai_token_total, type, prompt, model, model, scenario, scenario) .increment(usage.getPromptTokens()); meterRegistry.counter(ai_token_total, type, completion, model, model, scenario, scenario) .increment(usage.getCompletionTokens()); return answer; } finally { sample.stop(Timer.builder(ai_request_duration) .tag(scenario, scenario) .publishPercentileHistogram() .register(meterRegistry)); } } }这段代码做了三件事记录本次请求耗时、记录 prompt token、记录 completion token。标签里带上scenario和model后面就能在 Grafana 上按场景和模型去切分。成本指标可以类似地累加。比如你配置一张价格表把每百万 token 的单价放进去然后按实际消耗计算成本增量BigDecimal promptCost priceConfig.pricePerMillion(model, prompt) .multiply(BigDecimal.valueOf(usage.getPromptTokens())) .divide(BigDecimal.valueOf(1_000_000)); meterRegistry.counter(ai_cost_estimate_total, model, model, scenario, scenario) .increment(promptCost.doubleValue());这里要注意成本是估算值不建议把这个指标当成精确账本。它更适合做趋势对比和异常告警。真要算钱还是以模型平台控制台的账单为准。3.3 第三步Grafana仪表盘和告警的配置要点指标打出来之后剩下就是展示和告警。Grafana 接 Prometheus 数据源这一步属于常规操作我不展开就说我实际用下来最有价值的几个 Panel。首先是请求量按模型拆分的趋势图。核心查询可以写成sum(rate(ai_request_total[5m])) by (model)如果你没有单独自定义ai_request_total就需要用 Spring AI 内置的指标名找到包含 request 或 call 的计数指标再套同样的语法。记住一个原则指标名会变查询套路不太会变。第二个是延迟分位数。比如看 P99 总耗时histogram_quantile(0.99, sum(rate(ai_request_duration_seconds_bucket[5m])) by (le, model) )这个查询依赖 Timer 生成直方图桶所以前面代码里我加了publishPercentileHistogram()这一步很关键。第三个是 token 消耗速率sum(rate(ai_token_total[5m])) by (type, model)第四个是成本趋势通常直接看累计值变化比如sum(increase(ai_cost_estimate_total[1h])) by (model)告警规则我建议先配三条。错误率达到某个阈值时告警比如/actuator/prometheus里如果有错误计数器超过 5% 持续 5 分钟就触发P99 延迟超过 5 秒持续 5 分钟触发单模型日成本环比前一天上涨超过 50% 触发。成本告警最好做成慢一点的频率比如一小时或一天跑一次避免被打扰。4. 常见问题与排查技巧实录4.1 有指标但数量稀疏为什么Prometheus抓不到数据最常见的情况是/actuator/prometheus能访问但 Prometheus 里查不到任何 AI 相关指标或者查到的指标数量和实际调用次数完全对不上。这里有一个很典型的排查路径。先确认你的调用代码到底走没走 Spring AI 的封装。如果你在某个地方直接用了底层模型 SDK 的RestClient甚至绕过了ChatClient那 Spring AI 的观测是看不到你这笔调用的。解决办法很简单把调用统一收敛到 Spring AI 的ChatClient/ChatModel接口上。再确认 Actuator 暴露的端点在 Prometheus 的抓取配置里地址对不对。很多 Kubernetes 部署场景下Prometheus 抓的是 Pod IP而 Actuator 的端口可能没有暴露到 Pod 的management端口上。建议先在 Prometheus 的 Targets 页面看这个 job 是不是 UP如果不是检查网络策略和注解标注。还有一个我自己踩过的坑改了application.yml后没有重启应用。Actuator 的端点响应是实时的但配置文件的改动必须重启才生效。排查的时候别急着看代码先看服务启动时间。4.2 令牌统计与模型平台控制台对不上口径、重试和缓存很多同事第一次看到自己统计的 token 消耗和模型平台控制台不一致会怀疑是不是算错了。实际上这个误差非常正常原因有三个。第一token 计算口径不同。模型平台的计费系统可能基于特殊的切token方法而 Spring AI 返回的TokenUsage是模型 API 在响应里带回来的数值两者天然存在轻微差异。第二重试导致重复统计。如果你的代码里配了重试机制一次失败重试两次你可能会把三笔 token 都加上但模型平台只在成功的那次扣费或者在失败请求也计费不同的供应商策略还不一样。第三流式场景下TokenUsage可能只包含部分字段。有些模型在流式返回时只在最后一个 chunk 里有完整的 usage 信息如果你提前读取了就会少记。怎么处理我的建议是应用侧统计用于做相对趋势比如今天比昨天涨了多少、哪个场景烧钱这些是可靠的绝对数值和模型平台账单对不上没关系只要误差在合理范围比如 5% 以内就不需要纠结。真要做成本管理定期抽样对账用平台账单当基准校准。4.3 Actuator端点暴露在生产环境的风险控制这个必须单独拎出来说。/actuator/prometheus虽然只是指标端点但在生产环境直接暴露到公网仍然有风险。至少有三个方向的加固建议。第一端口收敛。如果业务端口和管理端口分开就把 Actuator 单独放到 management 端口上不让它在同一个入口被外部访问到。第二网络限制。在云环境里安全组只允许 Prometheus 的机器 IP 访问其他地方一律拒绝。如果用了 Kubernetes尽量不要把它做成公开的 Ingress 路由。第三指标内容脱敏。不要在指标标签里放用户 ID、订单号、Prompt 原文这些敏感信息。指标是给监控系统用的不是给数据仓库用的标签基数爆炸和敏感信息泄漏都是在这里翻车的。5. 从Dify到Spring AI可视化工作流迁移时的监控要点5.1 Dify自带的功能为什么换到Java代码后全没有了用过 Dify 这类平台的朋友应该深有体会拖个节点、连条线工作流自动有运行日志、token 消耗统计、成本估算甚至还有详细的每个节点耗时。这些能力让我们在原型阶段非常舒服。但当你决定把它迁到 Spring AI写 Java 代码自建 Agent 流程时这些开箱即用的功能就全没了。这里要有一个心理预期可视化平台自带的可观测性本质上是平台替你做了一层通用埋点。而代码化之后这层通用能力需要你自己用 Micrometer、Prometheus、Grafana 重新搭起来。有意思的是这一步恰恰是很多团队迁移后最容易忽略的盲区。我自己建议的迁移顺序是先把监控搭好再迁业务逻辑。先在空工程里把spring-ai-observability相关配置跑通验证能出指标了然后再把 Dify 里的工作流一个节点一个节点搬到 Java 代码中。否则你搬完才发现没有日志、没有 token 统计、没有成本报表回头再补监控那就要面对一堆不可比的数据。5.2 对接百炼DashScope等模型平台时的监控细节现在国内团队用 Spring AI 对接百炼已经很常见模型名可能是qwen-max、qwen-plus这一类的通义千问模型。对接方式一般是走 OpenAI 兼容协议把 base-url 指向百炼的兼容地址。这个连接方式本身不复杂但我在做监控时发现几个细节值得注意。第一个细节是模型名的归一化。百炼平台上同一个模型可能在不同区域、不同版本里有不同名字而你在代码里写的是业务名比如qwen-max。为了保证 Grafana 面板上模型维度干净建议在自定义指标时增加一个映射逻辑把供应商返回的模型名映射成业务统称。比如qwen-max-2024统一映射为qwen-max或者直接映射成aliyun-qwen-max。第二个细节是不同供应商的TokenUsage字段未必完整。OpenAI 生态的接口一般都能返回 prompt/completion 的用量但有些兼容接口或自建模型可能在特定参数下不返回。这时候就不能只依赖内置观测要在框架调用层面做兜底用失败不计数的方式避免脏数据污染报表。第三个细节是流式响应的观测。如果你用chatClient.prompt(...).stream()做流式输出内置观测通常也能记录但流式场景下的指标会比同步调用复杂一些。在统计延迟时至少把首 token 延迟和总耗时分开。如果框架没有直接暴露首 token 延迟可以考虑在流式回调里用自己记录时间戳的方式实现。这些细节处理完你再看一个跨多家模型供应商的系统时指标面板才真正有可用性。否则每次出问题都要去翻原始日志等于监控白搭。最后说点个人体会。AI 应用的可观测性和传统业务系统有个很大不同它的不稳定来源多了一层外部模型供应商而且每一点流量都牵扯真实费用。把 Spring AI 的指标监控做起来不只是为了让仪表盘好看更是为了让团队在扩容、压测、降价换模型时有依据。我通常建议团队先做最基础的三件事把内置指标跑通、把请求延迟和令牌做成自定义指标、把成本和错误告警配好。这三个做好了后续再谈更细的链路追踪都不迟。如果你正在做类似的迁移可以对照着排查。遇到指标名对不上的问题最好的办法是直接翻 Spring AI 对应版本的源码看清观察器注册逻辑比在搜索引擎里反复找答案要快得多。
返回列表