跳到主要内容
版本:1.0.0

可观测性

Spring AI 基于 Micrometer 提供开箱即用的可观测性支持,自动记录 ChatModel、EmbeddingModel、ImageModel、VectorStore、Tool Calling 等组件的调用指标、耗时和内容快照,可对接 Zipkin、Grafana、Datadog 等主流监控后端。

1. 快速启用

引入对应 AI 模型或向量数据库的 Spring Boot Starter 即可自动启用可观测性,无需额外依赖。

首次使用时只需加入 Micrometer 的监控后端实现,例如 Zipkin:

pom.xml
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-bridge-brave</artifactId>
</dependency>
<dependency>
<groupId>io.zipkin.reporter2</groupId>
<artifactId>zipkin-reporter-brave</artifactId>
</dependency>

启动应用后,所有 AI 组件的调用自动出现在 Zipkin 的 trace 面板中。

2. 配置项

各组件的可观测性默认开启,可通过配置控制日志输出和指标采集:

配置项默认值说明
spring.ai.chat.observations.log-completionfalse是否在日志中输出模型的完整回复内容
spring.ai.chat.observations.log-errorfalse是否在日志中输出模型的错误回复
spring.ai.chat.observations.include-inputfalse是否在指标中附带用户输入内容
spring.ai.chat.client.observations.include-inputfalseChatClient 观测是否附带用户输入
spring.ai.image.observations.log-responsefalse是否在日志中输出图片生成响应
spring.ai.image.observations.log-errorfalse是否在日志中输出图片生成的错误
spring.ai.image.observations.include-inputfalse是否在指标中附带输入的提示词
spring.ai.tool.observations.include-inputfalse工具调用是否附带输入参数
spring.ai.tool.observations.include-errorfalse工具调用是否附带错误信息
spring.ai.vectorstore.observations.log-queryfalse是否在日志中输出向量搜索查询
spring.ai.vectorstore.observations.log-resultsfalse是否在日志中输出向量搜索结果
spring.ai.vectorstore.observations.log-errorfalse是否在日志中输出向量存储的错误
spring.ai.vectorstore.observations.include-inputfalse是否在指标中附带输入查询
spring.ai.tracing.include-request-responsefalse总体开关:是否在所有 trace span 中附带请求/响应内容
application.yml
spring:
ai:
chat:
observations:
log-completion: true # 调试时开启,便于排查模型回复
log-error: true
vectorstore:
observations:
log-query: true
log-error: true
tracing:
include-request-response: true

3. 可观测的组件

3.1 ChatModel

每次调用 ChatModel 或 StreamingChatModel 自动创建一个 Observation,记录模型名称、操作类型、AI 提供商等维度信息。

低基数标签(维度):

标签值示例说明
gen_ai.operation.namechat, streaming调用操作类型
gen_ai.systemspring_aiAI 框架标识
gen_ai.request.modelqwen3:8b使用的模型名称
gen_ai.providerollama, openaiAI 服务提供商
gen_ai.content.usage.input_tokens150输入 token 数
gen_ai.content.usage.output_tokens80输出 token 数

高基数标签(详细诊断):

标签说明
gen_ai.error.type错误类型(发生错误时)
gen_ai.request.temperature模型温度参数
gen_ai.request.top_ptop_p 参数
gen_ai.request.top_ktop_k 参数
gen_ai.response.id响应的唯一标识

3.2 EmbeddingModel

每次向量化调用自动记录嵌入模型、输入 token 数等指标。

标签值示例说明
gen_ai.operation.nameembedding操作类型
gen_ai.systemspring_aiAI 框架标识
gen_ai.request.modelmxbai-embed-large嵌入模型名称
gen_ai.providerollamaAI 服务提供商

3.3 ImageModel

图片生成调用自动记录模型名称、生成数量、尺寸等参数。

标签值示例说明
gen_ai.operation.nameimage_generation操作类型
gen_ai.systemspring_aiAI 框架标识
gen_ai.request.modeldall-e-3图片模型名称
gen_ai.provideropenaiAI 服务提供商

3.4 VectorStore

向量存储的写入、删除和检索操作自动记录,包含数据库信息、查询相似度等指标。

标签值示例说明
db.systempostgresql, redis, qdrant数据库类型
db.operationadd, delete, similarity_search操作类型
db.vector.metricscosine, euclidean相似度度量方式
db.vector.top_k5返回结果数
db.vector.similarity_threshold0.75相似度阈值

如果 VectorStore 实现未自动集成观测,可使用 AbstractObservationVectorStore 包装:

VectorStore rawStore = new SimpleVectorStore(embeddingModel);

// 包装后可观测
VectorStore observableStore = new ObservationVectorStore(
rawStore, observationRegistry, "custom_convention");

3.5 Tool Calling

工具调用的执行自动记录,包括工具名称、执行耗时、错误信息。

标签值示例说明
spring.ai.tool.namegetWeather被调用的工具名称
spring.ai.tool.statussuccess, error执行结果状态

3.6 ChatClient

ChatClient 层面的整次调用(涵盖 Advisors 链 + ChatModel 调用 + 工具回调 + 响应生成)统一记录。

标签值示例说明
spring.ai.chat.client.namemyChatClientChatClient 名称(Builder 指定时)
spring.ai.chat.client.prompt.typetext, multimodal提示词类型

3.7 Advisor

Advisor 链中每个 Advisor 的执行开始和结束自动记录:

标签说明
spring.ai.advisor.nameAdvisor 实现类简称
spring.ai.advisor.type执行阶段:beforeafter

4. 自定义观测约定

可以通过继承默认约定类并重写标签方法,在指标中添加自定义维度。

@Component
public class TenantAwareChatModelObservationConvention
extends DefaultChatModelObservationConvention {

@Override
public KeyValues getLowCardinalityKeyValues(
ChatModelObservationContext context) {
return super.getLowCardinalityKeyValues().and(
KeyValue.of("tenant.id", TenantContext.getCurrentTenant())
);
}

@Override
public KeyValues getHighCardinalityKeyValues(
ChatModelObservationContext context) {
return super.getHighCardinalityKeyValues().and(
KeyValue.of("user.id", UserContext.getCurrentUserId())
);
}
}

约定类只需声明为 Spring Bean,Spring AI 的自动配置会优先使用自定义约定而非默认约定。

可重写的约定类:

默认约定类观测范围
DefaultChatModelObservationConventionChatModel / StreamingChatModel
DefaultEmbeddingModelObservationConventionEmbeddingModel
DefaultImageModelObservationConventionImageModel
DefaultVectorStoreObservationConventionVectorStore 读/写/搜索

5. 手动创建 Span

对于自定义组件或需要更细粒度的追踪,可以直接使用 Micrometer 的 ObservationRegistry 手动创建观测:

@Component
public class CustomPipeline {

private final ObservationRegistry registry;

public CustomPipeline(ObservationRegistry registry) {
this.registry = registry;
}

public String execute(String input) {
Observation observation = Observation.createNotStarted(
"custom.ai.pipeline", registry)
.lowCardinalityKeyValue("pipeline.name", "document-etl")
.start();

try (Observation.Scope scope = observation.openScope()) {
// 执行业务逻辑
String result = process(input);
observation.event(Observation.Event.of("pipeline.completed"));
return result;
} catch (Exception e) {
observation.error(e);
throw e;
} finally {
observation.stop();
}
}

private String process(String input) {
return "processed: " + input;
}
}

6. 完整示例

完整示例:ObservabilityExample.java
public class ObservabilityExample {

public static void main(String[] args) {
var ctx = SpringApplication.run(ObservabilityExample.class, args);

OllamaApi ollamaApi = OllamaApi.builder()
.baseUrl("http://localhost:11434")
.build();

// ChatModel 调用自动观测
OllamaChatModel chatModel = OllamaChatModel.builder()
.ollamaApi(ollamaApi)
.defaultOptions(OllamaOptions.builder().model("qwen3:8b").build())
.build();

ChatClient chatClient = ChatClient.builder(chatModel)
.defaultAdvisors(
new SimpleLoggerAdvisor(),
new MessageChatMemoryAdvisor(new InMemoryChatMemory())
)
.build();

// 每次调用都会在 Zipkin/Grafana 中产生 trace span
String response = chatClient.prompt()
.user("介绍一下 Spring AI 的可观测性")
.advisors(a -> a.param("chat_memory_conversation_id", "obs-001"))
.call()
.content();

System.out.println(response);
}
}