From 75d68662ae24d2e480291f587b9d02a273166958 Mon Sep 17 00:00:00 2001 From: luocq3 Date: Thu, 20 Jun 2024 18:24:59 +0800 Subject: [PATCH] Change the Prompt's modelOptions() to return ChatOptions instead of ModelOptions. --- .../ai/anthropic/AnthropicChatModel.java | 24 +++++-------- .../ai/anthropic/AnthropicChatOptions.java | 6 ++++ .../ai/anthropic/AnthropicChatModelIT.java | 9 +++-- .../ai/azure/openai/AzureOpenAiChatModel.java | 34 +++++++------------ .../anthropic/BedrockAnthropicChatModel.java | 12 ++----- .../BedrockAnthropic3ChatModel.java | 12 ++----- .../cohere/BedrockCohereChatModel.java | 12 ++----- .../BedrockAi21Jurassic2ChatModel.java | 12 ++----- .../bedrock/llama/BedrockLlamaChatModel.java | 12 ++----- .../bedrock/titan/BedrockTitanChatModel.java | 12 ++----- .../ai/minimax/MiniMaxChatModel.java | 18 ++++------ .../ai/mistralai/MistralAiChatModel.java | 25 +++++--------- .../ai/ollama/OllamaChatModel.java | 14 +++----- .../ai/openai/OpenAiChatModel.java | 23 +++++-------- .../TransformersEmbeddingModelTests.java | 2 +- .../gemini/VertexAiGeminiChatModel.java | 22 +++++------- .../palm2/VertexAiPaLm2ChatModel.java | 12 ++----- .../ai/watsonx/WatsonxAiChatModel.java | 8 ++--- .../ai/zhipuai/ZhiPuAiChatModel.java | 20 ++++------- .../ai/chat/prompt/Prompt.java | 7 ++-- 20 files changed, 104 insertions(+), 192 deletions(-) diff --git a/models/spring-ai-anthropic/src/main/java/org/springframework/ai/anthropic/AnthropicChatModel.java b/models/spring-ai-anthropic/src/main/java/org/springframework/ai/anthropic/AnthropicChatModel.java index f4336d938..a9f02fb86 100644 --- a/models/spring-ai-anthropic/src/main/java/org/springframework/ai/anthropic/AnthropicChatModel.java +++ b/models/spring-ai-anthropic/src/main/java/org/springframework/ai/anthropic/AnthropicChatModel.java @@ -41,7 +41,6 @@ import org.springframework.ai.anthropic.api.AnthropicApi.Usage; import org.springframework.ai.anthropic.metadata.AnthropicChatResponseMetadata; import org.springframework.ai.chat.model.ChatResponse; import org.springframework.ai.chat.model.Generation; -import org.springframework.ai.chat.model.StreamingChatModel; import org.springframework.ai.chat.messages.MessageType; import org.springframework.ai.chat.metadata.ChatGenerationMetadata; import org.springframework.ai.chat.prompt.ChatOptions; @@ -59,11 +58,12 @@ import org.springframework.util.CollectionUtils; * The {@link ChatModel} implementation for the Anthropic service. * * @author Christian Tzolov + * @author luocongqiu * @since 1.0.0 */ public class AnthropicChatModel extends AbstractFunctionCallSupport> - implements ChatModel, StreamingChatModel { + implements ChatModel { private static final Logger logger = LoggerFactory.getLogger(AnthropicChatModel.class); @@ -81,7 +81,7 @@ public class AnthropicChatModel extends /** * The default options used for the chat completion requests. */ - private AnthropicChatOptions defaultOptions; + private final AnthropicChatOptions defaultOptions; /** * The retry template used to retry the OpenAI API calls. @@ -280,20 +280,14 @@ public class AnthropicChatModel extends systemPrompt, this.defaultOptions.getMaxTokens(), this.defaultOptions.getTemperature(), stream); if (prompt.getOptions() != null) { - if (prompt.getOptions() instanceof ChatOptions runtimeOptions) { - AnthropicChatOptions updatedRuntimeOptions = ModelOptionsUtils.copyToTarget(runtimeOptions, - ChatOptions.class, AnthropicChatOptions.class); + AnthropicChatOptions updatedRuntimeOptions = ModelOptionsUtils.copyToTarget(prompt.getOptions(), + ChatOptions.class, AnthropicChatOptions.class); - Set promptEnabledFunctions = this.handleFunctionCallbackConfigurations(updatedRuntimeOptions, - IS_RUNTIME_CALL); - functionsForThisRequest.addAll(promptEnabledFunctions); + Set promptEnabledFunctions = this.handleFunctionCallbackConfigurations(updatedRuntimeOptions, + IS_RUNTIME_CALL); + functionsForThisRequest.addAll(promptEnabledFunctions); - request = ModelOptionsUtils.merge(updatedRuntimeOptions, request, ChatCompletionRequest.class); - } - else { - throw new IllegalArgumentException("Prompt options are not of type ChatOptions: " - + prompt.getOptions().getClass().getSimpleName()); - } + request = ModelOptionsUtils.merge(updatedRuntimeOptions, request, ChatCompletionRequest.class); } if (this.defaultOptions != null) { diff --git a/models/spring-ai-anthropic/src/main/java/org/springframework/ai/anthropic/AnthropicChatOptions.java b/models/spring-ai-anthropic/src/main/java/org/springframework/ai/anthropic/AnthropicChatOptions.java index 6d13f6bae..f971b75d9 100644 --- a/models/spring-ai-anthropic/src/main/java/org/springframework/ai/anthropic/AnthropicChatOptions.java +++ b/models/spring-ai-anthropic/src/main/java/org/springframework/ai/anthropic/AnthropicChatOptions.java @@ -25,6 +25,7 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.annotation.JsonProperty; +import org.springframework.ai.anthropic.api.AnthropicApi; import org.springframework.ai.anthropic.api.AnthropicApi.ChatCompletionRequest; import org.springframework.ai.chat.prompt.ChatOptions; import org.springframework.ai.model.function.FunctionCallback; @@ -90,6 +91,11 @@ public class AnthropicChatOptions implements ChatOptions, FunctionCallingOptions return this; } + public Builder withModel(AnthropicApi.ChatModel model) { + this.options.model = model.getValue(); + return this; + } + public Builder withMaxTokens(Integer maxTokens) { this.options.maxTokens = maxTokens; return this; diff --git a/models/spring-ai-anthropic/src/test/java/org/springframework/ai/anthropic/AnthropicChatModelIT.java b/models/spring-ai-anthropic/src/test/java/org/springframework/ai/anthropic/AnthropicChatModelIT.java index affedc656..c62b3c2b6 100644 --- a/models/spring-ai-anthropic/src/test/java/org/springframework/ai/anthropic/AnthropicChatModelIT.java +++ b/models/spring-ai-anthropic/src/test/java/org/springframework/ai/anthropic/AnthropicChatModelIT.java @@ -202,10 +202,11 @@ class AnthropicChatModelIT { List messages = new ArrayList<>(List.of(userMessage)); var promptOptions = AnthropicChatOptions.builder() - .withModel(AnthropicApi.ChatModel.CLAUDE_3_OPUS.getValue()) + .withModel(AnthropicApi.ChatModel.CLAUDE_3_OPUS) .withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService()) .withName("getCurrentWeather") - .withDescription("Get the weather in location. Return temperature in 36°F or 36°C format.") + .withDescription( + "Get the weather in location. Return temperature in 36°F or 36°C format. Use multi-turn if needed.") .build())) .build(); @@ -214,9 +215,7 @@ class AnthropicChatModelIT { logger.info("Response: {}", response); Generation generation = response.getResult(); - assertThat(generation.getOutput().getContent()).containsAnyOf("30.0", "30"); - assertThat(generation.getOutput().getContent()).containsAnyOf("10.0", "10"); - assertThat(generation.getOutput().getContent()).containsAnyOf("15.0", "15"); + assertThat(generation.getOutput().getContent()).contains("30", "10", "15"); } } \ No newline at end of file diff --git a/models/spring-ai-azure-openai/src/main/java/org/springframework/ai/azure/openai/AzureOpenAiChatModel.java b/models/spring-ai-azure-openai/src/main/java/org/springframework/ai/azure/openai/AzureOpenAiChatModel.java index b7e4535aa..b88345848 100644 --- a/models/spring-ai-azure-openai/src/main/java/org/springframework/ai/azure/openai/AzureOpenAiChatModel.java +++ b/models/spring-ai-azure-openai/src/main/java/org/springframework/ai/azure/openai/AzureOpenAiChatModel.java @@ -51,7 +51,6 @@ import org.springframework.ai.chat.metadata.PromptMetadata.PromptFilterMetadata; import org.springframework.ai.chat.model.ChatModel; import org.springframework.ai.chat.model.ChatResponse; import org.springframework.ai.chat.model.Generation; -import org.springframework.ai.chat.model.StreamingChatModel; import org.springframework.ai.chat.prompt.ChatOptions; import org.springframework.ai.chat.prompt.Prompt; import org.springframework.ai.model.ModelOptionsUtils; @@ -79,12 +78,12 @@ import java.util.concurrent.atomic.AtomicBoolean; * @author Christian Tzolov * @author Grogdunn * @author Benoit Moussaud + * @author luocongqiu * @see ChatModel * @see com.azure.ai.openai.OpenAIClient */ -public class AzureOpenAiChatModel - extends AbstractFunctionCallSupport - implements ChatModel, StreamingChatModel { +public class AzureOpenAiChatModel extends + AbstractFunctionCallSupport implements ChatModel { private static final String DEFAULT_DEPLOYMENT_NAME = "gpt-35-turbo"; @@ -233,24 +232,17 @@ public class AzureOpenAiChatModel } if (prompt.getOptions() != null) { - if (prompt.getOptions() instanceof ChatOptions runtimeOptions) { - AzureOpenAiChatOptions updatedRuntimeOptions = ModelOptionsUtils.copyToTarget(runtimeOptions, - ChatOptions.class, AzureOpenAiChatOptions.class); - // JSON merge doesn't due to Azure OpenAI service bug: - // https://github.com/Azure/azure-sdk-for-java/issues/38183 - // options = ModelOptionsUtils.merge(runtimeOptions, options, - // ChatCompletionsOptions.class); - options = merge(updatedRuntimeOptions, options); + AzureOpenAiChatOptions updatedRuntimeOptions = ModelOptionsUtils.copyToTarget(prompt.getOptions(), + ChatOptions.class, AzureOpenAiChatOptions.class); + // JSON merge doesn't due to Azure OpenAI service bug: + // https://github.com/Azure/azure-sdk-for-java/issues/38183 + // options = ModelOptionsUtils.merge(runtimeOptions, options, + // ChatCompletionsOptions.class); + options = merge(updatedRuntimeOptions, options); - Set promptEnabledFunctions = this.handleFunctionCallbackConfigurations(updatedRuntimeOptions, - IS_RUNTIME_CALL); - functionsForThisRequest.addAll(promptEnabledFunctions); - - } - else { - throw new IllegalArgumentException("Prompt options are not of type ChatCompletionsOptions:" - + prompt.getOptions().getClass().getSimpleName()); - } + Set promptEnabledFunctions = this.handleFunctionCallbackConfigurations(updatedRuntimeOptions, + IS_RUNTIME_CALL); + functionsForThisRequest.addAll(promptEnabledFunctions); } // Add the enabled functions definitions to the request's tools parameter. diff --git a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic/BedrockAnthropicChatModel.java b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic/BedrockAnthropicChatModel.java index 9ea5af4f8..d6a44d9bf 100644 --- a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic/BedrockAnthropicChatModel.java +++ b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic/BedrockAnthropicChatModel.java @@ -103,15 +103,9 @@ public class BedrockAnthropicChatModel implements ChatModel, StreamingChatModel } if (prompt.getOptions() != null) { - if (prompt.getOptions() instanceof ChatOptions runtimeOptions) { - AnthropicChatOptions updatedRuntimeOptions = ModelOptionsUtils.copyToTarget(runtimeOptions, - ChatOptions.class, AnthropicChatOptions.class); - request = ModelOptionsUtils.merge(updatedRuntimeOptions, request, AnthropicChatRequest.class); - } - else { - throw new IllegalArgumentException("Prompt options are not of type ChatOptions: " - + prompt.getOptions().getClass().getSimpleName()); - } + AnthropicChatOptions updatedRuntimeOptions = ModelOptionsUtils.copyToTarget(prompt.getOptions(), + ChatOptions.class, AnthropicChatOptions.class); + request = ModelOptionsUtils.merge(updatedRuntimeOptions, request, AnthropicChatRequest.class); } return request; diff --git a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic3/BedrockAnthropic3ChatModel.java b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic3/BedrockAnthropic3ChatModel.java index e84ad2520..0b42d4266 100644 --- a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic3/BedrockAnthropic3ChatModel.java +++ b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic3/BedrockAnthropic3ChatModel.java @@ -122,15 +122,9 @@ public class BedrockAnthropic3ChatModel implements ChatModel, StreamingChatModel } if (prompt.getOptions() != null) { - if (prompt.getOptions() instanceof ChatOptions runtimeOptions) { - Anthropic3ChatOptions updatedRuntimeOptions = ModelOptionsUtils.copyToTarget(runtimeOptions, - ChatOptions.class, Anthropic3ChatOptions.class); - request = ModelOptionsUtils.merge(updatedRuntimeOptions, request, AnthropicChatRequest.class); - } - else { - throw new IllegalArgumentException("Prompt options are not of type ChatOptions: " - + prompt.getOptions().getClass().getSimpleName()); - } + Anthropic3ChatOptions updatedRuntimeOptions = ModelOptionsUtils.copyToTarget(prompt.getOptions(), + ChatOptions.class, Anthropic3ChatOptions.class); + request = ModelOptionsUtils.merge(updatedRuntimeOptions, request, AnthropicChatRequest.class); } return request; diff --git a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/cohere/BedrockCohereChatModel.java b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/cohere/BedrockCohereChatModel.java index 5c4be40b8..e9895fc1d 100644 --- a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/cohere/BedrockCohereChatModel.java +++ b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/cohere/BedrockCohereChatModel.java @@ -100,15 +100,9 @@ public class BedrockCohereChatModel implements ChatModel, StreamingChatModel { .build(); if (prompt.getOptions() != null) { - if (prompt.getOptions() instanceof ChatOptions runtimeOptions) { - BedrockCohereChatOptions updatedRuntimeOptions = ModelOptionsUtils.copyToTarget(runtimeOptions, - ChatOptions.class, BedrockCohereChatOptions.class); - request = ModelOptionsUtils.merge(updatedRuntimeOptions, request, CohereChatRequest.class); - } - else { - throw new IllegalArgumentException("Prompt options are not of type ChatOptions: " - + prompt.getOptions().getClass().getSimpleName()); - } + BedrockCohereChatOptions updatedRuntimeOptions = ModelOptionsUtils.copyToTarget(prompt.getOptions(), + ChatOptions.class, BedrockCohereChatOptions.class); + request = ModelOptionsUtils.merge(updatedRuntimeOptions, request, CohereChatRequest.class); } return request; diff --git a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/jurassic2/BedrockAi21Jurassic2ChatModel.java b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/jurassic2/BedrockAi21Jurassic2ChatModel.java index 13518fd51..b6f9d6cbc 100644 --- a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/jurassic2/BedrockAi21Jurassic2ChatModel.java +++ b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/jurassic2/BedrockAi21Jurassic2ChatModel.java @@ -76,15 +76,9 @@ public class BedrockAi21Jurassic2ChatModel implements ChatModel { Ai21Jurassic2ChatRequest request = Ai21Jurassic2ChatRequest.builder(promptValue).build(); if (prompt.getOptions() != null) { - if (prompt.getOptions() instanceof ChatOptions runtimeOptions) { - BedrockAi21Jurassic2ChatOptions updatedRuntimeOptions = ModelOptionsUtils.copyToTarget(runtimeOptions, - ChatOptions.class, BedrockAi21Jurassic2ChatOptions.class); - request = ModelOptionsUtils.merge(updatedRuntimeOptions, request, Ai21Jurassic2ChatRequest.class); - } - else { - throw new IllegalArgumentException("Prompt options are not of type ChatOptions: " - + prompt.getOptions().getClass().getSimpleName()); - } + BedrockAi21Jurassic2ChatOptions updatedRuntimeOptions = ModelOptionsUtils.copyToTarget(prompt.getOptions(), + ChatOptions.class, BedrockAi21Jurassic2ChatOptions.class); + request = ModelOptionsUtils.merge(updatedRuntimeOptions, request, Ai21Jurassic2ChatRequest.class); } if (this.defaultOptions != null) { diff --git a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/llama/BedrockLlamaChatModel.java b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/llama/BedrockLlamaChatModel.java index ab9f5c7b7..b39176322 100644 --- a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/llama/BedrockLlamaChatModel.java +++ b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/llama/BedrockLlamaChatModel.java @@ -115,16 +115,10 @@ public class BedrockLlamaChatModel implements ChatModel, StreamingChatModel { } if (prompt.getOptions() != null) { - if (prompt.getOptions() instanceof ChatOptions runtimeOptions) { - BedrockLlamaChatOptions updatedRuntimeOptions = ModelOptionsUtils.copyToTarget(runtimeOptions, - ChatOptions.class, BedrockLlamaChatOptions.class); + BedrockLlamaChatOptions updatedRuntimeOptions = ModelOptionsUtils.copyToTarget(prompt.getOptions(), + ChatOptions.class, BedrockLlamaChatOptions.class); - request = ModelOptionsUtils.merge(updatedRuntimeOptions, request, LlamaChatRequest.class); - } - else { - throw new IllegalArgumentException("Prompt options are not of type ChatOptions: " - + prompt.getOptions().getClass().getSimpleName()); - } + request = ModelOptionsUtils.merge(updatedRuntimeOptions, request, LlamaChatRequest.class); } return request; diff --git a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/titan/BedrockTitanChatModel.java b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/titan/BedrockTitanChatModel.java index 77b91e09f..b144a2a10 100644 --- a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/titan/BedrockTitanChatModel.java +++ b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/titan/BedrockTitanChatModel.java @@ -100,16 +100,10 @@ public class BedrockTitanChatModel implements ChatModel, StreamingChatModel { } if (prompt.getOptions() != null) { - if (prompt.getOptions() instanceof ChatOptions runtimeOptions) { - BedrockTitanChatOptions updatedRuntimeOptions = ModelOptionsUtils.copyToTarget(runtimeOptions, - ChatOptions.class, BedrockTitanChatOptions.class); + BedrockTitanChatOptions updatedRuntimeOptions = ModelOptionsUtils.copyToTarget(prompt.getOptions(), + ChatOptions.class, BedrockTitanChatOptions.class); - requestBuilder = update(requestBuilder, updatedRuntimeOptions); - } - else { - throw new IllegalArgumentException("Prompt options are not of type ChatOptions: " - + prompt.getOptions().getClass().getSimpleName()); - } + requestBuilder = update(requestBuilder, updatedRuntimeOptions); } return requestBuilder.build(); diff --git a/models/spring-ai-minimax/src/main/java/org/springframework/ai/minimax/MiniMaxChatModel.java b/models/spring-ai-minimax/src/main/java/org/springframework/ai/minimax/MiniMaxChatModel.java index 48101b6f9..b884584f4 100644 --- a/models/spring-ai-minimax/src/main/java/org/springframework/ai/minimax/MiniMaxChatModel.java +++ b/models/spring-ai-minimax/src/main/java/org/springframework/ai/minimax/MiniMaxChatModel.java @@ -246,20 +246,14 @@ public class MiniMaxChatModel extends ChatCompletionRequest request = new ChatCompletionRequest(chatCompletionMessages, stream); if (prompt.getOptions() != null) { - if (prompt.getOptions() instanceof ChatOptions runtimeOptions) { - MiniMaxChatOptions updatedRuntimeOptions = ModelOptionsUtils.copyToTarget(runtimeOptions, - ChatOptions.class, MiniMaxChatOptions.class); + MiniMaxChatOptions updatedRuntimeOptions = ModelOptionsUtils.copyToTarget(prompt.getOptions(), + ChatOptions.class, MiniMaxChatOptions.class); - Set promptEnabledFunctions = this.handleFunctionCallbackConfigurations(updatedRuntimeOptions, - IS_RUNTIME_CALL); - functionsForThisRequest.addAll(promptEnabledFunctions); + Set promptEnabledFunctions = this.handleFunctionCallbackConfigurations(updatedRuntimeOptions, + IS_RUNTIME_CALL); + functionsForThisRequest.addAll(promptEnabledFunctions); - request = ModelOptionsUtils.merge(updatedRuntimeOptions, request, ChatCompletionRequest.class); - } - else { - throw new IllegalArgumentException("Prompt options are not of type ChatOptions: " - + prompt.getOptions().getClass().getSimpleName()); - } + request = ModelOptionsUtils.merge(updatedRuntimeOptions, request, ChatCompletionRequest.class); } if (this.defaultOptions != null) { diff --git a/models/spring-ai-mistral-ai/src/main/java/org/springframework/ai/mistralai/MistralAiChatModel.java b/models/spring-ai-mistral-ai/src/main/java/org/springframework/ai/mistralai/MistralAiChatModel.java index 6447d7ed3..734056900 100644 --- a/models/spring-ai-mistral-ai/src/main/java/org/springframework/ai/mistralai/MistralAiChatModel.java +++ b/models/spring-ai-mistral-ai/src/main/java/org/springframework/ai/mistralai/MistralAiChatModel.java @@ -20,7 +20,6 @@ import org.slf4j.LoggerFactory; import org.springframework.ai.chat.model.ChatModel; import org.springframework.ai.chat.model.ChatResponse; import org.springframework.ai.chat.model.Generation; -import org.springframework.ai.chat.model.StreamingChatModel; import org.springframework.ai.chat.metadata.ChatGenerationMetadata; import org.springframework.ai.chat.prompt.ChatOptions; import org.springframework.ai.chat.prompt.Prompt; @@ -54,18 +53,19 @@ import java.util.concurrent.ConcurrentHashMap; * @author Christian Tzolov * @author Grogdunn * @author Thomas Vitale + * @author luocongqiu * @since 0.8.1 */ public class MistralAiChatModel extends AbstractFunctionCallSupport> - implements ChatModel, StreamingChatModel { + implements ChatModel { private final Logger log = LoggerFactory.getLogger(getClass()); /** * The default options used for the chat completion requests. */ - private MistralAiChatOptions defaultOptions; + private final MistralAiChatOptions defaultOptions; /** * Low-level access to the OpenAI API. @@ -209,21 +209,14 @@ public class MistralAiChatModel extends } if (prompt.getOptions() != null) { - if (prompt.getOptions() instanceof ChatOptions runtimeOptions) { - var updatedRuntimeOptions = ModelOptionsUtils.copyToTarget(runtimeOptions, ChatOptions.class, - MistralAiChatOptions.class); + var updatedRuntimeOptions = ModelOptionsUtils.copyToTarget(prompt.getOptions(), ChatOptions.class, + MistralAiChatOptions.class); - Set promptEnabledFunctions = this.handleFunctionCallbackConfigurations(updatedRuntimeOptions, - IS_RUNTIME_CALL); - functionsForThisRequest.addAll(promptEnabledFunctions); + Set promptEnabledFunctions = this.handleFunctionCallbackConfigurations(updatedRuntimeOptions, + IS_RUNTIME_CALL); + functionsForThisRequest.addAll(promptEnabledFunctions); - request = ModelOptionsUtils.merge(updatedRuntimeOptions, request, - MistralAiApi.ChatCompletionRequest.class); - } - else { - throw new IllegalArgumentException("Prompt options are not of type ChatOptions: " - + prompt.getOptions().getClass().getSimpleName()); - } + request = ModelOptionsUtils.merge(updatedRuntimeOptions, request, MistralAiApi.ChatCompletionRequest.class); } // Add the enabled functions definitions to the request's tools parameter. diff --git a/models/spring-ai-ollama/src/main/java/org/springframework/ai/ollama/OllamaChatModel.java b/models/spring-ai-ollama/src/main/java/org/springframework/ai/ollama/OllamaChatModel.java index d3adb17b4..39405c2d6 100644 --- a/models/spring-ai-ollama/src/main/java/org/springframework/ai/ollama/OllamaChatModel.java +++ b/models/spring-ai-ollama/src/main/java/org/springframework/ai/ollama/OllamaChatModel.java @@ -24,7 +24,6 @@ import reactor.core.publisher.Flux; import org.springframework.ai.chat.model.ChatResponse; import org.springframework.ai.chat.model.Generation; -import org.springframework.ai.chat.model.StreamingChatModel; import org.springframework.ai.chat.messages.Message; import org.springframework.ai.chat.messages.MessageType; import org.springframework.ai.chat.metadata.ChatGenerationMetadata; @@ -50,9 +49,10 @@ import org.springframework.util.StringUtils; * most up-to-date information on available models. * * @author Christian Tzolov + * @author luocongqiu * @since 0.8.0 */ -public class OllamaChatModel implements ChatModel, StreamingChatModel { +public class OllamaChatModel implements ChatModel { /** * Low-level Ollama API library. @@ -144,14 +144,8 @@ public class OllamaChatModel implements ChatModel, StreamingChatModel { // runtime options OllamaOptions runtimeOptions = null; if (prompt.getOptions() != null) { - if (prompt.getOptions() instanceof ChatOptions runtimeChatOptions) { - runtimeOptions = ModelOptionsUtils.copyToTarget(runtimeChatOptions, ChatOptions.class, - OllamaOptions.class); - } - else { - throw new IllegalArgumentException("Prompt options are not of type ChatOptions: " - + prompt.getOptions().getClass().getSimpleName()); - } + runtimeOptions = ModelOptionsUtils.copyToTarget(prompt.getOptions(), ChatOptions.class, + OllamaOptions.class); } OllamaOptions mergedOptions = ModelOptionsUtils.merge(runtimeOptions, this.defaultOptions, OllamaOptions.class); diff --git a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiChatModel.java b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiChatModel.java index 4d807816d..a2bc84b65 100644 --- a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiChatModel.java +++ b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiChatModel.java @@ -71,20 +71,21 @@ import reactor.core.publisher.Flux; * @author Grogdunn * @author Hyunjoon Choi * @author Mariusz Bernacki + * @author luocongqiu * @see ChatModel * @see StreamingChatModel * @see OpenAiApi */ public class OpenAiChatModel extends AbstractFunctionCallSupport> - implements ChatModel, StreamingChatModel { + implements ChatModel { private static final Logger logger = LoggerFactory.getLogger(OpenAiChatModel.class); /** * The default options used for the chat completion requests. */ - private OpenAiChatOptions defaultOptions; + private final OpenAiChatOptions defaultOptions; /** * The retry template used to retry the OpenAI API calls. @@ -277,20 +278,14 @@ public class OpenAiChatModel extends ChatCompletionRequest request = new ChatCompletionRequest(chatCompletionMessages, stream); if (prompt.getOptions() != null) { - if (prompt.getOptions() instanceof ChatOptions runtimeOptions) { - OpenAiChatOptions updatedRuntimeOptions = ModelOptionsUtils.copyToTarget(runtimeOptions, - ChatOptions.class, OpenAiChatOptions.class); + OpenAiChatOptions updatedRuntimeOptions = ModelOptionsUtils.copyToTarget(prompt.getOptions(), + ChatOptions.class, OpenAiChatOptions.class); - Set promptEnabledFunctions = this.handleFunctionCallbackConfigurations(updatedRuntimeOptions, - IS_RUNTIME_CALL); - functionsForThisRequest.addAll(promptEnabledFunctions); + Set promptEnabledFunctions = this.handleFunctionCallbackConfigurations(updatedRuntimeOptions, + IS_RUNTIME_CALL); + functionsForThisRequest.addAll(promptEnabledFunctions); - request = ModelOptionsUtils.merge(updatedRuntimeOptions, request, ChatCompletionRequest.class); - } - else { - throw new IllegalArgumentException("Prompt options are not of type ChatOptions: " - + prompt.getOptions().getClass().getSimpleName()); - } + request = ModelOptionsUtils.merge(updatedRuntimeOptions, request, ChatCompletionRequest.class); } if (this.defaultOptions != null) { diff --git a/models/spring-ai-transformers/src/test/java/org/springframework/ai/transformers/TransformersEmbeddingModelTests.java b/models/spring-ai-transformers/src/test/java/org/springframework/ai/transformers/TransformersEmbeddingModelTests.java index 023496eff..40f963b5d 100644 --- a/models/spring-ai-transformers/src/test/java/org/springframework/ai/transformers/TransformersEmbeddingModelTests.java +++ b/models/spring-ai-transformers/src/test/java/org/springframework/ai/transformers/TransformersEmbeddingModelTests.java @@ -30,7 +30,7 @@ import static org.assertj.core.api.Assertions.assertThat; */ public class TransformersEmbeddingModelTests { - private static DecimalFormat DF = new DecimalFormat("#.######"); + private static DecimalFormat DF = new DecimalFormat("#.#####"); @Test void embed() throws Exception { diff --git a/models/spring-ai-vertex-ai-gemini/src/main/java/org/springframework/ai/vertexai/gemini/VertexAiGeminiChatModel.java b/models/spring-ai-vertex-ai-gemini/src/main/java/org/springframework/ai/vertexai/gemini/VertexAiGeminiChatModel.java index 220439de6..a198cdcea 100644 --- a/models/spring-ai-vertex-ai-gemini/src/main/java/org/springframework/ai/vertexai/gemini/VertexAiGeminiChatModel.java +++ b/models/spring-ai-vertex-ai-gemini/src/main/java/org/springframework/ai/vertexai/gemini/VertexAiGeminiChatModel.java @@ -36,7 +36,6 @@ import com.google.protobuf.util.JsonFormat; import org.springframework.ai.chat.model.ChatModel; import org.springframework.ai.chat.model.ChatResponse; import org.springframework.ai.chat.model.Generation; -import org.springframework.ai.chat.model.StreamingChatModel; import org.springframework.ai.chat.messages.AssistantMessage; import org.springframework.ai.chat.messages.Message; import org.springframework.ai.chat.messages.MessageType; @@ -65,11 +64,12 @@ import java.util.stream.Collectors; /** * @author Christian Tzolov * @author Grogdunn + * @author luocongqiu * @since 0.8.1 */ public class VertexAiGeminiChatModel extends AbstractFunctionCallSupport - implements ChatModel, StreamingChatModel, DisposableBean { + implements ChatModel, DisposableBean { private final static boolean IS_RUNTIME_CALL = true; @@ -163,7 +163,7 @@ public class VertexAiGeminiChatModel .map(candidate -> candidate.getContent().getPartsList()) .flatMap(List::stream) .map(Part::getText) - .map(t -> new Generation(t.toString())) + .map(t -> new Generation(t)) .toList(); return new ChatResponse(generations, toChatResponseMetadata(response)); @@ -186,7 +186,7 @@ public class VertexAiGeminiChatModel .map(candidate -> candidate.getContent().getPartsList()) .flatMap(List::stream) .map(Part::getText) - .map(t -> new Generation(t.toString())) + .map(t -> new Generation(t)) .toList(); return new ChatResponse(generations, toChatResponseMetadata(response)); @@ -217,17 +217,11 @@ public class VertexAiGeminiChatModel VertexAiGeminiChatOptions updatedRuntimeOptions = null; if (prompt.getOptions() != null) { - if (prompt.getOptions() instanceof ChatOptions runtimeOptions) { - updatedRuntimeOptions = ModelOptionsUtils.copyToTarget(runtimeOptions, ChatOptions.class, - VertexAiGeminiChatOptions.class); + updatedRuntimeOptions = ModelOptionsUtils.copyToTarget(prompt.getOptions(), ChatOptions.class, + VertexAiGeminiChatOptions.class); - functionsForThisRequest - .addAll(handleFunctionCallbackConfigurations(updatedRuntimeOptions, IS_RUNTIME_CALL)); - } - else { - throw new IllegalArgumentException("Prompt options are not of type ChatOptions: " - + prompt.getOptions().getClass().getSimpleName()); - } + functionsForThisRequest + .addAll(handleFunctionCallbackConfigurations(updatedRuntimeOptions, IS_RUNTIME_CALL)); } if (this.defaultOptions != null) { diff --git a/models/spring-ai-vertex-ai-palm2/src/main/java/org/springframework/ai/vertexai/palm2/VertexAiPaLm2ChatModel.java b/models/spring-ai-vertex-ai-palm2/src/main/java/org/springframework/ai/vertexai/palm2/VertexAiPaLm2ChatModel.java index a55ebab92..db22e132f 100644 --- a/models/spring-ai-vertex-ai-palm2/src/main/java/org/springframework/ai/vertexai/palm2/VertexAiPaLm2ChatModel.java +++ b/models/spring-ai-vertex-ai-palm2/src/main/java/org/springframework/ai/vertexai/palm2/VertexAiPaLm2ChatModel.java @@ -97,15 +97,9 @@ public class VertexAiPaLm2ChatModel implements ChatModel { } if (prompt.getOptions() != null) { - if (prompt.getOptions() instanceof ChatOptions runtimeOptions) { - VertexAiPaLm2ChatOptions updatedRuntimeOptions = ModelOptionsUtils.copyToTarget(runtimeOptions, - ChatOptions.class, VertexAiPaLm2ChatOptions.class); - request = ModelOptionsUtils.merge(updatedRuntimeOptions, request, GenerateMessageRequest.class); - } - else { - throw new IllegalArgumentException("Prompt options are not of type ChatOptions: " - + prompt.getOptions().getClass().getSimpleName()); - } + VertexAiPaLm2ChatOptions updatedRuntimeOptions = ModelOptionsUtils.copyToTarget(prompt.getOptions(), + ChatOptions.class, VertexAiPaLm2ChatOptions.class); + request = ModelOptionsUtils.merge(updatedRuntimeOptions, request, GenerateMessageRequest.class); } return request; diff --git a/models/spring-ai-watsonx-ai/src/main/java/org/springframework/ai/watsonx/WatsonxAiChatModel.java b/models/spring-ai-watsonx-ai/src/main/java/org/springframework/ai/watsonx/WatsonxAiChatModel.java index 6e6d37927..91a0cda70 100644 --- a/models/spring-ai-watsonx-ai/src/main/java/org/springframework/ai/watsonx/WatsonxAiChatModel.java +++ b/models/spring-ai-watsonx-ai/src/main/java/org/springframework/ai/watsonx/WatsonxAiChatModel.java @@ -118,16 +118,12 @@ public class WatsonxAiChatModel implements ChatModel, StreamingChatModel { if (prompt.getOptions() instanceof WatsonxAiChatOptions runtimeOptions) { options = ModelOptionsUtils.merge(runtimeOptions, options, WatsonxAiChatOptions.class); } - else if (prompt.getOptions() instanceof ChatOptions runtimeOptions) { - var updatedRuntimeOptions = ModelOptionsUtils.copyToTarget(runtimeOptions, ChatOptions.class, + else { + var updatedRuntimeOptions = ModelOptionsUtils.copyToTarget(prompt.getOptions(), ChatOptions.class, WatsonxAiChatOptions.class); options = ModelOptionsUtils.merge(updatedRuntimeOptions, options, WatsonxAiChatOptions.class); } - else { - throw new IllegalArgumentException("Prompt options are not of type ChatOptions: " - + prompt.getOptions().getClass().getSimpleName()); - } } Map parameters = options.toMap(); diff --git a/models/spring-ai-zhipuai/src/main/java/org/springframework/ai/zhipuai/ZhiPuAiChatModel.java b/models/spring-ai-zhipuai/src/main/java/org/springframework/ai/zhipuai/ZhiPuAiChatModel.java index 42d94a71a..ea8b03be9 100644 --- a/models/spring-ai-zhipuai/src/main/java/org/springframework/ai/zhipuai/ZhiPuAiChatModel.java +++ b/models/spring-ai-zhipuai/src/main/java/org/springframework/ai/zhipuai/ZhiPuAiChatModel.java @@ -74,7 +74,7 @@ public class ZhiPuAiChatModel extends /** * The default options used for the chat completion requests. */ - private ZhiPuAiChatOptions defaultOptions; + private final ZhiPuAiChatOptions defaultOptions; /** * The retry template used to retry the ZhiPuAI API calls. @@ -252,20 +252,14 @@ public class ZhiPuAiChatModel extends ChatCompletionRequest request = new ChatCompletionRequest(chatCompletionMessages, stream); if (prompt.getOptions() != null) { - if (prompt.getOptions() instanceof ChatOptions runtimeOptions) { - ZhiPuAiChatOptions updatedRuntimeOptions = ModelOptionsUtils.copyToTarget(runtimeOptions, - ChatOptions.class, ZhiPuAiChatOptions.class); + ZhiPuAiChatOptions updatedRuntimeOptions = ModelOptionsUtils.copyToTarget(prompt.getOptions(), + ChatOptions.class, ZhiPuAiChatOptions.class); - Set promptEnabledFunctions = this.handleFunctionCallbackConfigurations(updatedRuntimeOptions, - IS_RUNTIME_CALL); - functionsForThisRequest.addAll(promptEnabledFunctions); + Set promptEnabledFunctions = this.handleFunctionCallbackConfigurations(updatedRuntimeOptions, + IS_RUNTIME_CALL); + functionsForThisRequest.addAll(promptEnabledFunctions); - request = ModelOptionsUtils.merge(updatedRuntimeOptions, request, ChatCompletionRequest.class); - } - else { - throw new IllegalArgumentException("Prompt options are not of type ChatOptions: " - + prompt.getOptions().getClass().getSimpleName()); - } + request = ModelOptionsUtils.merge(updatedRuntimeOptions, request, ChatCompletionRequest.class); } if (this.defaultOptions != null) { diff --git a/spring-ai-core/src/main/java/org/springframework/ai/chat/prompt/Prompt.java b/spring-ai-core/src/main/java/org/springframework/ai/chat/prompt/Prompt.java index 1e4b97ed7..caf627e18 100644 --- a/spring-ai-core/src/main/java/org/springframework/ai/chat/prompt/Prompt.java +++ b/spring-ai-core/src/main/java/org/springframework/ai/chat/prompt/Prompt.java @@ -25,9 +25,12 @@ import org.springframework.ai.chat.messages.FunctionMessage; import org.springframework.ai.chat.messages.Message; import org.springframework.ai.chat.messages.SystemMessage; import org.springframework.ai.chat.messages.UserMessage; -import org.springframework.ai.model.ModelOptions; import org.springframework.ai.model.ModelRequest; +/** + * @author Mark Pollack + * @author luocongqiu + */ public class Prompt implements ModelRequest> { private final List messages; @@ -68,7 +71,7 @@ public class Prompt implements ModelRequest> { } @Override - public ModelOptions getOptions() { + public ChatOptions getOptions() { return this.modelOptions; }