
文章摘要Spring AI 2.0已经为ChatClient、Advisor、ChatModel、Tool Calling、EmbeddingModel和VectorStore提供Micrometer观测能力但很多项目接入Actuator和Prometheus后只能看到JVM指标看不到gen_ai_client_token_usage_total、gen_ai_chat_client_operation_seconds或Trace。常见原因包括依赖不完整、自建ChatClient绕过自动配置、调用只返回字符串、指标尚未完成、Prometheus名称转换、流式调用上下文断裂以及Provider不返回Usage。本文给出从依赖、配置、Bean、接口、端点到PromQL的完整排查链路。一、先确认你要找的是哪一层指标Spring AI 2.0至少有两层调用观测。ChatClient层反映整个应用调用链Prompt模板 → Advisor → Memory → RAG → Tool Calling → ChatModel常见Prometheus指标gen_ai_chat_client_operation_seconds_count gen_ai_chat_client_operation_seconds_sum gen_ai_chat_client_operation_seconds_max gen_ai_chat_client_operation_active_countChatModel层反映实际模型Provider调用gen_ai_client_operation_seconds_count gen_ai_client_operation_seconds_sum gen_ai_client_operation_seconds_max gen_ai_client_operation_active_count gen_ai_client_token_usage_total如果只看spring_ai_chat_client可能永远找不到因为Prometheus命名会把点号转换为下划线并附加单位或统计后缀。二、最小依赖是否完整至少需要dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-actuator/artifactId/dependencydependencygroupIdio.micrometer/groupIdartifactIdmicrometer-registry-prometheus/artifactId/dependency如果要导出分布式Trace还需要对应Tracing Bridge和Exporter例如OpenTelemetry或Brave方案。不要只引入micrometer-core却没有Registry。Micrometer可以在内存中记录但Prometheus端点不会自动出现。三、Actuator端点是否开放配置management:endpoints:web:exposure:include:health,info,metrics,prometheusendpoint:health:show-details:when_authorized检查curlhttp://localhost:8080/actuatorcurlhttp://localhost:8080/actuator/metricscurlhttp://localhost:8080/actuator/prometheus如果/actuator/prometheus返回404先不要排查Spring AI。需要检查Prometheus Registry是否在ClassPathActuator端点是否暴露安全配置是否拦截应用是否使用不同管理端口Context Path是否变化。四、最常见问题手工创建ChatClient丢失ObservationRegistry错误做法BeanChatClientcustomChatClient(ChatModelchatModel){returnChatClient.create(chatModel);}在复杂多模型配置中手工创建客户端可能绕过自动配置的Customizer和Observability。官方建议在需要自定义Builder时注入ChatClientBuilderConfigurer示意BeanChatClientcustomChatClient(ChatModelchatModel,ChatClientBuilderConfigurerconfigurer){ChatClient.BuilderbuilderChatClient.builder(chatModel);configurer.configure(builder);returnbuilder.defaultSystem(你是企业AI助手).build();}这样可以保留ObservationRegistry已注册Customizer框架自动配置能力。如果你直接new一个ChatModel也要检查它是否使用了正确的ObservationRegistry。五、为什么调用成功却没有Token指标Token指标依赖Provider返回Usage数据。模型响应必须包含类似input_tokens output_tokens total_tokens如果使用OpenAI兼容接口但服务端没有返回UsageSpring AI无法凭空知道真实Token数。常见场景自建OpenAI兼容网关忽略usage流式接口没有在最终事件返回usage第三方Provider字段格式不同代理层删除响应字段模型SDK未实现Usage映射。先通过完整ChatResponse检查ChatResponseresponsechatClient.prompt().user(解释RAG).call().chatResponse();Usageusageresponse.getMetadata().getUsage();System.out.println(usage.getPromptTokens());System.out.println(usage.getCompletionTokens());System.out.println(usage.getTotalTokens());如果这里就是0或nullPrometheus没有Token指标是结果不是原因。六、为什么.content()不方便调试UsageStringanswerchatClient.prompt().user(message).call().content();这种写法只返回内容。排查期间改为ChatResponseresponsechatClient.prompt().user(message).call().chatResponse();然后检查Response MetadataUsageFinish ReasonModelNative Usage。Spring AI 2.0的Usage接口还提供getNativeUsage()用于访问Provider原始用量对象。七、Prometheus名称为什么和文档不一样Micrometer内部Meter名称可能是gen_ai.client.token.usagePrometheus导出后可能显示gen_ai_client_token_usage_total并带标签gen_ai_token_typeinput gen_ai_token_typeoutput gen_ai_token_typetotal查询sum by (gen_ai_token_type) ( rate(gen_ai_client_token_usage_total[5m]) )平均模型调用耗时sum(rate(gen_ai_client_operation_seconds_sum[5m])) / sum(rate(gen_ai_client_operation_seconds_count[5m]))ChatClient平均端到端耗时sum(rate(gen_ai_chat_client_operation_seconds_sum[5m])) / sum(rate(gen_ai_chat_client_operation_seconds_count[5m]))两个耗时不同是正常的。ChatClient还包含Advisor、Memory、RAG和工具链开销。八、为什么只有active_count没有completed指标active_count表示当前正在进行的调用。完成类指标只有在请求结束后才会更新_seconds_count _seconds_sum _seconds_max流式连接长期不结束时你可能看到active_count 1 completed count未增加这不是指标丢失而是调用还未完成。检查前端是否一直保持连接Flux是否收到完成信号是否因异常没有正确终止Nginx是否中断但上游仍运行客户端取消是否传播到Provider。九、流式调用的Trace为什么断开Spring AI文档特别说明OpenAI与Anthropic的流式HTTP调用可能在线程切换后丢失父Observation上下文导致HTTP Span没有正确挂到ChatModel Span下面。表现ChatClient Trace存在 ChatModel Trace存在 HTTP请求Span存在 但三者不是父子链这不一定表示调用没有被观测而是Trace树不完整。处理思路以gen_ai.client.operation为模型层主Span使用业务requestId和traceId辅助关联不要只依赖HTTP Span树判断模型调用是否存在关注当前Spring AI补丁版本的修复情况避免在自定义异步线程中继续丢失上下文。十、日志内容为什么默认看不到PromptSpring AI默认不会导出Prompt和Completion内容因为其中可能包含用户隐私API密钥商业数据RAG证据工具参数内部System Prompt。调试时可以临时配置spring:ai:chat:observations:log-prompt:truelog-completion:trueinclude-error-logging:trueChatClient层还有独立配置spring:ai:chat:client:observations:log-prompt:truelog-completion:true生产环境不建议直接开启全文日志。更安全的记录方式prompt_hash prompt_length template_id template_version input_token output_token十一、Tool Calling为什么Token比预期高一次用户请求触发工具调用时可能执行多次模型调用第一次模型调用 → 选择工具 → 执行工具 → 第二次模型调用 → 生成最终回答如果继续调用第二个工具模型调用次数更多。最终ChatResponse中的Usage可能是整个工具循环的累计值。所以1个HTTP请求 ≠ 1次模型请求建议同时监控业务请求数 ChatClient调用数 ChatModel调用数 Tool调用数 Token数十二、多模型项目标签是否爆炸低基数标签可以放入MeterProvider模型层级业务场景成功或失败流式与否。高基数信息不要放Meter标签userIdconversationIdrequestIdPrompt全文文档IDTool参数。否则Prometheus时间序列数量会迅速膨胀。高基数数据应放Trace 日志 审计表十三、建议的Dashboard指标流量ChatClient QPS ChatModel QPS 当前并发 流式连接数延迟ChatClient P50/P95/P99 ChatModel P50/P95/P99 VectorStore查询耗时 Tool耗时成本输入Token 输出Token 缓存写入Token 缓存读取Token 按模型估算费用稳定性429 超时 5xx 解析失败 工具失败 熔断次数 降级次数十四、完整排查清单□ 已引入spring-boot-starter-actuator □ 已引入Prometheus Registry □ prometheus端点已暴露 □ 使用正确管理端口和Context Path □ ChatClient没有绕过自动配置 □ 自定义Builder保留ObservationRegistry □ Provider响应包含Usage □ 通过ChatResponse验证Usage □ 使用Prometheus转换后的指标名 □ 流式调用已经结束 □ 没把Trace断链误判为无观测 □ 没把高基数数据放Meter标签 □ Tool Calling多次模型调用已纳入成本总结Spring AI看不到Token和耗时指标通常集中在四类原因Actuator与Registry未接通 自建客户端绕过自动配置 Provider没有返回Usage 查询了错误的Prometheus指标名从端点、Bean、完整响应、Meter名称和流式生命周期逐层检查通常可以快速定位。