From bc9b3a93a65bf04a1003b40a92250c102df027f7 Mon Sep 17 00:00:00 2001 From: chickenlj Date: Tue, 3 Dec 2024 16:04:16 +0800 Subject: [PATCH 1/7] add observability example --- .../observability-example/compose.yaml | 5 + .../observability-example/pom.xml | 120 ++++++++++++++++++ .../FileSpanExporterAutoConfiguration.java | 38 ++++++ .../ObservabilityApplication.java | 48 +++++++ .../observability/exporter/oltp/JsonUtil.java | 26 ++++ .../exporter/oltp/OtlpFileSpanExporter.java | 74 +++++++++++ .../oltp/OtlpFileSpanExporterProvider.java | 28 ++++ .../src/main/resources/application.properties | 13 ++ .../ObservabilityApplicationTests.java | 13 ++ spring-ai-alibaba-examples/pom.xml | 1 + 10 files changed, 366 insertions(+) create mode 100644 spring-ai-alibaba-examples/observability-example/compose.yaml create mode 100644 spring-ai-alibaba-examples/observability-example/pom.xml create mode 100644 spring-ai-alibaba-examples/observability-example/src/main/java/com/alibaba/cloud/ai/example/observability/FileSpanExporterAutoConfiguration.java create mode 100644 spring-ai-alibaba-examples/observability-example/src/main/java/com/alibaba/cloud/ai/example/observability/ObservabilityApplication.java create mode 100755 spring-ai-alibaba-examples/observability-example/src/main/java/com/alibaba/cloud/ai/example/observability/exporter/oltp/JsonUtil.java create mode 100755 spring-ai-alibaba-examples/observability-example/src/main/java/com/alibaba/cloud/ai/example/observability/exporter/oltp/OtlpFileSpanExporter.java create mode 100755 spring-ai-alibaba-examples/observability-example/src/main/java/com/alibaba/cloud/ai/example/observability/exporter/oltp/OtlpFileSpanExporterProvider.java create mode 100644 spring-ai-alibaba-examples/observability-example/src/main/resources/application.properties create mode 100644 spring-ai-alibaba-examples/observability-example/src/test/java/com/alibaba/cloud/ai/example/observability/ObservabilityApplicationTests.java diff --git a/spring-ai-alibaba-examples/observability-example/compose.yaml b/spring-ai-alibaba-examples/observability-example/compose.yaml new file mode 100644 index 00000000..ff23f8a8 --- /dev/null +++ b/spring-ai-alibaba-examples/observability-example/compose.yaml @@ -0,0 +1,5 @@ +services: + zipkin: + image: 'openzipkin/zipkin:latest' + ports: + - '9411:9411' diff --git a/spring-ai-alibaba-examples/observability-example/pom.xml b/spring-ai-alibaba-examples/observability-example/pom.xml new file mode 100644 index 00000000..f5b7f539 --- /dev/null +++ b/spring-ai-alibaba-examples/observability-example/pom.xml @@ -0,0 +1,120 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.3.3 + + + com.alibaba.cloud.ai + observability-example + 0.0.1-SNAPSHOT + observability-example + Demo project for Spring AI Alibaba + + + 17 + 1.0.0-M3 + 1.0.0-M3.2 + + + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.boot + spring-boot-starter-web + + + io.micrometer + micrometer-core + 1.13.6 + + + + io.micrometer + micrometer-tracing-bridge-otel + 1.3.4 + + + + + + + + io.opentelemetry + opentelemetry-sdk-extension-autoconfigure-spi + 1.37.0 + + + io.opentelemetry + opentelemetry-exporter-common + 1.37.0 + + + io.opentelemetry + opentelemetry-exporter-otlp-common + 1.37.0 + + + io.opentelemetry + opentelemetry-exporter-otlp + 1.37.0 + + + com.alibaba.cloud.ai + spring-ai-alibaba-starter + ${spring-ai-alibaba.version} + + + + + + + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + org.springframework.ai + spring-ai-bom + ${spring-ai.version} + pom + import + + + + + + + + org.graalvm.buildtools + native-maven-plugin + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + false + + + + + diff --git a/spring-ai-alibaba-examples/observability-example/src/main/java/com/alibaba/cloud/ai/example/observability/FileSpanExporterAutoConfiguration.java b/spring-ai-alibaba-examples/observability-example/src/main/java/com/alibaba/cloud/ai/example/observability/FileSpanExporterAutoConfiguration.java new file mode 100644 index 00000000..fcc606a4 --- /dev/null +++ b/spring-ai-alibaba-examples/observability-example/src/main/java/com/alibaba/cloud/ai/example/observability/FileSpanExporterAutoConfiguration.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.cloud.ai.example.observability; + +import com.alibaba.cloud.ai.example.observability.exporter.oltp.OtlpFileSpanExporter; +import com.alibaba.cloud.ai.example.observability.exporter.oltp.OtlpFileSpanExporterProvider; + +import org.springframework.boot.actuate.autoconfigure.tracing.ConditionalOnEnabledTracing; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ConditionalOnClass({OtlpFileSpanExporter.class}) +public class FileSpanExporterAutoConfiguration { + @Bean + @ConditionalOnMissingBean + @ConditionalOnEnabledTracing + OtlpFileSpanExporter outputSpanExporter() { + OtlpFileSpanExporterProvider provider = new OtlpFileSpanExporterProvider(); + return (OtlpFileSpanExporter)provider.createExporter(null); + } +} diff --git a/spring-ai-alibaba-examples/observability-example/src/main/java/com/alibaba/cloud/ai/example/observability/ObservabilityApplication.java b/spring-ai-alibaba-examples/observability-example/src/main/java/com/alibaba/cloud/ai/example/observability/ObservabilityApplication.java new file mode 100644 index 00000000..cb77e14e --- /dev/null +++ b/spring-ai-alibaba-examples/observability-example/src/main/java/com/alibaba/cloud/ai/example/observability/ObservabilityApplication.java @@ -0,0 +1,48 @@ +package com.alibaba.cloud.ai.example.observability; + +import org.springframework.ai.chat.client.ChatClient; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +import java.util.Map; + +@SpringBootApplication +public class ObservabilityApplication { + + public static void main(String[] args) { + SpringApplication.run(ObservabilityApplication.class, args); + } + + @Bean + ChatClient chatClient(ChatClient.Builder builder) { + return builder.build(); + } +} + +@Controller +@ResponseBody +class JokeController { + + private final ChatClient chatClient; + + JokeController(ChatClient chatClient) { + this.chatClient = chatClient; + } + + @GetMapping("/joke") + Map joke() { + var reply = chatClient + .prompt() + .user(""" + tell me a joke. be concise. don't send anything except the joke. + """) + .call() + .content(); + + return Map.of("joke", reply); + } +} diff --git a/spring-ai-alibaba-examples/observability-example/src/main/java/com/alibaba/cloud/ai/example/observability/exporter/oltp/JsonUtil.java b/spring-ai-alibaba-examples/observability-example/src/main/java/com/alibaba/cloud/ai/example/observability/exporter/oltp/JsonUtil.java new file mode 100755 index 00000000..8522f5d0 --- /dev/null +++ b/spring-ai-alibaba-examples/observability-example/src/main/java/com/alibaba/cloud/ai/example/observability/exporter/oltp/JsonUtil.java @@ -0,0 +1,26 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package com.alibaba.cloud.ai.example.observability.exporter.oltp; + +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.io.SegmentedStringWriter; +import java.io.IOException; + +final class JsonUtil { + + static final JsonFactory JSON_FACTORY = new JsonFactory(); + + static JsonGenerator create(SegmentedStringWriter stringWriter) { + try { + return JSON_FACTORY.createGenerator(stringWriter); + } catch (IOException e) { + throw new IllegalStateException("Unable to create in-memory JsonGenerator, can't happen.", e); + } + } + + private JsonUtil() {} +} diff --git a/spring-ai-alibaba-examples/observability-example/src/main/java/com/alibaba/cloud/ai/example/observability/exporter/oltp/OtlpFileSpanExporter.java b/spring-ai-alibaba-examples/observability-example/src/main/java/com/alibaba/cloud/ai/example/observability/exporter/oltp/OtlpFileSpanExporter.java new file mode 100755 index 00000000..e11c117f --- /dev/null +++ b/spring-ai-alibaba-examples/observability-example/src/main/java/com/alibaba/cloud/ai/example/observability/exporter/oltp/OtlpFileSpanExporter.java @@ -0,0 +1,74 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package com.alibaba.cloud.ai.example.observability.exporter.oltp; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.io.SegmentedStringWriter; +import io.opentelemetry.exporter.internal.otlp.traces.ResourceSpansMarshaler; +import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.trace.data.SpanData; +import io.opentelemetry.sdk.trace.export.SpanExporter; +import java.io.IOException; +import java.util.Collection; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * A {@link SpanExporter} which writes {@linkplain SpanData spans} to a {@link Logger} in OTLP JSON + * format. Each log line will include a single {@code ResourceSpans}. + */ +public final class OtlpFileSpanExporter implements SpanExporter { + + private static final Logger logger = + Logger.getLogger(OtlpFileSpanExporter.class.getName()); + + private final AtomicBoolean isShutdown = new AtomicBoolean(); + + /** Returns a new {@link OtlpFileSpanExporter}. */ + public static SpanExporter create() { + return new OtlpFileSpanExporter(); + } + + private OtlpFileSpanExporter() {} + + @Override + public CompletableResultCode export(Collection spans) { + if (isShutdown.get()) { + return CompletableResultCode.ofFailure(); + } + + ResourceSpansMarshaler[] allResourceSpans = ResourceSpansMarshaler.create(spans); + for (ResourceSpansMarshaler resourceSpans : allResourceSpans) { + SegmentedStringWriter sw = + new SegmentedStringWriter(JsonUtil.JSON_FACTORY._getBufferRecycler()); + try (JsonGenerator gen = JsonUtil.create(sw)) { + resourceSpans.writeJsonTo(gen); + } catch (IOException e) { + // Shouldn't happen in practice, just skip it. + continue; + } + try { + logger.log(Level.INFO, sw.getAndClear()); + } catch (IOException e) { + logger.log(Level.WARNING, "Unable to read OTLP JSON spans", e); + } + } + return CompletableResultCode.ofSuccess(); + } + + @Override + public CompletableResultCode flush() { + return CompletableResultCode.ofSuccess(); + } + + @Override + public CompletableResultCode shutdown() { + if (!isShutdown.compareAndSet(false, true)) { + logger.log(Level.INFO, "Calling shutdown() multiple times."); + } + return CompletableResultCode.ofSuccess(); + } +} diff --git a/spring-ai-alibaba-examples/observability-example/src/main/java/com/alibaba/cloud/ai/example/observability/exporter/oltp/OtlpFileSpanExporterProvider.java b/spring-ai-alibaba-examples/observability-example/src/main/java/com/alibaba/cloud/ai/example/observability/exporter/oltp/OtlpFileSpanExporterProvider.java new file mode 100755 index 00000000..70f2414f --- /dev/null +++ b/spring-ai-alibaba-examples/observability-example/src/main/java/com/alibaba/cloud/ai/example/observability/exporter/oltp/OtlpFileSpanExporterProvider.java @@ -0,0 +1,28 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package com.alibaba.cloud.ai.example.observability.exporter.oltp; + +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import io.opentelemetry.sdk.autoconfigure.spi.traces.ConfigurableSpanExporterProvider; +import io.opentelemetry.sdk.trace.export.SpanExporter; + +/** + * {@link SpanExporter} SPI implementation for {@link OtlpFileSpanExporter}. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ +public class OtlpFileSpanExporterProvider implements ConfigurableSpanExporterProvider { + @Override + public SpanExporter createExporter(ConfigProperties config) { + return OtlpFileSpanExporter.create(); + } + + @Override + public String getName() { + return "logging-otlp"; + } +} diff --git a/spring-ai-alibaba-examples/observability-example/src/main/resources/application.properties b/spring-ai-alibaba-examples/observability-example/src/main/resources/application.properties new file mode 100644 index 00000000..831c6e3f --- /dev/null +++ b/spring-ai-alibaba-examples/observability-example/src/main/resources/application.properties @@ -0,0 +1,13 @@ +spring.application.name=ai +# +#export AI_DASHSCOPE_API_KEY=... +spring.ai.dashscope.api-key=${AI_DASHSCOPE_API_KEY} +# +management.endpoints.web.exposure.include=* +management.endpoint.health.show-details=always +management.tracing.sampling.probability=1.0 +# +spring.threads.virtual.enabled=true + +# +#spring.docker.compose.lifecycle-management=start_only \ No newline at end of file diff --git a/spring-ai-alibaba-examples/observability-example/src/test/java/com/alibaba/cloud/ai/example/observability/ObservabilityApplicationTests.java b/spring-ai-alibaba-examples/observability-example/src/test/java/com/alibaba/cloud/ai/example/observability/ObservabilityApplicationTests.java new file mode 100644 index 00000000..60713ce9 --- /dev/null +++ b/spring-ai-alibaba-examples/observability-example/src/test/java/com/alibaba/cloud/ai/example/observability/ObservabilityApplicationTests.java @@ -0,0 +1,13 @@ +package com.alibaba.cloud.ai.example.observability; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class ObservabilityApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/spring-ai-alibaba-examples/pom.xml b/spring-ai-alibaba-examples/pom.xml index 025789bc..45cd64b1 100644 --- a/spring-ai-alibaba-examples/pom.xml +++ b/spring-ai-alibaba-examples/pom.xml @@ -41,6 +41,7 @@ rag-example output-parser-example playground-flight-booking + observability-example From 6a5b6844c1c78552ae9c26500e5e036c6531fe96 Mon Sep 17 00:00:00 2001 From: cirilla-zmh Date: Wed, 27 Nov 2024 18:23:45 +0800 Subject: [PATCH 2/7] add auto configuration of dashscope chat model --- .../dashscope/DashScopeAutoConfiguration.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/spring-ai-alibaba-autoconfigure/src/main/java/com/alibaba/cloud/ai/autoconfigure/dashscope/DashScopeAutoConfiguration.java b/spring-ai-alibaba-autoconfigure/src/main/java/com/alibaba/cloud/ai/autoconfigure/dashscope/DashScopeAutoConfiguration.java index 01ba2082..c47ad0b2 100644 --- a/spring-ai-alibaba-autoconfigure/src/main/java/com/alibaba/cloud/ai/autoconfigure/dashscope/DashScopeAutoConfiguration.java +++ b/spring-ai-alibaba-autoconfigure/src/main/java/com/alibaba/cloud/ai/autoconfigure/dashscope/DashScopeAutoConfiguration.java @@ -26,10 +26,12 @@ import com.alibaba.cloud.ai.dashscope.rerank.DashScopeRerankModel; import com.alibaba.dashscope.audio.asr.transcription.Transcription; import com.alibaba.dashscope.audio.tts.SpeechSynthesizer; +import io.micrometer.observation.ObservationRegistry; import org.jetbrains.annotations.NotNull; import org.springframework.ai.autoconfigure.retry.SpringAiRetryAutoConfiguration; import org.springframework.ai.model.function.FunctionCallback; import org.springframework.ai.model.function.FunctionCallbackContext; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.ImportAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; @@ -93,10 +95,11 @@ public Transcription transcription() { @ConditionalOnProperty(prefix = DashScopeChatProperties.CONFIG_PREFIX, name = "enabled", havingValue = "true", matchIfMissing = true) public DashScopeChatModel dashscopeChatModel(DashScopeConnectionProperties commonProperties, - DashScopeChatProperties chatProperties, RestClient.Builder restClientBuilder, - WebClient.Builder webClientBuilder, List toolFunctionCallbacks, - FunctionCallbackContext functionCallbackContext, RetryTemplate retryTemplate, - ResponseErrorHandler responseErrorHandler) { + DashScopeChatProperties chatProperties, RestClient.Builder restClientBuilder, + WebClient.Builder webClientBuilder, List toolFunctionCallbacks, + FunctionCallbackContext functionCallbackContext, RetryTemplate retryTemplate, + ResponseErrorHandler responseErrorHandler, + ObjectProvider observationRegistry) { if (!CollectionUtils.isEmpty(toolFunctionCallbacks)) { chatProperties.getOptions().getFunctionCallbacks().addAll(toolFunctionCallbacks); @@ -106,7 +109,7 @@ public DashScopeChatModel dashscopeChatModel(DashScopeConnectionProperties commo responseErrorHandler); return new DashScopeChatModel(dashscopeApi, chatProperties.getOptions(), functionCallbackContext, - retryTemplate); + retryTemplate, observationRegistry.getIfUnique(() -> ObservationRegistry.NOOP)); } @Bean From f86dd18c06eeb39002d71c8c7a0a832f51586942 Mon Sep 17 00:00:00 2001 From: cirilla-zmh Date: Tue, 3 Dec 2024 19:11:48 +0800 Subject: [PATCH 3/7] fea: auto configure observation registry of dashscope chat model --- .../dashscope/DashScopeAutoConfiguration.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/spring-ai-alibaba-autoconfigure/src/main/java/com/alibaba/cloud/ai/autoconfigure/dashscope/DashScopeAutoConfiguration.java b/spring-ai-alibaba-autoconfigure/src/main/java/com/alibaba/cloud/ai/autoconfigure/dashscope/DashScopeAutoConfiguration.java index c47ad0b2..2af8f803 100644 --- a/spring-ai-alibaba-autoconfigure/src/main/java/com/alibaba/cloud/ai/autoconfigure/dashscope/DashScopeAutoConfiguration.java +++ b/spring-ai-alibaba-autoconfigure/src/main/java/com/alibaba/cloud/ai/autoconfigure/dashscope/DashScopeAutoConfiguration.java @@ -95,11 +95,10 @@ public Transcription transcription() { @ConditionalOnProperty(prefix = DashScopeChatProperties.CONFIG_PREFIX, name = "enabled", havingValue = "true", matchIfMissing = true) public DashScopeChatModel dashscopeChatModel(DashScopeConnectionProperties commonProperties, - DashScopeChatProperties chatProperties, RestClient.Builder restClientBuilder, - WebClient.Builder webClientBuilder, List toolFunctionCallbacks, - FunctionCallbackContext functionCallbackContext, RetryTemplate retryTemplate, - ResponseErrorHandler responseErrorHandler, - ObjectProvider observationRegistry) { + DashScopeChatProperties chatProperties, RestClient.Builder restClientBuilder, + WebClient.Builder webClientBuilder, List toolFunctionCallbacks, + FunctionCallbackContext functionCallbackContext, RetryTemplate retryTemplate, + ResponseErrorHandler responseErrorHandler, ObjectProvider observationRegistry) { if (!CollectionUtils.isEmpty(toolFunctionCallbacks)) { chatProperties.getOptions().getFunctionCallbacks().addAll(toolFunctionCallbacks); @@ -108,8 +107,8 @@ public DashScopeChatModel dashscopeChatModel(DashScopeConnectionProperties commo var dashscopeApi = dashscopeChatApi(commonProperties, chatProperties, restClientBuilder, webClientBuilder, responseErrorHandler); - return new DashScopeChatModel(dashscopeApi, chatProperties.getOptions(), functionCallbackContext, - retryTemplate, observationRegistry.getIfUnique(() -> ObservationRegistry.NOOP)); + return new DashScopeChatModel(dashscopeApi, chatProperties.getOptions(), functionCallbackContext, retryTemplate, + observationRegistry.getIfUnique(() -> ObservationRegistry.NOOP)); } @Bean From 7b70cfd01144b63357d1f8c261bf9968c7ee8b61 Mon Sep 17 00:00:00 2001 From: cirilla-zmh Date: Tue, 3 Dec 2024 19:32:45 +0800 Subject: [PATCH 4/7] example: get trace id with OTel API --- .../observability-example/compose.yaml | 2 +- .../ai/example/observability/ObservabilityApplication.java | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/spring-ai-alibaba-examples/observability-example/compose.yaml b/spring-ai-alibaba-examples/observability-example/compose.yaml index ff23f8a8..83acbf14 100644 --- a/spring-ai-alibaba-examples/observability-example/compose.yaml +++ b/spring-ai-alibaba-examples/observability-example/compose.yaml @@ -1,5 +1,5 @@ services: zipkin: - image: 'openzipkin/zipkin:latest' + image: 'openzipkin/zipkin:3.4' ports: - '9411:9411' diff --git a/spring-ai-alibaba-examples/observability-example/src/main/java/com/alibaba/cloud/ai/example/observability/ObservabilityApplication.java b/spring-ai-alibaba-examples/observability-example/src/main/java/com/alibaba/cloud/ai/example/observability/ObservabilityApplication.java index cb77e14e..72ba0720 100644 --- a/spring-ai-alibaba-examples/observability-example/src/main/java/com/alibaba/cloud/ai/example/observability/ObservabilityApplication.java +++ b/spring-ai-alibaba-examples/observability-example/src/main/java/com/alibaba/cloud/ai/example/observability/ObservabilityApplication.java @@ -1,5 +1,8 @@ package com.alibaba.cloud.ai.example.observability; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanContext; +import io.opentelemetry.context.Context; import org.springframework.ai.chat.client.ChatClient; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @@ -42,7 +45,7 @@ Map joke() { """) .call() .content(); - - return Map.of("joke", reply); + Span currentSpan = Span.current(); + return Map.of("joke", reply, "traceId", currentSpan.getSpanContext().getTraceId()); } } From 6bba88f7736405ed38e3581089f242afec18c35c Mon Sep 17 00:00:00 2001 From: cirilla-zmh Date: Tue, 3 Dec 2024 19:37:45 +0800 Subject: [PATCH 5/7] restore docker compose.yaml --- spring-ai-alibaba-examples/observability-example/compose.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-ai-alibaba-examples/observability-example/compose.yaml b/spring-ai-alibaba-examples/observability-example/compose.yaml index 83acbf14..ff23f8a8 100644 --- a/spring-ai-alibaba-examples/observability-example/compose.yaml +++ b/spring-ai-alibaba-examples/observability-example/compose.yaml @@ -1,5 +1,5 @@ services: zipkin: - image: 'openzipkin/zipkin:3.4' + image: 'openzipkin/zipkin:latest' ports: - '9411:9411' From ac8441e41e24a0a82abc7508a7cc7cb257a6204e Mon Sep 17 00:00:00 2001 From: cirilla-zmh Date: Tue, 3 Dec 2024 19:41:38 +0800 Subject: [PATCH 6/7] example: records all of inputs & outputs in span --- .../src/main/resources/application.properties | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/spring-ai-alibaba-examples/observability-example/src/main/resources/application.properties b/spring-ai-alibaba-examples/observability-example/src/main/resources/application.properties index 831c6e3f..0acb222a 100644 --- a/spring-ai-alibaba-examples/observability-example/src/main/resources/application.properties +++ b/spring-ai-alibaba-examples/observability-example/src/main/resources/application.properties @@ -9,5 +9,11 @@ management.tracing.sampling.probability=1.0 # spring.threads.virtual.enabled=true +spring.ai.chat.client.observations.include-input=true +spring.ai.chat.observations.include-completion=true +spring.ai.chat.observations.include-prompt=true +spring.ai.image.observations.include-prompt=true +spring.ai.vectorstore.observations.include-query-response=true + # #spring.docker.compose.lifecycle-management=start_only \ No newline at end of file From 16662e566174098ff799212c89a4a42df44e8095 Mon Sep 17 00:00:00 2001 From: cirilla-zmh Date: Wed, 4 Dec 2024 10:12:27 +0800 Subject: [PATCH 7/7] example: customize the implementation of dashscope chat model --- .gitignore | 1 + .../ObservabilityApplication.java | 28 +++++++++++++++++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 0c0c62ac..1ff95012 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ target/ ### IntelliJ IDEA ### .idea/* +**/.idea/* .idea/modules.xml .idea/jarRepositories.xml .idea/compiler.xml diff --git a/spring-ai-alibaba-examples/observability-example/src/main/java/com/alibaba/cloud/ai/example/observability/ObservabilityApplication.java b/spring-ai-alibaba-examples/observability-example/src/main/java/com/alibaba/cloud/ai/example/observability/ObservabilityApplication.java index 72ba0720..9f49f676 100644 --- a/spring-ai-alibaba-examples/observability-example/src/main/java/com/alibaba/cloud/ai/example/observability/ObservabilityApplication.java +++ b/spring-ai-alibaba-examples/observability-example/src/main/java/com/alibaba/cloud/ai/example/observability/ObservabilityApplication.java @@ -1,16 +1,25 @@ package com.alibaba.cloud.ai.example.observability; +import com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeChatProperties; +import com.alibaba.cloud.ai.dashscope.api.DashScopeApi; +import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatModel; +import io.micrometer.observation.ObservationRegistry; import io.opentelemetry.api.trace.Span; -import io.opentelemetry.api.trace.SpanContext; -import io.opentelemetry.context.Context; import org.springframework.ai.chat.client.ChatClient; +import org.springframework.ai.model.function.FunctionCallback; +import org.springframework.ai.model.function.FunctionCallbackContext; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; +import org.springframework.retry.support.RetryTemplate; import org.springframework.stereotype.Controller; +import org.springframework.util.CollectionUtils; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ResponseBody; +import java.util.List; import java.util.Map; @SpringBootApplication @@ -24,6 +33,21 @@ public static void main(String[] args) { ChatClient chatClient(ChatClient.Builder builder) { return builder.build(); } + + @Bean + @ConditionalOnProperty(prefix = DashScopeChatProperties.CONFIG_PREFIX, name = "enabled", havingValue = "true", + matchIfMissing = true) + public DashScopeChatModel dashscopeChatModel(DashScopeChatProperties chatProperties, List toolFunctionCallbacks, + FunctionCallbackContext functionCallbackContext, RetryTemplate retryTemplate, + ObjectProvider observationRegistry, DashScopeApi dashScopeApi) { + + if (!CollectionUtils.isEmpty(toolFunctionCallbacks)) { + chatProperties.getOptions().getFunctionCallbacks().addAll(toolFunctionCallbacks); + } + + return new DashScopeChatModel(dashScopeApi, chatProperties.getOptions(), functionCallbackContext, retryTemplate, + observationRegistry.getIfUnique(() -> ObservationRegistry.NOOP)); + } } @Controller