Skip to content

Commit 49e1dd1

Browse files
committed
Refactor toolcalling support for Minimax
- Update Minimax Chat Model to use ToolCalling Manager and ToolExecutionEligibilityPredicate - Update Minimax ChatOptions to implement ToolCallingChatOptions - Update Autoconfiguration for MinimaxChat model to use ToolCallingAutoconfiguration - Update tests Signed-off-by: Ilayaperumal Gopinathan <[email protected]>
1 parent 9805262 commit 49e1dd1

File tree

10 files changed

+313
-279
lines changed

10 files changed

+313
-279
lines changed

auto-configurations/models/spring-ai-autoconfigure-model-minimax/src/main/java/org/springframework/ai/model/minimax/autoconfigure/MiniMaxChatAutoConfiguration.java

+16-21
Original file line numberDiff line numberDiff line change
@@ -16,27 +16,26 @@
1616

1717
package org.springframework.ai.model.minimax.autoconfigure;
1818

19-
import java.util.List;
20-
2119
import io.micrometer.observation.ObservationRegistry;
2220

2321
import org.springframework.ai.chat.observation.ChatModelObservationConvention;
2422
import org.springframework.ai.minimax.MiniMaxChatModel;
2523
import org.springframework.ai.minimax.api.MiniMaxApi;
2624
import org.springframework.ai.model.SpringAIModelProperties;
2725
import org.springframework.ai.model.SpringAIModels;
28-
import org.springframework.ai.model.function.DefaultFunctionCallbackResolver;
29-
import org.springframework.ai.model.function.FunctionCallback;
30-
import org.springframework.ai.model.function.FunctionCallbackResolver;
26+
import org.springframework.ai.model.tool.DefaultToolExecutionEligibilityPredicate;
27+
import org.springframework.ai.model.tool.ToolCallingManager;
28+
import org.springframework.ai.model.tool.ToolExecutionEligibilityPredicate;
29+
import org.springframework.ai.model.tool.autoconfigure.ToolCallingAutoConfiguration;
3130
import org.springframework.ai.retry.autoconfigure.SpringAiRetryAutoConfiguration;
3231
import org.springframework.beans.factory.ObjectProvider;
3332
import org.springframework.boot.autoconfigure.AutoConfiguration;
33+
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
3434
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
3535
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
3636
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
3737
import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration;
3838
import org.springframework.boot.context.properties.EnableConfigurationProperties;
39-
import org.springframework.context.ApplicationContext;
4039
import org.springframework.context.annotation.Bean;
4140
import org.springframework.retry.support.RetryTemplate;
4241
import org.springframework.util.Assert;
@@ -50,28 +49,32 @@
5049
* @author Geng Rong
5150
* @author Ilayaperumal Gopinathan
5251
*/
53-
@AutoConfiguration(after = { RestClientAutoConfiguration.class, SpringAiRetryAutoConfiguration.class })
52+
@AutoConfiguration(after = { RestClientAutoConfiguration.class, SpringAiRetryAutoConfiguration.class,
53+
ToolCallingAutoConfiguration.class })
5454
@ConditionalOnClass(MiniMaxApi.class)
5555
@EnableConfigurationProperties({ MiniMaxConnectionProperties.class, MiniMaxChatProperties.class })
5656
@ConditionalOnProperty(name = SpringAIModelProperties.CHAT_MODEL, havingValue = SpringAIModels.MINIMAX,
5757
matchIfMissing = true)
58+
@ImportAutoConfiguration(classes = { SpringAiRetryAutoConfiguration.class, RestClientAutoConfiguration.class,
59+
ToolCallingAutoConfiguration.class })
5860
public class MiniMaxChatAutoConfiguration {
5961

6062
@Bean
6163
@ConditionalOnMissingBean
6264
public MiniMaxChatModel miniMaxChatModel(MiniMaxConnectionProperties commonProperties,
6365
MiniMaxChatProperties chatProperties, ObjectProvider<RestClient.Builder> restClientBuilderProvider,
64-
List<FunctionCallback> toolFunctionCallbacks, FunctionCallbackResolver functionCallbackResolver,
65-
RetryTemplate retryTemplate, ResponseErrorHandler responseErrorHandler,
66-
ObjectProvider<ObservationRegistry> observationRegistry,
67-
ObjectProvider<ChatModelObservationConvention> observationConvention) {
66+
ToolCallingManager toolCallingManager, RetryTemplate retryTemplate,
67+
ResponseErrorHandler responseErrorHandler, ObjectProvider<ObservationRegistry> observationRegistry,
68+
ObjectProvider<ChatModelObservationConvention> observationConvention,
69+
ObjectProvider<ToolExecutionEligibilityPredicate> openAiToolExecutionEligibilityPredicate) {
6870

6971
var miniMaxApi = miniMaxApi(chatProperties.getBaseUrl(), commonProperties.getBaseUrl(),
7072
chatProperties.getApiKey(), commonProperties.getApiKey(),
7173
restClientBuilderProvider.getIfAvailable(RestClient::builder), responseErrorHandler);
7274

73-
var chatModel = new MiniMaxChatModel(miniMaxApi, chatProperties.getOptions(), functionCallbackResolver,
74-
toolFunctionCallbacks, retryTemplate, observationRegistry.getIfUnique(() -> ObservationRegistry.NOOP));
75+
var chatModel = new MiniMaxChatModel(miniMaxApi, chatProperties.getOptions(), toolCallingManager, retryTemplate,
76+
observationRegistry.getIfUnique(() -> ObservationRegistry.NOOP),
77+
openAiToolExecutionEligibilityPredicate.getIfUnique(DefaultToolExecutionEligibilityPredicate::new));
7578

7679
observationConvention.ifAvailable(chatModel::setObservationConvention);
7780
return chatModel;
@@ -89,12 +92,4 @@ private MiniMaxApi miniMaxApi(String baseUrl, String commonBaseUrl, String apiKe
8992
return new MiniMaxApi(resolvedBaseUrl, resolvedApiKey, restClientBuilder, responseErrorHandler);
9093
}
9194

92-
@Bean
93-
@ConditionalOnMissingBean
94-
public FunctionCallbackResolver springAiFunctionManager(ApplicationContext context) {
95-
DefaultFunctionCallbackResolver manager = new DefaultFunctionCallbackResolver();
96-
manager.setApplicationContext(context);
97-
return manager;
98-
}
99-
10095
}

auto-configurations/models/spring-ai-autoconfigure-model-minimax/src/test/java/org/springframework/ai/model/minimax/autoconfigure/FunctionCallbackInPromptIT.java

+3-4
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import org.springframework.ai.minimax.MiniMaxChatOptions;
3535
import org.springframework.ai.model.function.FunctionCallback;
3636
import org.springframework.ai.retry.autoconfigure.SpringAiRetryAutoConfiguration;
37+
import org.springframework.ai.tool.function.FunctionToolCallback;
3738
import org.springframework.boot.autoconfigure.AutoConfigurations;
3839
import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration;
3940
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
@@ -63,8 +64,7 @@ void functionCallTest() {
6364
"What's the weather like in San Francisco, Tokyo, and Paris? Return the temperature in Celsius.");
6465

6566
var promptOptions = MiniMaxChatOptions.builder()
66-
.functionCallbacks(List.of(FunctionCallback.builder()
67-
.function("CurrentWeatherService", new MockWeatherService())
67+
.toolCallbacks(List.of(FunctionToolCallback.builder("CurrentWeatherService", new MockWeatherService())
6868
.description("Get the weather in location")
6969
.inputType(MockWeatherService.Request.class)
7070
.build()))
@@ -89,8 +89,7 @@ void streamingFunctionCallTest() {
8989
"What's the weather like in San Francisco, Tokyo, and Paris? Return the temperature in Celsius.");
9090

9191
var promptOptions = MiniMaxChatOptions.builder()
92-
.functionCallbacks(List.of(FunctionCallback.builder()
93-
.function("CurrentWeatherService", new MockWeatherService())
92+
.toolCallbacks(List.of(FunctionToolCallback.builder("CurrentWeatherService", new MockWeatherService())
9493
.description("Get the weather in location")
9594
.inputType(MockWeatherService.Request.class)
9695
.build()))

auto-configurations/models/spring-ai-autoconfigure-model-minimax/src/test/java/org/springframework/ai/model/minimax/autoconfigure/FunctionCallbackWithPlainFunctionBeanIT.java

+9-8
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import org.springframework.ai.minimax.MiniMaxChatModel;
3535
import org.springframework.ai.minimax.MiniMaxChatOptions;
3636
import org.springframework.ai.model.function.FunctionCallingOptions;
37+
import org.springframework.ai.model.tool.ToolCallingChatOptions;
3738
import org.springframework.ai.retry.autoconfigure.SpringAiRetryAutoConfiguration;
3839
import org.springframework.boot.autoconfigure.AutoConfigurations;
3940
import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration;
@@ -69,16 +70,16 @@ void functionCallTest() {
6970
UserMessage userMessage = new UserMessage(
7071
"What's the weather like in San Francisco, Tokyo, and Paris? Return the temperature in Celsius.");
7172

72-
ChatResponse response = chatModel.call(
73-
new Prompt(List.of(userMessage), MiniMaxChatOptions.builder().function("weatherFunction").build()));
73+
ChatResponse response = chatModel.call(new Prompt(List.of(userMessage),
74+
MiniMaxChatOptions.builder().toolNames("weatherFunction").build()));
7475

7576
logger.info("Response: {}", response);
7677

7778
assertThat(response.getResult().getOutput().getText()).contains("30", "10", "15");
7879

7980
// Test weatherFunctionTwo
8081
response = chatModel.call(new Prompt(List.of(userMessage),
81-
MiniMaxChatOptions.builder().function("weatherFunctionTwo").build()));
82+
MiniMaxChatOptions.builder().toolNames("weatherFunctionTwo").build()));
8283

8384
logger.info("Response: {}", response);
8485

@@ -97,8 +98,8 @@ void functionCallWithPortableFunctionCallingOptions() {
9798
UserMessage userMessage = new UserMessage(
9899
"What's the weather like in San Francisco, Tokyo, and Paris? Return the temperature in Celsius.");
99100

100-
FunctionCallingOptions functionOptions = FunctionCallingOptions.builder()
101-
.function("weatherFunction")
101+
ToolCallingChatOptions functionOptions = ToolCallingChatOptions.builder()
102+
.toolNames("weatherFunction")
102103
.build();
103104

104105
ChatResponse response = chatModel.call(new Prompt(List.of(userMessage), functionOptions));
@@ -118,8 +119,8 @@ void streamFunctionCallTest() {
118119
UserMessage userMessage = new UserMessage(
119120
"What's the weather like in San Francisco, Tokyo, and Paris? Return the temperature in Celsius.");
120121

121-
Flux<ChatResponse> response = chatModel.stream(
122-
new Prompt(List.of(userMessage), MiniMaxChatOptions.builder().function("weatherFunction").build()));
122+
Flux<ChatResponse> response = chatModel.stream(new Prompt(List.of(userMessage),
123+
MiniMaxChatOptions.builder().toolNames("weatherFunction").build()));
123124

124125
String content = response.collectList()
125126
.block()
@@ -137,7 +138,7 @@ void streamFunctionCallTest() {
137138

138139
// Test weatherFunctionTwo
139140
response = chatModel.stream(new Prompt(List.of(userMessage),
140-
MiniMaxChatOptions.builder().function("weatherFunctionTwo").build()));
141+
MiniMaxChatOptions.builder().toolNames("weatherFunctionTwo").build()));
141142

142143
content = response.collectList()
143144
.block()

auto-configurations/models/spring-ai-autoconfigure-model-minimax/src/test/java/org/springframework/ai/model/minimax/autoconfigure/MiniMaxFunctionCallbackIT.java

+10-8
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@
3333
import org.springframework.ai.minimax.MiniMaxChatModel;
3434
import org.springframework.ai.minimax.MiniMaxChatOptions;
3535
import org.springframework.ai.model.function.FunctionCallback;
36+
import org.springframework.ai.model.tool.autoconfigure.ToolCallingAutoConfiguration;
3637
import org.springframework.ai.retry.autoconfigure.SpringAiRetryAutoConfiguration;
38+
import org.springframework.ai.tool.function.FunctionToolCallback;
3739
import org.springframework.boot.autoconfigure.AutoConfigurations;
3840
import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration;
3941
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
@@ -52,8 +54,9 @@ public class MiniMaxFunctionCallbackIT {
5254

5355
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
5456
.withPropertyValues("spring.ai.minimax.apiKey=" + System.getenv("MINIMAX_API_KEY"))
55-
.withConfiguration(AutoConfigurations.of(SpringAiRetryAutoConfiguration.class,
56-
RestClientAutoConfiguration.class, MiniMaxChatAutoConfiguration.class))
57+
.withConfiguration(
58+
AutoConfigurations.of(SpringAiRetryAutoConfiguration.class, RestClientAutoConfiguration.class,
59+
MiniMaxChatAutoConfiguration.class, ToolCallingAutoConfiguration.class))
5760
.withUserConfiguration(Config.class);
5861

5962
@Test
@@ -66,7 +69,7 @@ void functionCallTest() {
6669
"What's the weather like in San Francisco, Tokyo, and Paris? Return the temperature in Celsius.");
6770

6871
ChatResponse response = chatModel
69-
.call(new Prompt(List.of(userMessage), MiniMaxChatOptions.builder().function("WeatherInfo").build()));
72+
.call(new Prompt(List.of(userMessage), MiniMaxChatOptions.builder().toolNames("WeatherInfo").build()));
7073

7174
logger.info("Response: {}", response);
7275

@@ -84,8 +87,8 @@ void streamFunctionCallTest() {
8487
UserMessage userMessage = new UserMessage(
8588
"What's the weather like in San Francisco, Tokyo, and Paris? Return the temperature in Celsius.");
8689

87-
Flux<ChatResponse> response = chatModel
88-
.stream(new Prompt(List.of(userMessage), MiniMaxChatOptions.builder().function("WeatherInfo").build()));
90+
Flux<ChatResponse> response = chatModel.stream(
91+
new Prompt(List.of(userMessage), MiniMaxChatOptions.builder().toolNames("WeatherInfo").build()));
8992

9093
String content = response.collectList()
9194
.block()
@@ -108,10 +111,9 @@ void streamFunctionCallTest() {
108111
static class Config {
109112

110113
@Bean
111-
public FunctionCallback weatherFunctionInfo() {
114+
public FunctionToolCallback<MockWeatherService.Request, MockWeatherService.Response> weatherFunctionInfo() {
112115

113-
return FunctionCallback.builder()
114-
.function("WeatherInfo", new MockWeatherService())
116+
return FunctionToolCallback.builder("WeatherInfo", new MockWeatherService())
115117
.description("Get the weather in location")
116118
.inputType(MockWeatherService.Request.class)
117119
.build();

0 commit comments

Comments
 (0)