Skip to content

Commit 43905d5

Browse files
committed
fix
1 parent be4827d commit 43905d5

12 files changed

Lines changed: 668 additions & 105 deletions

File tree

apm-protocol/apm-network/src/main/java/org/apache/skywalking/apm/network/trace/component/ComponentsDefine.java

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,36 @@ public class ComponentsDefine {
265265

266266
public static final OfficialComponent DMDB_JDBC_DRIVER = new OfficialComponent(163, "Dmdb-jdbc-driver");
267267

268-
public static final OfficialComponent SPRING_AI = new OfficialComponent(164, "Spring-ai");
268+
public static final OfficialComponent SPRING_AI_UNKNOWN = new OfficialComponent(164, "spring-ai-unknown");
269+
270+
public static final OfficialComponent SPRING_AI_ANTHROPIC = new OfficialComponent(165, "spring-ai-anthropic");
271+
272+
public static final OfficialComponent SPRING_AI_BEDROCK = new OfficialComponent(166, "spring-ai-aws-bedrock");
273+
274+
public static final OfficialComponent SPRING_AI_AZURE_OPENAI = new OfficialComponent(167, "spring-ai-azure-openai");
275+
276+
public static final OfficialComponent SPRING_AI_COHERE = new OfficialComponent(168, "spring-ai-cohere");
277+
278+
public static final OfficialComponent SPRING_AI_DEEPSEEK = new OfficialComponent(169, "spring-ai-deepseek");
279+
280+
public static final OfficialComponent SPRING_AI_GOOGLE_GENAI = new OfficialComponent(170, "spring-ai-gcp-genai");
281+
282+
public static final OfficialComponent SPRING_AI_VERTEXAI = new OfficialComponent(171, "spring-ai-gcp-vertex-ai");
283+
284+
public static final OfficialComponent SPRING_AI_MISTRAL_AI = new OfficialComponent(172, "spring-ai-mistral-ai");
285+
286+
public static final OfficialComponent SPRING_AI_OPENAI = new OfficialComponent(173, "spring-ai-openai");
287+
288+
public static final OfficialComponent SPRING_AI_HUGGINGFACE = new OfficialComponent(174, "spring-ai-huggingface");
289+
290+
public static final OfficialComponent SPRING_AI_MINIMAX = new OfficialComponent(175, "spring-ai-minimax");
291+
292+
public static final OfficialComponent SPRING_AI_OLLAMA = new OfficialComponent(176, "spring-ai-ollama");
293+
294+
public static final OfficialComponent SPRING_AI_OPENAI_SDK = new OfficialComponent(177, "spring-ai-openai-sdk");
295+
296+
public static final OfficialComponent SPRING_AI_ZHIPU_AI = new OfficialComponent(178, "spring-ai-zhipu-ai");
297+
298+
public static final OfficialComponent SPRING_AI = new OfficialComponent(179, "spring-ai");
269299

270300
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
*/
18+
19+
package org.apache.skywalking.apm.agent.core.util;
20+
21+
import com.google.gson.Gson;
22+
import com.google.gson.GsonBuilder;
23+
24+
public class GsonUtil {
25+
26+
private static final Gson GSON = new GsonBuilder()
27+
.disableHtmlEscaping()
28+
.create();
29+
30+
public static String toJson(Object src) {
31+
if (src == null) {
32+
return null;
33+
}
34+
return GSON.toJson(src);
35+
}
36+
}

apm-sniffer/apm-sdk-plugin/spring-plugins/spring-ai-1.x-plugin/pom.xml

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,5 @@
4343
<scope>provided</scope>
4444
</dependency>
4545

46-
<dependency>
47-
<groupId>org.springframework.ai</groupId>
48-
<artifactId>spring-ai-advisors-vector-store</artifactId>
49-
<version>1.1.0</version>
50-
<scope>provided</scope>
51-
</dependency>
5246
</dependencies>
5347
</project>

apm-sniffer/apm-sdk-plugin/spring-plugins/spring-ai-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/ai/v1/ChatModelCallInterceptor.java

Lines changed: 24 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,13 @@
2626
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
2727
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
2828
import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
29+
import org.apache.skywalking.apm.network.trace.component.OfficialComponent;
2930
import org.apache.skywalking.apm.plugin.spring.ai.v1.common.ChatModelMetadataResolver;
3031
import org.apache.skywalking.apm.plugin.spring.ai.v1.config.SpringAiPluginConfig;
3132
import org.apache.skywalking.apm.plugin.spring.ai.v1.contant.Constants;
3233
import org.apache.skywalking.apm.plugin.spring.ai.v1.enums.AiProviderEnum;
33-
import org.springframework.ai.chat.messages.Message;
34+
import org.apache.skywalking.apm.plugin.spring.ai.v1.messages.InputMessages;
35+
import org.apache.skywalking.apm.plugin.spring.ai.v1.messages.OutputMessages;
3436
import org.springframework.ai.chat.metadata.ChatResponseMetadata;
3537
import org.springframework.ai.chat.metadata.Usage;
3638
import org.springframework.ai.chat.model.ChatResponse;
@@ -45,27 +47,29 @@ public class ChatModelCallInterceptor implements InstanceMethodsAroundIntercepto
4547
@Override
4648
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
4749
ChatModelMetadataResolver.ApiMetadata apiMetadata = ChatModelMetadataResolver.getMetadata(objInst);
48-
String providerName = AiProviderEnum.UNKNOW.getValue();
50+
String providerName = AiProviderEnum.UNKNOWN.getValue();
51+
OfficialComponent component = ComponentsDefine.SPRING_AI_UNKNOWN;
4952
String peer = null;
5053

5154
if (apiMetadata != null) {
5255
if (apiMetadata.getProviderName() != null) {
5356
providerName = apiMetadata.getProviderName();
57+
component = apiMetadata.getComponent();
5458
}
5559
peer = apiMetadata.getPeer();
5660
}
5761
AbstractSpan span = ContextManager.createExitSpan("Spring-ai/" + providerName + "/call", peer);
5862
SpanLayer.asGenAI(span);
63+
span.setComponent(component);
64+
Tags.GEN_AI_OPERATION_NAME.set(span, Constants.CHAT);
65+
Tags.GEN_AI_PROVIDER_NAME.set(span, apiMetadata.getProviderName());
5966

6067
Prompt prompt = (Prompt) allArguments[0];
6168
ChatOptions chatOptions = prompt.getOptions();
6269
if (chatOptions == null) {
6370
return;
6471
}
6572

66-
span.setComponent(ComponentsDefine.SPRING_AI);
67-
Tags.GEN_AI_OPERATION_NAME.set(span, Constants.CHAT);
68-
Tags.GEN_AI_PROVIDER_NAME.set(span, apiMetadata.getProviderName());
6973
Tags.GEN_AI_REQUEST_MODEL.set(span, chatOptions.getModel());
7074
Tags.GEN_AI_TEMPERATURE.set(span, String.valueOf(chatOptions.getTemperature()));
7175
Tags.GEN_AI_TOP_K.set(span, String.valueOf(chatOptions.getTopK()));
@@ -120,7 +124,7 @@ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allA
120124
}
121125
}
122126

123-
collectContent(span, allArguments, generation, totalTokens);
127+
collectContent(span, allArguments, response, totalTokens);
124128
} finally {
125129
ContextManager.stopSpan();
126130
}
@@ -134,7 +138,7 @@ public void handleMethodException(EnhancedInstance objInst, Method method, Objec
134138
}
135139
}
136140

137-
private void collectContent(AbstractSpan span, Object[] allArguments, Generation generation, long totalTokens) {
141+
private void collectContent(AbstractSpan span, Object[] allArguments, ChatResponse response, long totalTokens) {
138142
int tokenThreshold = SpringAiPluginConfig.Plugin.SpringAi.CONTENT_COLLECT_THRESHOLD_TOKENS;
139143

140144
if (tokenThreshold >= 0 && totalTokens < tokenThreshold) {
@@ -146,7 +150,7 @@ private void collectContent(AbstractSpan span, Object[] allArguments, Generation
146150
}
147151

148152
if (SpringAiPluginConfig.Plugin.SpringAi.COLLECT_COMPLETION) {
149-
collectCompletion(span, generation);
153+
collectCompletion(span, response);
150154
}
151155
}
152156

@@ -161,33 +165,25 @@ private void collectPrompt(AbstractSpan span, Object[] allArguments) {
161165
return;
162166
}
163167

168+
InputMessages inputMessages = InputMessages.fromPrompt(prompt);
169+
String inputMessagesJson = inputMessages.toJson();
164170
int limit = SpringAiPluginConfig.Plugin.SpringAi.PROMPT_LENGTH_LIMIT;
165-
if (limit > 0 && promptText.length() > limit) {
166-
promptText = promptText.substring(0, limit);
167-
}
168-
169-
StringBuilder stringBuilder = new StringBuilder();
170-
for (Message instruction : prompt.getInstructions()) {
171-
stringBuilder.append(instruction.getText());
171+
if (limit > 0 && inputMessagesJson.length() > limit) {
172+
inputMessagesJson = inputMessagesJson.substring(0, limit);
172173
}
173174

174-
Tags.GEN_AI_INPUT_MESSAGES.set(span, promptText);
175+
Tags.GEN_AI_INPUT_MESSAGES.set(span, inputMessagesJson);
175176
}
176177

177-
private void collectCompletion(AbstractSpan span, Generation generation) {
178-
if (generation == null || generation.getOutput() == null) {
179-
return;
180-
}
181-
182-
String completionText = generation.getOutput().getText();
183-
if (completionText == null) {
184-
return;
185-
}
178+
private void collectCompletion(AbstractSpan span, ChatResponse response) {
186179

180+
OutputMessages outputMessages = OutputMessages.fromChatResponse(response);
181+
String outputMessagesJson = outputMessages.toJson();
187182
int limit = SpringAiPluginConfig.Plugin.SpringAi.COMPLETION_LENGTH_LIMIT;
188-
if (limit > 0 && completionText.length() > limit) {
189-
completionText = completionText.substring(0, limit);
183+
184+
if (limit > 0 && outputMessagesJson.length() > limit) {
185+
outputMessagesJson = outputMessagesJson.substring(0, limit);
190186
}
191-
Tags.GEN_AI_OUTPUT_MESSAGES.set(span, completionText);
187+
Tags.GEN_AI_OUTPUT_MESSAGES.set(span, outputMessagesJson);
192188
}
193189
}

apm-sniffer/apm-sdk-plugin/spring-plugins/spring-ai-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/ai/v1/ChatModelStreamInterceptor.java

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,13 @@
2727
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
2828
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
2929
import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
30+
import org.apache.skywalking.apm.network.trace.component.OfficialComponent;
3031
import org.apache.skywalking.apm.plugin.spring.ai.v1.common.ChatModelMetadataResolver;
3132
import org.apache.skywalking.apm.plugin.spring.ai.v1.config.SpringAiPluginConfig;
3233
import org.apache.skywalking.apm.plugin.spring.ai.v1.contant.Constants;
3334
import org.apache.skywalking.apm.plugin.spring.ai.v1.enums.AiProviderEnum;
35+
import org.apache.skywalking.apm.plugin.spring.ai.v1.messages.InputMessages;
36+
import org.apache.skywalking.apm.plugin.spring.ai.v1.messages.OutputMessages;
3437
import org.springframework.ai.chat.metadata.ChatResponseMetadata;
3538
import org.springframework.ai.chat.metadata.Usage;
3639
import org.springframework.ai.chat.model.ChatResponse;
@@ -41,6 +44,8 @@
4144
import reactor.core.publisher.Flux;
4245

4346
import java.lang.reflect.Method;
47+
import java.util.ArrayList;
48+
import java.util.List;
4449
import java.util.concurrent.atomic.AtomicBoolean;
4550
import java.util.concurrent.atomic.AtomicReference;
4651

@@ -49,19 +54,21 @@ public class ChatModelStreamInterceptor implements InstanceMethodsAroundIntercep
4954
@Override
5055
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
5156
ChatModelMetadataResolver.ApiMetadata apiMetadata = ChatModelMetadataResolver.getMetadata(objInst);
52-
String providerName = AiProviderEnum.UNKNOW.getValue();
57+
String providerName = AiProviderEnum.UNKNOWN.getValue();
58+
OfficialComponent component = ComponentsDefine.SPRING_AI_UNKNOWN;
5359
String peer = null;
5460

5561
if (apiMetadata != null) {
5662
if (apiMetadata.getProviderName() != null) {
5763
providerName = apiMetadata.getProviderName();
64+
component = apiMetadata.getComponent();
5865
}
5966
peer = apiMetadata.getPeer();
6067
}
6168
AbstractSpan span = ContextManager.createExitSpan("Spring-ai/" + providerName + "/stream", peer);
6269
SpanLayer.asGenAI(span);
6370

64-
span.setComponent(ComponentsDefine.SPRING_AI);
71+
span.setComponent(component);
6572
SpanLayer.asGenAI(span);
6673

6774
Prompt prompt = (Prompt) allArguments[0];
@@ -212,27 +219,36 @@ private void collectPrompt(AbstractSpan span, Object[] allArguments) {
212219
if (prompt == null) {
213220
return;
214221
}
215-
String promptText = prompt.getContents();
216-
if (promptText == null) {
217-
return;
218-
}
222+
223+
InputMessages inputMessages = InputMessages.fromPrompt(prompt);
224+
String inputMessagesJson = inputMessages.toJson();
225+
219226
int limit = SpringAiPluginConfig.Plugin.SpringAi.PROMPT_LENGTH_LIMIT;
220-
Tags.GEN_AI_INPUT_MESSAGES.set(span, truncate(promptText, limit));
227+
if (limit > 0 && inputMessagesJson.length() > limit) {
228+
inputMessagesJson = inputMessagesJson.substring(0, limit);
229+
}
230+
231+
Tags.GEN_AI_INPUT_MESSAGES.set(span, inputMessagesJson);
221232
}
222233

223234
private void collectCompletion(AbstractSpan span, StreamState state) {
224-
int limit = SpringAiPluginConfig.Plugin.SpringAi.COMPLETION_LENGTH_LIMIT;
225-
Tags.GEN_AI_OUTPUT_MESSAGES.set(span, truncate(state.completionBuilder.toString(), limit));
226-
}
227235

228-
private String truncate(String s, int limit) {
229-
if (s == null) {
230-
return null;
236+
String fullText = state.completionBuilder.toString();
237+
String finishReason = state.finishReason.get();
238+
List<InputMessages.MessagePart> parts = new ArrayList<>();
239+
if (fullText != null && !fullText.isEmpty()) {
240+
parts.add(new InputMessages.TextPart(fullText));
231241
}
232-
if (limit > 0 && s.length() > limit) {
233-
return s.substring(0, limit);
242+
243+
OutputMessages outputMessages = OutputMessages.create().append(OutputMessages.OutputMessage.create("assistant", parts, finishReason));
244+
String outputMessagesJson = outputMessages.toJson();
245+
246+
int limit = SpringAiPluginConfig.Plugin.SpringAi.COMPLETION_LENGTH_LIMIT;
247+
if (limit > 0 && outputMessagesJson.length() > limit) {
248+
outputMessagesJson = outputMessagesJson.substring(0, limit);
234249
}
235-
return s;
250+
251+
Tags.GEN_AI_OUTPUT_MESSAGES.set(span, outputMessagesJson);
236252
}
237253

238254
private Long readAndClearStartTime() {

0 commit comments

Comments
 (0)