文章目录1. 项目概述2. 架构原理2.1 观测数据流2.2 三个观测层级3. 环境准备3.1 前置条件3.2 依赖说明4. 自动配置4.1 自动配置类4.2 自动配置源码逻辑4.3 如何使用自动配置的 Bean4.4 配置属性5. 应用配置5.1 application.yml 关键配置5.2 logback-spring.xml6. 核心代码实现6.1 启动类6.2 StateGraph 观测6.3 ReactAgent 观测6.4 OtlpLoggingConfig6.5 ObservationFilterConfig7. 观测指标Metrics7.1 自动采集的指标7.2 查看指标8. 观测拦截器示例8.1 Bean 注册 Hook8.2 树型 Span 结构9. API 端点1. 项目概述本案例演示如何为Spring AI Alibaba的ReactAgent和StateGraph接入完整的可观测性方案覆盖图执行观测Graph/Node/Edge三级生命周期的Trace和Metrics模型调用观测ChatClient/ChatModel的调用耗时、Token用量、Prompt/Response日志OTLP 导出TraceMetricsLogs通过OTLP/gRPC统一导出到SkyWalking OAPPrometheus GrafanaMetrics通过/actuator/prometheus暴露2. 架构原理2.1 观测数据流┌──────────────────────────────────────────────────────────────┐ │ 应用层 │ │ ReactAgent / StateGraph ↔ ChatClient ↔ ChatModel │ │ │ │ │ │ │ ▼ ▼ ▼ │ │ GraphObservation ChatClient ChatModel │ │ LifecycleListener Observation Observation │ │ │ │ │ │ │ └──────────────────────┼───────────────┘ │ │ ▼ │ │ Micrometer Observation API │ │ (ObservationRegistry) │ │ │ │ │ │ │ ▼ ▼ ▼ │ │ Metrics Tracing Logging │ │ │ │ │ │ │ ▼ ▼ ▼ │ │ OTLP/gRPC OTLP/gRPC OTLP/gRPC │ └────────────────────┬─────────┬─────────┬────────────────────┘ │ │ │ ▼ ▼ ▼ ┌──────────────────────────────────┐ │ SkyWalking OAP │ │ (192.168.1.111:4319 / 12800) │ └──────────────┬───────────────────┘ │ ┌──────────────┴───────────────────┐ │ Prometheus Grafana │ └──────────────────────────────────┘2.2 三个观测层级层级范围数据来源Graph 级StateGraph 整体执行执行次数、耗时、成功率、每个节点生命周期GraphObservationLifecycleListenerChat 级每次 LLM 调用调用耗时、Token 用量input/output/totalSpring AIChatModelObservationHTTP 级REST API 请求请求量、延迟、错误率Spring Boot Actuator3. 环境准备3.1 前置条件JDK 17Maven 3.6阿里云DashScope API KeySkyWalking OAP已部署在192.168.1.111:43193.2 依赖说明!-- 核心Agent Framework --dependencygroupIdcom.alibaba.cloud.ai/groupIdartifactIdspring-ai-alibaba-agent-framework/artifactIdversion1.1.2.2/version/dependency!-- 自动配置Graph Observation一键启用图执行观测 --dependencygroupIdcom.alibaba.cloud.ai/groupIdartifactIdspring-ai-alibaba-starter-graph-observation/artifactIdversion1.1.2.2/version/dependency!-- 观测基础设施 --dependencygroupIdio.micrometer/groupIdartifactIdmicrometer-tracing/artifactId!-- Trace 抽象 --/dependencydependencygroupIdio.micrometer/groupIdartifactIdmicrometer-tracing-bridge-otel/artifactId!-- Micrometer → OTel 桥接 --/dependencydependencygroupIdio.micrometer/groupIdartifactIdmicrometer-registry-otlp/artifactId!-- Metrics OTLP 导出 --/dependencydependencygroupIdio.opentelemetry/groupIdartifactIdopentelemetry-exporter-otlp/artifactId!-- Trace OTLP 导出 --/dependencydependencygroupIdio.opentelemetry.instrumentation/groupIdartifactIdopentelemetry-logback-appender-1.0/artifactId!-- Logs OTLP 导出 --version2.14.0-alpha/version/dependency4. 自动配置spring-ai-alibaba-starter-graph-observation通过GraphObservationAutoConfiguration提供一键自动装配。4.1 自动配置类类名com.alibaba.cloud.ai.autoconfigure.graph.GraphObservationAutoConfiguration触发条件ConditionalOnClass检测到ObservationRegistry和GraphObservationLifecycleListenerspring.ai.alibaba.graph.observation.enabledtrue默认就是true自动注册的 BeanBean 名称类型作用observationGraphCompileConfigCompileConfig预配置了ObservationRegistryGraphObservationLifecycleListenerGraph 编译时直接传入graphObservationLifecycleListenerGraphObservationLifecycleListener监听 Graph 执行全生命周期在 Node/Edge 级别创建 SpangraphObservationHandlerGraphObservationHandlerGraph 级别的 Span 创建和属性填充graphNodeObservationHandlerGraphNodeObservationHandlerNode 级别的 Span 创建graphEdgeObservationHandlerGraphEdgeObservationHandlerEdge 路由级别的 Span 创建4.2 自动配置源码逻辑GraphObservationAutoConfiguration的核心装配逻辑等价于ConfigurationConditionalOnClass({ObservationRegistry.class,GraphObservationLifecycleListener.class})EnableConfigurationProperties(GraphObservationProperties.class)publicclassGraphObservationAutoConfiguration{BeanpublicCompileConfigobservationGraphCompileConfig(ObjectProviderObservationRegistryobservationRegistry,ObjectProviderGraphObservationLifecycleListenerlisteners){CompileConfig.BuilderbuilderCompileConfig.builder();observationRegistry.ifUnique(builder::observationRegistry);listeners.ifUnique(builder::withLifecycleListener);returnbuilder.build();}BeanpublicGraphObservationLifecycleListenergraphObservationLifecycleListener(ObservationRegistryobservationRegistry,ObjectProviderGraphObservationConventionconvention,ObjectProviderGraphNodeObservationConventionnodeConvention,ObjectProviderGraphEdgeObservationConventionedgeConvention){returnnewGraphObservationLifecycleListener(observationRegistry,convention.getIfUnique(),nodeConvention.getIfUnique(),edgeConvention.getIfUnique());}// GraphObservationHandler, GraphNodeObservationHandler, GraphEdgeObservationHandler ...}4.3 如何使用自动配置的 Bean在自己的Config中直接注入observationGraphCompileConfigBeanpublicCompiledGraphmyGraph(Qualifier(observationGraphCompileConfig)CompileConfigobservationConfig){StateGraphgraphnewStateGraph();// ... 添加节点和边returngraph.compile(observationConfig);// ← 传入即可启用观测}BeanpublicReactAgentmyAgent(ObservationRegistryobservationRegistry,Qualifier(observationGraphCompileConfig)CompileConfigobservationConfig){returnReactAgent.builder().model(chatModel).observationRegistry(observationRegistry)// ← ChatModel 层观测.compileConfig(observationConfig)// ← Graph 层观测.build();}4.4 配置属性spring-ai-alibaba-starter-graph-observation提供的GraphObservationPropertiesspring.ai.alibaba.graph.observation:enabled:true# 是否启用 Graph 观测默认 trueSpring AI自带的ChatClient/ChatModel观测配置spring.ai.chat.client.observations:log-prompt:true# 日志中记录 Promptlog-completion:true# 日志中记录 Responsespring.ai.chat.observations:log-prompt:truelog-completion:trueinclude-error-logging:true# 记录异常日志spring.ai.tools.observations:include-content:true# Span 中包含工具调用入参和返回值5. 应用配置5.1 application.yml 关键配置server.port:8080spring.application.name:spring-ai-alibaba-observation# DashScope 模型spring.ai.dashscope:api-key:${DASHSCOPE_API_KEY}chat.options:model:qwen-plus# Graph 观测开关spring.ai.alibaba.graph.observation.enabled:true# Chat 观测配置spring.ai:tools.observations.include-content:truechat.client.observations:log-prompt:truelog-completion:truechat.observations:log-prompt:truelog-completion:trueinclude-error-logging:true# OTLP 导出到 SkyWalkingmanagement:tracing:enabled:truesampling.probability:1.0otlp:tracing:endpoint:http://192.168.1.111:4319transport:grpcexport.enabled:truelogging:endpoint:http://192.168.1.111:4319transport:grpcexport.enabled:trueendpoints.web.exposure.include:health,metrics,info# 日志格式带上 traceId / spanIdlogging:pattern:level:%5p [${spring.application.name:},%X{traceId:-},%X{spanId:-}]5.2 logback-spring.xmlconfigurationpropertynameCONSOLE_LOG_PATTERNvalue%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level [%mdc{traceId:-N/A}] [%mdc{spanId:-N/A}] %logger{36} - %msg%n/includeresourceorg/springframework/boot/logging/logback/defaults.xml/includeresourceorg/springframework/boot/logging/logback/console-appender.xml/!-- OTLP 日志 Appender日志也通过 OTLP 上报到 SkyWalking --appendernameOTLPclassio.opentelemetry.instrumentation.logback.appender.v1_0.OpenTelemetryAppendercaptureExperimentalAttributestrue/captureExperimentalAttributescaptureCodeAttributestrue/captureCodeAttributescaptureMdcAttributestraceId,spanId/captureMdcAttributes/appenderrootlevelINFOappender-refrefCONSOLE/appender-refrefOTLP//root/configuration6. 核心代码实现6.1 启动类SpringBootApplicationpublicclassObservationDemoApplication{publicstaticvoidmain(String[]args){SpringApplication.run(ObservationDemoApplication.class,args);}}只需SpringBootApplication——starter-graph-observation的自动配置会自动生效。6.2 StateGraph 观测通过注入自动配置的observationGraphCompileConfig一行代码启用Bean(observedTextProcessGraph)publicCompiledGraphobservedTextProcessGraph(ChatModelchatModel,Qualifier(observationGraphCompileConfig)CompileConfigobservationConfig){StateGraphgraphnewStateGraph();graph.addNode(parse_input,node_async(state-{...})).addNode(analyze_text,node_async(state-{StringresultChatClient.builder(chatModel).build().prompt().user(Analyze: text).call().content();returnMap.of(analysis,result);})).addNode(format_output,node_async(state-{...})).addEdge(START,parse_input).addEdge(parse_input,analyze_text).addEdge(analyze_text,format_output).addEdge(format_output,END);returngraph.compile(observationConfig);// ← 关键传入观测 Config}效果每个Node执行自动创建SpanGraph级别的totalduration自动记录为Metric。6.3 ReactAgent 观测双层次观测.observationRegistry().compileConfig()Bean(observedWeatherAgent)publicReactAgentobservedWeatherAgent(ChatModelchatModel,ObservationRegistryobservationRegistry,Qualifier(observationGraphCompileConfig)CompileConfigobservationConfig){returnReactAgent.builder().name(weather-assistant).model(chatModel).instruction(You are a helpful weather assistant.).methodTools(newWeatherTool()).observationRegistry(observationRegistry)// ChatModel 层观测.compileConfig(observationConfig)// Graph 层观测.enableLogging(true).build();}6.4 OtlpLoggingConfigSpring Boot默认不自动装配LoggerProvider需手动安装OpenTelemetryAppenderComponentpublicclassOtlpLoggingConfigimplementsInitializingBean{privatefinalOpenTelemetryopenTelemetry;OverridepublicvoidafterPropertiesSet(){OpenTelemetryAppender.install(openTelemetry);}}6.5 ObservationFilterConfigSpring Boot 3.4移除了management.observations.http.server.requests.ignored-uris改用编程方式过滤BeanObservationPredicateonlyBusinessApiObservations(){return(observationName,context)-{if(contextinstanceofServerRequestObservationContextserver){Stringuriserver.getCarrier().getRequestURI();returnuri.startsWith(/api/)!uri.startsWith(/api/proxy/);}returntrue;};}7. 观测指标Metrics7.1 自动采集的指标指标名类型说明spring.ai.alibaba.graph.executionTimerGraph 执行耗时spring.ai.alibaba.graph.node.executionTimer单个 Node 执行耗时spring.ai.alibaba.graph.edge.executionTimerEdge 路由耗时gen_ai.client.operation.durationHistogramLLM 操作耗时GenAI 语义约定gen_ai.client.token.usageHistogramToken 用量input/output/total7.2 查看指标# 查看所有 Graph 相关指标curlhttp://localhost:8080/actuator/metrics|jq.names[]|grepgraph# 查看特定指标详情curlhttp://localhost:8080/actuator/metrics/spring.ai.alibaba.graph.execution# 查看观测状态curlhttp://localhost:8080/api/observation/status8. 观测拦截器示例8.1 Bean 注册 HookGraphObservationLifecycleListener作为LifecycleHook挂载在 Bean 生命周期的afterPropertiesSet时自动注册到HookManager全局生效无需每个Graph手动注册// 源码GraphObservationLifecycleListenerOverridepublicvoidafterPropertiesSet(){HookManager.register(this);// ← 全局注册所有 Graph 编译时自动包含}8.2 树型 Span 结构Graph Execution Span ├── Node: parse_input Span │ └── (ChatClient Span) │ └── (ChatModel Span) ├── Node: analyze_text Span │ └── (ChatClient Span) │ └── (ChatModel Span) │ ├── gen_ai.token.usage (input156, output89, total245) │ └── gen_ai.operation.duration (1.2s) ├── Edge: analyze_text - transform_text Span ├── Node: transform_text Span ├── Edge: transform_text - format_output Span ├── Node: format_output Span └── Edge: format_output - END Span9. API 端点# StateGraph 同步GET http://localhost:8080/api/graph/text-process?texthello# StateGraph 流式SSEGET http://localhost:8080/api/graph/text-process/stream?texthello# ReactAgent 同步GET http://localhost:8080/api/agent/weather?queryBeijing# ReactAgent 流式SSEGET http://localhost:8080/api/agent/weather/stream?queryBeijing# 观测状态查询GET http://localhost:8080/api/observation/status前端页面路径功能/index.html仪表盘首页/ai-chat.htmlAI 对话界面/trace-viewer.htmlTrace 链路查看器/ai-metrics.htmlAI 指标监控面板/log-viewer.html日志查看器