操作场景
Spring AI 是 Java 生态中常用的 AI 应用开发框架,Agent 运行时会产生多轮 ReAct 推理、模型调用、工具调用、向量检索和子 Agent 调用等数据。在 Spring AI 应用中引入腾讯云 Agent 可观测 SDK tencentcloud-agentobs-sdk-springai-java 后,只需将 SDK 注册到 Spring AI 使用的
ObservationRegistry 上,即可自动采集 Spring AI 原生产出的 Micrometer Observation,还原完整调用链路,并通过 OTLP/HTTP 协议将 Trace 上报到 腾讯云 Agent 可观测。产品能力介绍请参见 Agent 可观测产品页,如需对比其他接入方式,请参见 选择接入方式。接入完成后,您可以在 Agent 可观测控制台查看以下信息:
每次顶层
ChatClient 调用的完整调用链,以及入口、Agent、推理轮次(Step)、模型调用、工具调用、Embedding 和向量检索之间的父子关系。模型调用的请求模型、请求参数(如 temperature、max_tokens)、输入/输出 Token、结束原因(finish_reason)、耗时和输入/输出消息。
工具名称、调用参数、返回结果、耗时、错误类型和错误信息。
工具内部嵌套调用的子 Agent,以及多层子 Agent 的嵌套关系。
.call() 同步调用与 .stream() 流式调用的完整链路,流式调用跨 Reactor 线程时仍归属于同一条 Trace。按会话(Session)和用户(User)聚合的多轮请求关联关系。
SDK 具有以下特点:
无字节码增强:纯 SDK 依赖,不依赖 javaagent,业务代码无需修改。
无需开启 Spring AI 隐私开关:SDK 直接从 Observation 上下文读取 Prompt、Completion 和工具参数,无需开启 Spring AI 的
include-prompt 配置。可与其他 OTel 实现共存:SDK 内置的 OpenTelemetry 依赖已做隔离,可与应用中已有的 APM javaagent 或其他 OpenTelemetry 实现安全共存。
本文提供以下两种接入方式,您可根据实际情况选择:
接入方式 | 说明 | 推荐场景 |
使用支持 Skill 的 AI 工具,由 AI 创建或复用日志主题,并完成 SDK 引入、配置和验证。 | 希望减少手动配置,并在接入后通过自然语言分析 Trace 数据。 | |
引入 Maven 依赖,配置 Endpoint、日志主题和访问凭证,并在代码中注册 SDK。 | 需要精细控制接入参数,或所用工具不支持 Skill。 |
前提条件
接入前,请确认已完成以下准备工作:
已开通 AgentObs(Agent 可观测)。
已准备具备 AgentObs。写入权限的访问凭证,例如 CAM 子账号、CAM 角色或临时密钥。云 API 密钥信息请前往 API 密钥管理 获取,密钥需对目标主题有写入权限,权限模板参见 采集 Agent 可观测数据。
已获取接入所需的地域接入点(Endpoint):即 Agent 应用所在地域的接入点域名,请参见 地域和访问域名。以广州地域为例:
方式一填写地域:
ap-guangzhou。方式二填写域名:内网为
ap-guangzhou.cls.tencentyun.com,外网为 ap-guangzhou.cls.tencentcs.com。已基于 Spring AI 开发应用,且应用可以正常运行。版本要求如下:
组件 | 支持版本 |
JDK | 17及以上 |
Spring AI | 1.0.x、2.0.x |
Spring Boot | 3.x、4.x |
Micrometer Observation | 跟随应用使用的 Spring Boot 版本 |
方式一:通过 Skill 快速接入与分析
如果您使用支持 Skill 的 AI 工具,可使用 腾讯云 Agent 可观测助手 自动完成接入与分析。该 Skill 可创建或复用日志主题,识别 Spring AI 项目并完成 Maven 依赖引入、配置和验证。
在 AI 工具中输入以下内容:
请使用腾讯云 Agent 可观测助手 Skill:https://skillhub.cn/skills/tencentcloud-cls-agent-obs帮我把当前 Spring AI 项目接入腾讯云 Agent 可观测,地域为 ap-guangzhou。
接入完成后,您还可以直接描述分析需求。例如:
分析这个 Agent 最近 1 小时的运行情况,定位耗时最高、Token 消耗最多和失败最多的模型或工具调用,并给出可能原因。
方式二:手动配置接入
如果您需要精细控制 SDK、日志主题或访问凭证等参数,或者所用工具不支持 Skill,请按以下步骤手动完成接入。
步骤1:创建 Agent 可观测应用
1. 进入 Agent 可观测 页面。
2. 单击应用接入,根据页面提示创建应用。
3. 在新创建的应用右侧单击编辑,复制 Trace 日志主题 ID。该 ID 用于后续配置中的
CLS_TOPIC_ID。步骤2:引入 SDK 依赖
在 Spring AI 项目的
pom.xml 中添加以下依赖:<dependency><groupId>com.tencentcloudapi.observability</groupId><artifactId>tencentcloud-agentobs-sdk-springai-java</artifactId><version>1.0.1</version></dependency>
说明:
SDK 以
provided 方式依赖 spring-ai-client-chat、spring-ai-model 和 micrometer-observation,不会强制指定这些组件的版本,请确保应用中已引入上述依赖。SDK 源码和示例工程请参见 tencentcloud-agentobs-sdk-springai-java。
步骤3:配置环境变量
设置 Endpoint、日志主题 ID 和腾讯云访问密钥。以下示例以广州地域外网为例:
export CLS_ENDPOINT=ap-guangzhou.cls.tencentcs.comexport CLS_TOPIC_ID=<Trace 日志主题 ID>export CLS_SECRET_ID=<SecretId>export CLS_SECRET_KEY=<SecretKey>
$env:CLS_ENDPOINT = "ap-guangzhou.cls.tencentcs.com"$env:CLS_TOPIC_ID = "<Trace日志主题ID>"$env:CLS_SECRET_ID = "<SecretId>"$env:CLS_SECRET_KEY = "<SecretKey>"
环境变量 | 是否必填 | 说明 |
CLS_ENDPOINT | 是 | 地域接入点域名,须与 Trace 日志主题位于同一地域。未填写协议前缀时,SDK 自动补全 https://。 |
CLS_TOPIC_ID | 是 | 步骤1中获取的 Trace 日志主题 ID。请勿填写应用 ID。 |
CLS_SECRET_ID | 是 | |
CLS_SECRET_KEY | 是 | 腾讯云访问密钥 Key。 |
以上4项必填配置缺少任意一项时,SDK 初始化会抛出
IllegalStateException 并列出缺失项。除环境变量外,您也可以将配置写入
.env 文件。SDK 依次查找应用工作目录下的 ./.env 和 ~/.agentobs-springai/config.env,读取最先找到的一个文件,且不会覆盖已设置的环境变量。CLS_ENDPOINT=ap-guangzhou.cls.tencentcs.comCLS_TOPIC_ID=<Trace 日志主题 ID>CLS_SECRET_ID=<SecretId>CLS_SECRET_KEY=<SecretKey>
注意:
访问凭证属于敏感信息,建议通过环境变量或不提交到代码仓库的
.env 文件注入,并使用最小权限、可轮换的临时凭证,避免将 SecretKey 硬编码到代码中。步骤4:初始化采集
根据应用类型,将 SDK 注册到 Spring AI 使用的
ObservationRegistry 上。原有 ChatClient、ChatModel、@Tool 等业务代码无需修改。新增一个配置类,声明
ClsObservability Bean:import com.tencentcloudapi.observability.springai.ClsObservability;import io.micrometer.observation.ObservationRegistry;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;@Configurationpublic class ClsObservabilityConfig {// 容器关闭时自动上报剩余的 Span@Bean(destroyMethod = "shutdown")public ClsObservability clsObservability(ObservationRegistry observationRegistry) {// 从环境变量或 .env 文件读取 CLS 配置ClsObservability obs = ClsObservability.install();// 注册到 Spring AI 实际使用的 ObservationRegistryobs.registerOn(observationRegistry);return obs;}}
在应用启动时初始化 SDK,并注册到
ChatClient / ChatModel 所使用的 ObservationRegistry 上:ClsObservability obs = ClsObservability.install();obs.registerOn(registry);// ... 原有 Spring AI 业务代码 ...obs.flush(); // 可选,立即上报缓冲区中的 Spanobs.shutdown(); // 可选,JVM 退出时 SDK 会自动执行
注意:
SDK 必须注册到 Spring AI 实际使用的同一个
ObservationRegistry 实例上,自行通过 ObservationRegistry.create() 新建的实例无法接收 Spring AI 的事件。Spring Boot 应用通常由 spring-boot-starter-actuator 自动装配该 Bean;如果应用未引入 Actuator,可使用 @ConditionalOnMissingBean 声明一个兜底 Bean:@Bean@ConditionalOnMissingBeanpublic ObservationRegistry observationRegistry() {return ObservationRegistry.create();}
如需在代码中显式指定参数,可以传入
ClsConfig,未填写的字段会回退读取环境变量:import com.tencentcloudapi.observability.springai.ClsConfig;import com.tencentcloudapi.observability.springai.ClsObservability;ClsObservability obs = ClsObservability.install(ClsConfig.builder().serviceName("order-assistant").serviceVersion("2.3.0").deploymentEnvironment("prod").customAttribute("project_id", "proj_001").build()); // 访问凭证仍从环境变量或 .env 文件读取
配置优先级为:
ClsConfig 显式传入的值 > 环境变量 > .env 文件 > 默认值。ClsConfig 支持的可选参数如下:Builder 方法 | 环境变量 | 默认值 | 说明 |
serviceName | CLS_SERVICE_NAME | springai-app | 服务或应用名称。 |
serviceVersion | CLS_SERVICE_VERSION | 无 | 服务版本。 |
serviceInstanceId | CLS_SERVICE_INSTANCE_ID | <主机名>@<进程号> | 服务实例 ID。 |
deploymentEnvironment | CLS_DEPLOYMENT_ENVIRONMENT | 无 | 部署环境,例如 prod、test。 |
source | CLS_SOURCE | 本机 IP | 上报来源 IP。 |
batchSize | CLS_BATCH_SIZE | 32 | 每批上报的 Span 数量,取值范围为1 - 1000。 |
sampleRatio | CLS_SAMPLE_RATIO | 1.0 | |
debug | CLS_DEBUG | false | 是否以 DEBUG 级别输出每个 Observation 的开始和结束日志。 |
reactorContextPropagation | CLS_SPRINGAI_REACTOR_CONTEXT_PROPAGATION | true | |
customAttribute(key, value) | CLS_CUSTOM_<KEY> | 无 | 自定义属性,以 agent.custom.<key> 写入 Span,key 自动转为小写。 |
步骤5:关联会话与用户(推荐)
在调用
ChatClient 前,通过 ClsBaggage 设置会话 ID 和用户 ID,即可在 Agent 可观测控制台按会话或用户聚合分析 Trace:import com.tencentcloudapi.observability.springai.ClsBaggage;@PostMapping("/chat")public String chat(@RequestHeader("X-Session-Id") String sessionId,@RequestHeader("X-User-Id") String userId,@RequestBody String prompt) {ClsBaggage.set(sessionId, userId); // 或 ClsBaggage.set(sessionId, userId, userName)try {return chatClient.prompt().user(prompt).call().content();} finally {ClsBaggage.clear();}}
方法 | 写入的 Span 字段 |
ClsBaggage.set(sessionId, userId[, userName]) | 同时设置会话 ID、用户 ID 和用户名称。 |
ClsBaggage.setSession(id) | gen_ai.session.id |
ClsBaggage.setUser(id) | gen_ai.user.id |
ClsBaggage.setUserName(name) | gen_ai.user.name |
说明:
SDK 在每轮对话开始时读取并固化 Baggage,
.stream() 流式调用无需在 Reactor 算子间手动传递。未调用
ClsBaggage 时,SDK 会自动生成 sess-<16位十六进制> 格式的会话 ID,Trace 仍然完整,但无法按真实会话或用户聚合。步骤6:运行 Agent 并验证结果
1. 启动应用,在启动日志中确认出现
installed (service=..., endpoint=..., topic=..., sampleRatio=...),表示 SDK 初始化成功。2. 运行一次包含模型调用的 Agent 任务。建议同时触发一个工具调用,以便检查完整调用树。
3. 登录 Agent 可观测控制台,进入步骤1创建的应用。
4. 打开调用链页面,选择包含测试请求的时间范围。
5. 打开最新 Trace,检查是否包含 Entry、Agent、Step、Chat、Tool 等 Span。
6. 选择具体 Span,检查其耗时、状态、输入输出、Token 用量和模型请求参数等数据。
采集数据说明
Span 层级与采集属性
SDK 将 Spring AI 的 Observation 映射为以下调用树结构:
enter_application ← 入口,每次顶层 ChatClient 调用生成一个└─ invoke_agent main ← 主 Agent├─ react round_1 ← 第1轮推理│ ├─ chat <model> ← 模型调用(ChatModel)│ ├─ execute_tool <tool> ← 工具调用(ToolCallback)│ │ └─ invoke_subagent <tool> ← 工具内部嵌套调用的 ChatClient│ │ └─ react round_1 ─ chat / execute_tool ...│ ├─ embedding ← 向量化(EmbeddingModel)│ └─ retrieval <store> ← 向量检索(VectorStore)└─ react round_2 .. N ← 每多一轮工具调用,新增一个推理轮次└─ chat <model> / execute_tool <tool> ...
Span 类型(gen_ai.span.kind) | 对应操作 | 主要采集属性 |
entry | 应用入口 | 会话 ID、轮次 ID、用户 ID、输入/输出消息。Agent 执行出错时,错误状态会传播到该 Span。 |
agent | 主 Agent 或子 Agent | Agent 名称、Agent 范围( main 或 subagent)、输入/输出消息。子 Agent 通过 gen_ai.subagent.parent_tool_call.id 关联触发它的工具调用。 |
step | ReAct 推理轮次、Embedding 及其他操作 | 推理轮次编号、Step ID、结束原因;Embedding 的输入内容、向量数量和向量维度。 |
chat | 模型调用 | 请求模型、temperature、top_p、max_tokens 等请求参数,结束原因,输入/输出 Token,调用耗时,输入/输出消息。 |
tool | 工具调用 | 工具名称、调用 ID、调用参数、返回结果、调用耗时,异常时记录错误类型。 |
retriever | 向量检索 | 检索语句、top_k、返回文档数量、检索耗时。 |
调用树的识别规则如下:
ReAct 多轮推理:某次模型调用以
finish_reason=tool_calls 结束后,下一次模型调用会开启新的推理轮次 react round_N。子 Agent:工具内部调用的
ChatClient 识别为 invoke_subagent <工具名>,与外层共享会话 ID 和轮次 ID,支持任意嵌套深度,内外层 .call() 与 .stream() 可任意组合。多个顶层 ChatClient:同一请求内先后调用多个顶层
ChatClient 时,每次调用生成独立的 Trace。输入/输出消息采用 OpenAI Chat 格式的 JSON 数组记录,单个字段超过8000字符时截断。Spring AI 原生附带的 Micrometer 标签也会一并写入对应 Span。完整字段定义请参见 Agent Trace 字段定义说明。
Trace 采样
SDK 默认全量上报 Trace。如需降低上报量和存储成本,可调低采样率:
# 大约每 10 轮对话保留 1 轮export CLS_SAMPLE_RATIO=0.1
ClsObservability.install(ClsConfig.builder().sampleRatio(0.1).build());
采样率配置优先级为:
ClsConfig 显式传入的值 > JVM 参数 -Dcls.springai.sample-ratio > 环境变量 CLS_SAMPLE_RATIO > .env 文件 > 默认值 1.0。超出0.0 - 1.0范围的值会被修正为边界值,无法解析的值按 1.0 处理。注意:
采样以单轮对话(一次顶层
ChatClient 调用)为单位,同一轮对话内的所有 Span(包括嵌套的子 Agent)要么全部保留,要么全部丢弃,不会出现残缺的调用树。采样按轮次而非按会话进行,开启采样后,同一会话的多轮对话之间可能出现缺失。如需完整审计会话,请保持采样率为
1.0。采样仅减少上报量和存储量,被丢弃的轮次仍会在应用内完成采集处理。
采样率设置为
0 时将丢弃全部 Trace,SDK 会在启动时输出告警日志。流式调用
ChatClient.stream() 会将 Spring AI 内部的 Observation 派发到 Reactor 调度线程。为确保流式调用的 Span 归属于同一条 Trace,SDK 初始化时会自动开启 Reactor 自动上下文传播(Hooks.enableAutomaticContextPropagation())。该设置对 JVM 全局生效且可重复调用;应用中未引入 Reactor 时不执行任何操作。如果应用已自行开启该设置,可通过以下任一方式关闭 SDK 的自动开启:
代码配置:
ClsConfig.builder().reactorContextPropagation(false)JVM 参数:
-Dcls.springai.reactor-context-propagation=false(优先于环境变量)环境变量:
CLS_SPRINGAI_REACTOR_CONTEXT_PROPAGATION=false常见问题
启动时报错 IllegalStateException: CLS configuration incomplete
缺少必填配置。请检查
CLS_ENDPOINT、CLS_TOPIC_ID、CLS_SECRET_ID、CLS_SECRET_KEY 是否已通过环境变量、.env 文件或 ClsConfig 全部配置,报错信息中会列出缺失项。AgentObs 中没有 Trace 数据
请按以下顺序检查:
1. 确认
registerOn() 传入的是 Spring AI 实际使用的 ObservationRegistry,而不是自行新建的实例。2. 查看启动日志中的
installed (service=..., endpoint=..., topic=..., sampleRatio=...),确认 Endpoint、日志主题 ID 和采样率是否正确。3. 确认
CLS_ENDPOINT 与 Trace 日志主题位于同一地域。4. 确认
CLS_TOPIC_ID 为 Trace 日志主题 ID,而不是 Agent 可观测应用 ID。5. 确认访问密钥具备目标日志主题的写入权限。
6. 确认运行环境能够访问所配置的 Endpoint。使用内网域名时,需确保应用运行在同地域的腾讯云内网环境中。
7. 完成测试任务后,等待至少一个刷新周期再查询数据。
如仍无法定位,可设置
CLS_DEBUG=true,并将 com.tencentcloudapi.observability 的日志级别调整为 DEBUG,查看 onStart TURN session=... turn=... traceId=... 等 SDK 日志。AgentObs 中只有部分对话的 Trace
可能已开启 Trace 采样。请查看启动日志中的
sampleRatio 取值,如需全量上报,请设置 CLS_SAMPLE_RATIO=1.0。流式调用的 Span 被拆分为多条 Trace
Reactor 上下文传播被关闭或开启失败。请检查启动日志中是否有
enabled Reactor automatic context propagation,并确认未 reactorContextPropagation 设置为 false。Trace 中的会话 ID 显示为 sess-xxx
未设置会话信息。请在调用
ChatClient 前调用 ClsBaggage.set(...) 传入业务会话 ID 和用户 ID,详见步骤5。Spring AI 原生的 gen_ai.prompt 字段为空
Spring AI 的
include-prompt 配置默认关闭,因此原生字段为空。SDK 会直接读取对话内容并写入 gen_ai.input.messages 和 gen_ai.output.messages 字段,请查看这两个字段。Trace 中缺少 Token 或部分模型属性
Token 用量、结束原因等数据来自模型服务的返回结果。如果模型服务或对应的 Spring AI 模型集成未返回 Usage、结束原因等字段,SDK 无法采集。
应用中已使用 APM javaagent 或其他 OpenTelemetry 实现,是否冲突
不冲突。SDK 内置的 OpenTelemetry 依赖已重定位到独立包名,APM javaagent 的字节码增强不会作用于 SDK 的 Tracer;SDK 也不会注册全局
GlobalOpenTelemetry 实例,不会影响应用已有的 OpenTelemetry 配置。如果某个工作线程上同时存在 APM 注入的父上下文和上一次流式调用的残留状态,SDK 会以独立的根上下文开启新一轮对话,以确保 AgentObs 中的 Trace 完整独立,此时该请求与 APM 链路的关联会丢失。
相关文档
选择接入方式