Revamp function callback builder API
Introduces a simplified, type-safe builder pattern for function callbacks to improve developer experience and code reliability. The new hierarchical API separates concerns between direct function invocation and method reflection, while providing better compile-time safety. This change deprecates the older FunctionCallbackWrapper in favor of a more intuitive FunctionCallback.Builder that better handles generic types via ParameterizedTypeReference. It also adds automatic function description generation as a fallback when none is provided, though explicit descriptions are still recommended. The update standardizes function callback handling across all AI model implementations (OpenAI, Ollama, Minimax, etc.) and improves response handling with configurable converters. Core API Enhancements: - New Builder Interface: Replaced FunctionCallbackWrapper.builder() with FunctionCallback.builder(), introducing a hierarchical approach that improves customization and type safety. - Specialized Builders: Introduced FunctionInvokerBuilder for direct Function/BiFunction implementations and MethodInvokerBuilder for reflection-based invocations. - Generic Type Support: Added ParameterizedTypeReference for better handling of generic parameters. - Unified Method Definition: Merged method() and argumentTypes() into a single method() call for simplicity and type safety. - Automatic Descriptions: Implemented auto-generation of function descriptions, with warnings to encourage explicit descriptions. - Configurable Response Converters: Enhanced response handling with support for custom converters, reducing unnecessary JSON conversions. Architecture Improvements: - Established common Builder interface for shared properties - Separated function object handling from constructor - Added method-specific configuration (name, arg types, target) - Added JSON schema generation support for ResolvableType - Moved to standardized schema types across AI providers - Set OPEN_API_SCHEMA as default for Vertex AI Gemini Builder Pattern Standardization: - Standardized builder method ordering across implementations - Moved function() call after description() for consistency - Improved function callback configuration with unified patterns - Enhanced error handling and validation in DefaultFunctionCallbackBuilder Deprecations: - FunctionCallbackWrapper.Builder replaced by DefaultFunctionCallbackBuilder - Removed CustomizedTypeReference in favor of ParameterizedTypeReference - Deprecated older ChatClient API methods for function handling Testing & Documentation: - Updated all AI model implementations (OpenAI, Ollama, Minimax, Moonshot, ZhiPuAI) - Added comprehensive integration tests for static/instance methods - Added integration tests for auto-generated descriptions - Updated documentation to reflect new builder pattern usage - Added Kotlin extension for inputType() support Co-authored-by: Sébastien Deleuze <sebastien.deleuze@broadcom.com>
This commit is contained in:
committed by
Mark Pollack
parent
72c84fe8b8
commit
fb0d99dc37
@@ -48,7 +48,7 @@ import org.springframework.ai.converter.BeanOutputConverter;
|
||||
import org.springframework.ai.converter.ListOutputConverter;
|
||||
import org.springframework.ai.converter.MapOutputConverter;
|
||||
import org.springframework.ai.model.Media;
|
||||
import org.springframework.ai.model.function.FunctionCallbackWrapper;
|
||||
import org.springframework.ai.model.function.FunctionCallback;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
@@ -256,10 +256,11 @@ class AnthropicChatModelIT {
|
||||
|
||||
var promptOptions = AnthropicChatOptions.builder()
|
||||
.withModel(AnthropicApi.ChatModel.CLAUDE_3_OPUS.getName())
|
||||
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
|
||||
.withName("getCurrentWeather")
|
||||
.withDescription(
|
||||
.withFunctionCallbacks(List.of(FunctionCallback.builder()
|
||||
.description(
|
||||
"Get the weather in location. Return temperature in 36°F or 36°C format. Use multi-turn if needed.")
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
@@ -283,10 +284,11 @@ class AnthropicChatModelIT {
|
||||
|
||||
var promptOptions = AnthropicChatOptions.builder()
|
||||
.withModel(AnthropicApi.ChatModel.CLAUDE_3_5_SONNET.getName())
|
||||
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
|
||||
.withName("getCurrentWeather")
|
||||
.withDescription(
|
||||
.withFunctionCallbacks(List.of(FunctionCallback.builder()
|
||||
.description(
|
||||
"Get the weather in location. Return temperature in 36°F or 36°C format. Use multi-turn if needed.")
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ import org.springframework.ai.chat.model.ChatModel;
|
||||
import org.springframework.ai.chat.model.ChatResponse;
|
||||
import org.springframework.ai.converter.BeanOutputConverter;
|
||||
import org.springframework.ai.converter.ListOutputConverter;
|
||||
import org.springframework.ai.model.function.FunctionCallback;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
@@ -210,8 +211,30 @@ class AnthropicChatClientIT {
|
||||
|
||||
// @formatter:off
|
||||
String response = ChatClient.create(this.chatModel).prompt()
|
||||
.user(u -> u.text("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius."))
|
||||
.function("getCurrentWeather", "Get the weather in location", new MockWeatherService())
|
||||
.user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.")
|
||||
.functions(FunctionCallback.builder()
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build())
|
||||
.call()
|
||||
.content();
|
||||
// @formatter:on
|
||||
|
||||
logger.info("Response: {}", response);
|
||||
|
||||
assertThat(response).contains("30", "10", "15");
|
||||
}
|
||||
|
||||
@Test
|
||||
void functionCallWithGeneratedDescription() {
|
||||
|
||||
// @formatter:off
|
||||
String response = ChatClient.create(this.chatModel).prompt()
|
||||
.user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.")
|
||||
.functions(FunctionCallback.builder()
|
||||
.function("getCurrentWeatherInLocation", new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build())
|
||||
.call()
|
||||
.content();
|
||||
// @formatter:on
|
||||
@@ -226,7 +249,11 @@ class AnthropicChatClientIT {
|
||||
|
||||
// @formatter:off
|
||||
String response = ChatClient.builder(this.chatModel)
|
||||
.defaultFunction("getCurrentWeather", "Get the weather in location", new MockWeatherService())
|
||||
.defaultFunctions(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build())
|
||||
.defaultUser(u -> u.text("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius."))
|
||||
.build()
|
||||
.prompt()
|
||||
@@ -245,7 +272,11 @@ class AnthropicChatClientIT {
|
||||
// @formatter:off
|
||||
Flux<String> response = ChatClient.create(this.chatModel).prompt()
|
||||
.user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.")
|
||||
.function("getCurrentWeather", "Get the weather in location", new MockWeatherService())
|
||||
.functions(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build())
|
||||
.stream()
|
||||
.content();
|
||||
// @formatter:on
|
||||
|
||||
@@ -29,11 +29,10 @@ import org.springframework.ai.anthropic.AnthropicTestConfiguration;
|
||||
import org.springframework.ai.chat.client.ChatClient;
|
||||
import org.springframework.ai.chat.model.ChatModel;
|
||||
import org.springframework.ai.chat.model.ToolContext;
|
||||
import org.springframework.ai.model.function.MethodFunctionCallback;
|
||||
import org.springframework.ai.model.function.FunctionCallback;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;
|
||||
@@ -41,9 +40,10 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;
|
||||
@SpringBootTest(classes = AnthropicTestConfiguration.class, properties = "spring.ai.retry.on-http-codes=429")
|
||||
@EnabledIfEnvironmentVariable(named = "ANTHROPIC_API_KEY", matches = ".+")
|
||||
@ActiveProfiles("logging-test")
|
||||
class AnthropicChatClientMethodFunctionCallbackIT {
|
||||
class AnthropicChatClientMethodInvokingFunctionCallbackIT {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(AnthropicChatClientMethodFunctionCallbackIT.class);
|
||||
private static final Logger logger = LoggerFactory
|
||||
.getLogger(AnthropicChatClientMethodInvokingFunctionCallbackIT.class);
|
||||
|
||||
public static Map<String, Object> arguments = new ConcurrentHashMap<>();
|
||||
|
||||
@@ -53,15 +53,34 @@ class AnthropicChatClientMethodFunctionCallbackIT {
|
||||
}
|
||||
|
||||
@Test
|
||||
void methodGetWeatherStatic() {
|
||||
void methodGetWeatherGeneratedDescription() {
|
||||
|
||||
var method = ReflectionUtils.findMethod(TestFunctionClass.class, "getWeatherStatic", String.class, Unit.class);
|
||||
// @formatter:off
|
||||
String response = ChatClient.create(this.chatModel).prompt()
|
||||
.user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.")
|
||||
.functions(MethodFunctionCallback.builder()
|
||||
.method(method)
|
||||
.functions(FunctionCallback.builder()
|
||||
.method("getWeatherInLocation", String.class, Unit.class)
|
||||
.targetClass(TestFunctionClass.class)
|
||||
.build())
|
||||
.call()
|
||||
.content();
|
||||
// @formatter:on
|
||||
|
||||
logger.info("Response: {}", response);
|
||||
|
||||
assertThat(response).contains("30", "10", "15");
|
||||
}
|
||||
|
||||
@Test
|
||||
void methodGetWeatherStatic() {
|
||||
|
||||
// @formatter:off
|
||||
String response = ChatClient.create(this.chatModel).prompt()
|
||||
.user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.")
|
||||
.functions(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.method("getWeatherStatic", String.class, Unit.class)
|
||||
.targetClass(TestFunctionClass.class)
|
||||
.build())
|
||||
.call()
|
||||
.content();
|
||||
@@ -77,15 +96,13 @@ class AnthropicChatClientMethodFunctionCallbackIT {
|
||||
|
||||
TestFunctionClass targetObject = new TestFunctionClass();
|
||||
|
||||
var method = ReflectionUtils.findMethod(TestFunctionClass.class, "turnLight", String.class, boolean.class);
|
||||
|
||||
// @formatter:off
|
||||
String response = ChatClient.create(this.chatModel).prompt()
|
||||
.user("Turn light on in the living room.")
|
||||
.functions(MethodFunctionCallback.builder()
|
||||
.functionObject(targetObject)
|
||||
.method(method)
|
||||
.description("Can turn lights on or off by room name")
|
||||
.functions(FunctionCallback.builder()
|
||||
.description("Turn light on in the living room.")
|
||||
.method("turnLight", String.class, boolean.class)
|
||||
.targetObject(targetObject)
|
||||
.build())
|
||||
.call()
|
||||
.content();
|
||||
@@ -102,16 +119,13 @@ class AnthropicChatClientMethodFunctionCallbackIT {
|
||||
|
||||
TestFunctionClass targetObject = new TestFunctionClass();
|
||||
|
||||
var method = ReflectionUtils.findMethod(TestFunctionClass.class, "getWeatherNonStatic", String.class,
|
||||
Unit.class);
|
||||
|
||||
// @formatter:off
|
||||
String response = ChatClient.create(this.chatModel).prompt()
|
||||
.user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.")
|
||||
.functions(MethodFunctionCallback.builder()
|
||||
.functionObject(targetObject)
|
||||
.method(method)
|
||||
.functions(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.method("getWeatherNonStatic",String.class, Unit.class)
|
||||
.targetObject(targetObject)
|
||||
.build())
|
||||
.call()
|
||||
.content();
|
||||
@@ -127,17 +141,14 @@ class AnthropicChatClientMethodFunctionCallbackIT {
|
||||
|
||||
TestFunctionClass targetObject = new TestFunctionClass();
|
||||
|
||||
var method = ReflectionUtils.findMethod(TestFunctionClass.class, "getWeatherWithContext", String.class,
|
||||
Unit.class, ToolContext.class);
|
||||
|
||||
// @formatter:off
|
||||
String response = ChatClient.create(this.chatModel).prompt()
|
||||
.user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.")
|
||||
.functions(MethodFunctionCallback.builder()
|
||||
.functionObject(targetObject)
|
||||
.method(method)
|
||||
.functions(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.build())
|
||||
.method("getWeatherWithContext", String.class, Unit.class, ToolContext.class)
|
||||
.targetObject(targetObject)
|
||||
.build())
|
||||
.toolContext(Map.of("tool", "value"))
|
||||
.call()
|
||||
.content();
|
||||
@@ -154,17 +165,14 @@ class AnthropicChatClientMethodFunctionCallbackIT {
|
||||
|
||||
TestFunctionClass targetObject = new TestFunctionClass();
|
||||
|
||||
var method = ReflectionUtils.findMethod(TestFunctionClass.class, "getWeatherNonStatic", String.class,
|
||||
Unit.class);
|
||||
|
||||
// @formatter:off
|
||||
assertThatThrownBy(() -> ChatClient.create(this.chatModel).prompt()
|
||||
.user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.")
|
||||
.functions(MethodFunctionCallback.builder()
|
||||
.functionObject(targetObject)
|
||||
.method(method)
|
||||
.description("Get the weather in location")
|
||||
.build())
|
||||
.functions(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.method("getWeatherNonStatic", String.class, Unit.class)
|
||||
.targetObject(targetObject)
|
||||
.build())
|
||||
.toolContext(Map.of("tool", "value"))
|
||||
.call()
|
||||
.content())
|
||||
@@ -178,15 +186,13 @@ class AnthropicChatClientMethodFunctionCallbackIT {
|
||||
|
||||
TestFunctionClass targetObject = new TestFunctionClass();
|
||||
|
||||
var method = ReflectionUtils.findMethod(TestFunctionClass.class, "turnLivingRoomLightOn");
|
||||
|
||||
// @formatter:off
|
||||
String response = ChatClient.create(this.chatModel).prompt()
|
||||
.user("Turn light on in the living room.")
|
||||
.functions(MethodFunctionCallback.builder()
|
||||
.functionObject(targetObject)
|
||||
.method(method)
|
||||
.functions(FunctionCallback.builder()
|
||||
.description("Can turn lights on in the Living Room")
|
||||
.method("turnLivingRoomLightOn")
|
||||
.targetObject(targetObject)
|
||||
.build())
|
||||
.call()
|
||||
.content();
|
||||
@@ -215,6 +221,10 @@ class AnthropicChatClientMethodFunctionCallbackIT {
|
||||
arguments.put("method called", "argumentLessReturnVoid");
|
||||
}
|
||||
|
||||
public static String getWeatherInLocation(String city, Unit unit) {
|
||||
return getWeatherStatic(city, unit);
|
||||
}
|
||||
|
||||
public static String getWeatherStatic(String city, Unit unit) {
|
||||
|
||||
logger.info("City: " + city + " Unit: " + unit);
|
||||
@@ -39,7 +39,7 @@ import org.springframework.ai.chat.messages.UserMessage;
|
||||
import org.springframework.ai.chat.model.ChatResponse;
|
||||
import org.springframework.ai.chat.model.Generation;
|
||||
import org.springframework.ai.chat.prompt.Prompt;
|
||||
import org.springframework.ai.model.function.FunctionCallbackWrapper;
|
||||
import org.springframework.ai.model.function.FunctionCallback;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
@@ -70,10 +70,10 @@ class AzureOpenAiChatModelFunctionCallIT {
|
||||
|
||||
var promptOptions = AzureOpenAiChatOptions.builder()
|
||||
.withDeploymentName(this.selectedModel)
|
||||
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
|
||||
.withName("getCurrentWeather")
|
||||
.withDescription("Get the current weather in a given location")
|
||||
.withResponseConverter(response -> "" + response.temp() + response.unit())
|
||||
.withFunctionCallbacks(List.of(FunctionCallback.builder()
|
||||
.description("Get the current weather in a given location")
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
@@ -94,10 +94,10 @@ class AzureOpenAiChatModelFunctionCallIT {
|
||||
|
||||
var promptOptions = AzureOpenAiChatOptions.builder()
|
||||
.withDeploymentName(this.selectedModel)
|
||||
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
|
||||
.withName("getCurrentWeather")
|
||||
.withDescription("Get the current weather in a given location")
|
||||
.withResponseConverter(response -> "" + response.temp() + response.unit())
|
||||
.withFunctionCallbacks(List.of(FunctionCallback.builder()
|
||||
.description("Get the current weather in a given location")
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
@@ -116,10 +116,10 @@ class AzureOpenAiChatModelFunctionCallIT {
|
||||
|
||||
var promptOptions = AzureOpenAiChatOptions.builder()
|
||||
.withDeploymentName(this.selectedModel)
|
||||
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
|
||||
.withName("getCurrentWeather")
|
||||
.withDescription("Get the current weather in a given location")
|
||||
.withResponseConverter(response -> "" + response.temp() + response.unit())
|
||||
.withFunctionCallbacks(List.of(FunctionCallback.builder()
|
||||
.description("Get the current weather in a given location")
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
@@ -153,10 +153,10 @@ class AzureOpenAiChatModelFunctionCallIT {
|
||||
|
||||
var promptOptions = AzureOpenAiChatOptions.builder()
|
||||
.withDeploymentName(this.selectedModel)
|
||||
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
|
||||
.withName("getCurrentWeather")
|
||||
.withDescription("Get the current weather in a given location")
|
||||
.withResponseConverter(response -> "" + response.temp() + response.unit())
|
||||
.withFunctionCallbacks(List.of(FunctionCallback.builder()
|
||||
.description("Get the current weather in a given location")
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ import org.springframework.ai.chat.model.ChatModel;
|
||||
import org.springframework.ai.chat.model.ChatResponse;
|
||||
import org.springframework.ai.converter.BeanOutputConverter;
|
||||
import org.springframework.ai.converter.ListOutputConverter;
|
||||
import org.springframework.ai.model.function.FunctionCallback;
|
||||
import org.springframework.ai.model.function.FunctionCallingOptions;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
@@ -212,7 +213,11 @@ class BedrockConverseChatClientIT {
|
||||
// @formatter:off
|
||||
String response = ChatClient.create(this.chatModel)
|
||||
.prompt("What's the weather like in San Francisco, Tokyo, and Paris? Return the temperature in Celsius.")
|
||||
.function("getCurrentWeather", "Get the weather in location", new MockWeatherService())
|
||||
.functions(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build())
|
||||
.call()
|
||||
.content();
|
||||
// @formatter:on
|
||||
@@ -228,7 +233,11 @@ class BedrockConverseChatClientIT {
|
||||
// @formatter:off
|
||||
String response = ChatClient.create(this.chatModel)
|
||||
.prompt("What's the weather like in San Francisco, Tokyo, and Paris? Return the temperature in Celsius.")
|
||||
.function("getCurrentWeather", "Get the weather in location", new MockWeatherService())
|
||||
.functions(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build())
|
||||
.advisors(new SimpleLoggerAdvisor())
|
||||
.call()
|
||||
.content();
|
||||
@@ -244,7 +253,11 @@ class BedrockConverseChatClientIT {
|
||||
|
||||
// @formatter:off
|
||||
String response = ChatClient.builder(this.chatModel)
|
||||
.defaultFunction("getCurrentWeather", "Get the weather in location", new MockWeatherService())
|
||||
.defaultFunctions(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build())
|
||||
.defaultUser(u -> u.text("What's the weather like in San Francisco, Tokyo, and Paris? Return the temperature in Celsius."))
|
||||
.build()
|
||||
.prompt()
|
||||
@@ -263,7 +276,11 @@ class BedrockConverseChatClientIT {
|
||||
// @formatter:off
|
||||
Flux<String> response = ChatClient.create(this.chatModel).prompt()
|
||||
.user("What's the weather like in San Francisco, Tokyo, and Paris? Return the temperature in Celsius.")
|
||||
.function("getCurrentWeather", "Get the weather in location", new MockWeatherService())
|
||||
.functions(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build())
|
||||
.stream()
|
||||
.content();
|
||||
// @formatter:on
|
||||
@@ -280,7 +297,11 @@ class BedrockConverseChatClientIT {
|
||||
// @formatter:off
|
||||
Flux<String> response = ChatClient.create(this.chatModel).prompt()
|
||||
.user("What's the weather like in Paris? Return the temperature in Celsius.")
|
||||
.function("getCurrentWeather", "Get the weather in location", new MockWeatherService())
|
||||
.functions(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build())
|
||||
.stream()
|
||||
.content();
|
||||
// @formatter:on
|
||||
|
||||
@@ -47,7 +47,7 @@ import org.springframework.ai.converter.BeanOutputConverter;
|
||||
import org.springframework.ai.converter.ListOutputConverter;
|
||||
import org.springframework.ai.converter.MapOutputConverter;
|
||||
import org.springframework.ai.model.Media;
|
||||
import org.springframework.ai.model.function.FunctionCallbackWrapper;
|
||||
import org.springframework.ai.model.function.FunctionCallback;
|
||||
import org.springframework.ai.model.function.FunctionCallingOptions;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
@@ -254,10 +254,11 @@ class BedrockProxyChatModelIT {
|
||||
List<Message> messages = new ArrayList<>(List.of(userMessage));
|
||||
|
||||
var promptOptions = FunctionCallingOptions.builder()
|
||||
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
|
||||
.withName("getCurrentWeather")
|
||||
.withDescription(
|
||||
.withFunctionCallbacks(List.of(FunctionCallback.builder()
|
||||
.description(
|
||||
"Get the weather in location. Return temperature in 36°F or 36°C format. Use multi-turn if needed.")
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
@@ -281,10 +282,11 @@ class BedrockProxyChatModelIT {
|
||||
|
||||
var promptOptions = FunctionCallingOptions.builder()
|
||||
.withModel("anthropic.claude-3-5-sonnet-20240620-v1:0")
|
||||
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
|
||||
.withName("getCurrentWeather")
|
||||
.withDescription(
|
||||
.withFunctionCallbacks(List.of(FunctionCallback.builder()
|
||||
.description(
|
||||
"Get the weather in location. Return temperature in 36°F or 36°C format. Use multi-turn if needed.")
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ import software.amazon.awssdk.services.bedrockruntime.model.ConverseStreamOutput
|
||||
import org.springframework.ai.bedrock.converse.BedrockProxyChatModel;
|
||||
import org.springframework.ai.bedrock.converse.MockWeatherService;
|
||||
import org.springframework.ai.chat.prompt.Prompt;
|
||||
import org.springframework.ai.model.function.FunctionCallbackWrapper;
|
||||
import org.springframework.ai.model.function.FunctionCallback;
|
||||
import org.springframework.ai.model.function.FunctionCallingOptionsBuilder.PortableFunctionCallingOptions;
|
||||
|
||||
/**
|
||||
@@ -52,9 +52,10 @@ public final class BedrockConverseChatModelMain2 {
|
||||
"What's the weather like in Paris? Return the temperature in Celsius.",
|
||||
PortableFunctionCallingOptions.builder()
|
||||
.withModel(modelId)
|
||||
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
|
||||
.withName("getCurrentWeather")
|
||||
.withDescription("Get the weather in location")
|
||||
.withFunctionCallbacks(List.of(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build()))
|
||||
.build());
|
||||
|
||||
@@ -68,11 +69,6 @@ public final class BedrockConverseChatModelMain2 {
|
||||
Flux<ConverseStreamOutput> responses = chatModel.converseStream(streamRequest);
|
||||
List<ConverseStreamOutput> responseList = responses.collectList().block();
|
||||
System.out.println(responseList);
|
||||
|
||||
// Flux<ChatResponse> responses2 = ConverseApiUtils.toChatResponse(responses);
|
||||
// List<ChatResponse> responseList2 = responses2.collectList().block();
|
||||
// System.out.println(responseList2);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ import org.junit.jupiter.api.Test;
|
||||
import org.springframework.ai.chat.prompt.Prompt;
|
||||
import org.springframework.ai.minimax.api.MiniMaxApi;
|
||||
import org.springframework.ai.minimax.api.MockWeatherService;
|
||||
import org.springframework.ai.model.function.FunctionCallbackWrapper;
|
||||
import org.springframework.ai.model.function.FunctionCallback;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@@ -67,10 +67,10 @@ public class ChatCompletionRequestTests {
|
||||
var request = client.createRequest(new Prompt("Test message content",
|
||||
MiniMaxChatOptions.builder()
|
||||
.withModel("PROMPT_MODEL")
|
||||
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
|
||||
.withName(TOOL_FUNCTION_NAME)
|
||||
.withDescription("Get the weather in location")
|
||||
.withResponseConverter(response -> "" + response.temp() + response.unit())
|
||||
.withFunctionCallbacks(List.of(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.function(TOOL_FUNCTION_NAME, new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build()))
|
||||
.build()),
|
||||
false);
|
||||
@@ -94,10 +94,10 @@ public class ChatCompletionRequestTests {
|
||||
var client = new MiniMaxChatModel(new MiniMaxApi("TEST"),
|
||||
MiniMaxChatOptions.builder()
|
||||
.withModel("DEFAULT_MODEL")
|
||||
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
|
||||
.withName(TOOL_FUNCTION_NAME)
|
||||
.withDescription("Get the weather in location")
|
||||
.withResponseConverter(response -> "" + response.temp() + response.unit())
|
||||
.withFunctionCallbacks(List.of(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.function(TOOL_FUNCTION_NAME, new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build()))
|
||||
.build());
|
||||
|
||||
@@ -126,9 +126,10 @@ public class ChatCompletionRequestTests {
|
||||
// Override the default options function with one from the prompt
|
||||
request = client.createRequest(new Prompt("Test message content",
|
||||
MiniMaxChatOptions.builder()
|
||||
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
|
||||
.withName(TOOL_FUNCTION_NAME)
|
||||
.withDescription("Overridden function description")
|
||||
.withFunctionCallbacks(List.of(FunctionCallback.builder()
|
||||
.description("Overridden function description")
|
||||
.function(TOOL_FUNCTION_NAME, new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build()))
|
||||
.build()),
|
||||
false);
|
||||
|
||||
@@ -34,6 +34,7 @@ import org.springframework.ai.converter.BeanOutputConverter;
|
||||
import org.springframework.ai.converter.ListOutputConverter;
|
||||
import org.springframework.ai.mistralai.api.MistralAiApi;
|
||||
import org.springframework.ai.mistralai.api.MistralAiApi.ChatCompletionRequest.ToolChoice;
|
||||
import org.springframework.ai.model.function.FunctionCallback;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
@@ -224,7 +225,11 @@ class MistralAiChatClientIT {
|
||||
String response = ChatClient.create(this.chatModel).prompt()
|
||||
.options(MistralAiChatOptions.builder().withModel(MistralAiApi.ChatModel.SMALL).withToolChoice(ToolChoice.AUTO).build())
|
||||
.user(u -> u.text("What's the weather like in San Francisco, Tokyo, and Paris? Use parallel function calling if required. Response should be in Celsius."))
|
||||
.function("getCurrentWeather", "Get the weather in location", new MockWeatherService())
|
||||
.functions(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build())
|
||||
.call()
|
||||
.content();
|
||||
// @formatter:on
|
||||
@@ -242,7 +247,11 @@ class MistralAiChatClientIT {
|
||||
// @formatter:off
|
||||
String response = ChatClient.builder(this.chatModel)
|
||||
.defaultOptions(MistralAiChatOptions.builder().withModel(MistralAiApi.ChatModel.SMALL).build())
|
||||
.defaultFunction("getCurrentWeather", "Get the weather in location", new MockWeatherService())
|
||||
.defaultFunctions(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build())
|
||||
.defaultUser(u -> u.text("What's the weather like in San Francisco, Tokyo, and Paris? Use parallel function calling if required. Response should be in Celsius."))
|
||||
.build()
|
||||
.prompt().call().content();
|
||||
@@ -262,7 +271,11 @@ class MistralAiChatClientIT {
|
||||
Flux<String> response = ChatClient.create(this.chatModel).prompt()
|
||||
.options(MistralAiChatOptions.builder().withModel(MistralAiApi.ChatModel.SMALL).build())
|
||||
.user("What's the weather like in San Francisco, Tokyo, and Paris? Use parallel function calling if required. Response should be in Celsius.")
|
||||
.function("getCurrentWeather", "Get the weather in location", new MockWeatherService())
|
||||
.functions(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build())
|
||||
.stream()
|
||||
.content();
|
||||
// @formatter:on
|
||||
|
||||
@@ -42,7 +42,7 @@ import org.springframework.ai.converter.BeanOutputConverter;
|
||||
import org.springframework.ai.converter.ListOutputConverter;
|
||||
import org.springframework.ai.converter.MapOutputConverter;
|
||||
import org.springframework.ai.mistralai.api.MistralAiApi;
|
||||
import org.springframework.ai.model.function.FunctionCallbackWrapper;
|
||||
import org.springframework.ai.model.function.FunctionCallback;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
@@ -193,10 +193,10 @@ class MistralAiChatModelIT {
|
||||
|
||||
var promptOptions = MistralAiChatOptions.builder()
|
||||
.withModel(MistralAiApi.ChatModel.SMALL.getValue())
|
||||
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
|
||||
.withName("getCurrentWeather")
|
||||
.withDescription("Get the weather in location")
|
||||
.withResponseConverter(response -> "" + response.temp() + response.unit())
|
||||
.withFunctionCallbacks(List.of(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
@@ -216,10 +216,10 @@ class MistralAiChatModelIT {
|
||||
|
||||
var promptOptions = MistralAiChatOptions.builder()
|
||||
.withModel(MistralAiApi.ChatModel.SMALL.getValue())
|
||||
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
|
||||
.withName("getCurrentWeather")
|
||||
.withDescription("Get the weather in location")
|
||||
.withResponseConverter(response -> "" + response.temp() + response.unit())
|
||||
.withFunctionCallbacks(List.of(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ 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.prompt.Prompt;
|
||||
import org.springframework.ai.model.function.FunctionCallbackWrapper;
|
||||
import org.springframework.ai.model.function.FunctionCallback;
|
||||
import org.springframework.ai.moonshot.MoonshotChatOptions;
|
||||
import org.springframework.ai.moonshot.MoonshotTestConfiguration;
|
||||
import org.springframework.ai.moonshot.api.MockWeatherService;
|
||||
@@ -63,10 +63,10 @@ class MoonshotChatModelFunctionCallingIT {
|
||||
|
||||
var promptOptions = MoonshotChatOptions.builder()
|
||||
.withModel(MoonshotApi.ChatModel.MOONSHOT_V1_8K.getValue())
|
||||
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
|
||||
.withName("getCurrentWeather")
|
||||
.withDescription("Get the weather in location")
|
||||
.withResponseConverter(response -> "" + response.temp() + response.unit())
|
||||
.withFunctionCallbacks(List.of(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
@@ -86,11 +86,9 @@ class MoonshotChatModelFunctionCallingIT {
|
||||
List<Message> messages = new ArrayList<>(List.of(userMessage));
|
||||
|
||||
var promptOptions = MoonshotChatOptions.builder()
|
||||
// .withModel(OpenAiApi.ChatModel.GPT_4_TURBO_PREVIEW.getValue())
|
||||
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
|
||||
.withName("getCurrentWeather")
|
||||
.withDescription("Get the weather in location")
|
||||
.withResponseConverter(response -> "" + response.temp() + response.unit())
|
||||
.withFunctionCallbacks(List.of(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ 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.prompt.Prompt;
|
||||
import org.springframework.ai.model.function.FunctionCallbackWrapper;
|
||||
import org.springframework.ai.model.function.FunctionCallback;
|
||||
import org.springframework.ai.ollama.api.OllamaApi;
|
||||
import org.springframework.ai.ollama.api.OllamaOptions;
|
||||
import org.springframework.ai.ollama.api.tool.MockWeatherService;
|
||||
@@ -63,11 +63,11 @@ class OllamaChatModelFunctionCallingIT extends BaseOllamaIT {
|
||||
|
||||
var promptOptions = OllamaOptions.builder()
|
||||
.withModel(MODEL)
|
||||
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
|
||||
.withName("getCurrentWeather")
|
||||
.withDescription(
|
||||
.withFunctionCallbacks(List.of(FunctionCallback.builder()
|
||||
.description(
|
||||
"Find the weather conditions, forecasts, and temperatures for a location, like a city or state.")
|
||||
.withResponseConverter(response -> "" + response.temp() + response.unit())
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
@@ -88,11 +88,11 @@ class OllamaChatModelFunctionCallingIT extends BaseOllamaIT {
|
||||
|
||||
var promptOptions = OllamaOptions.builder()
|
||||
.withModel(MODEL)
|
||||
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
|
||||
.withName("getCurrentWeather")
|
||||
.withDescription(
|
||||
.withFunctionCallbacks(List.of(FunctionCallback.builder()
|
||||
.description(
|
||||
"Find the weather conditions, forecasts, and temperatures for a location, like a city or state.")
|
||||
.withResponseConverter(response -> "" + response.temp() + response.unit())
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ import java.util.List;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.ai.chat.prompt.Prompt;
|
||||
import org.springframework.ai.model.function.FunctionCallbackWrapper;
|
||||
import org.springframework.ai.model.function.FunctionCallback;
|
||||
import org.springframework.ai.openai.api.OpenAiApi;
|
||||
import org.springframework.ai.openai.api.tool.MockWeatherService;
|
||||
|
||||
@@ -67,10 +67,10 @@ public class ChatCompletionRequestTests {
|
||||
var request = client.createRequest(new Prompt("Test message content",
|
||||
OpenAiChatOptions.builder()
|
||||
.withModel("PROMPT_MODEL")
|
||||
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
|
||||
.withName(TOOL_FUNCTION_NAME)
|
||||
.withDescription("Get the weather in location")
|
||||
.withResponseConverter(response -> "" + response.temp() + response.unit())
|
||||
.withFunctionCallbacks(List.of(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.function(TOOL_FUNCTION_NAME, new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build()))
|
||||
.build()),
|
||||
false);
|
||||
@@ -94,10 +94,10 @@ public class ChatCompletionRequestTests {
|
||||
var client = new OpenAiChatModel(new OpenAiApi("TEST"),
|
||||
OpenAiChatOptions.builder()
|
||||
.withModel("DEFAULT_MODEL")
|
||||
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
|
||||
.withName(TOOL_FUNCTION_NAME)
|
||||
.withDescription("Get the weather in location")
|
||||
.withResponseConverter(response -> "" + response.temp() + response.unit())
|
||||
.withFunctionCallbacks(List.of(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.function(TOOL_FUNCTION_NAME, new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build()))
|
||||
.build());
|
||||
|
||||
@@ -126,9 +126,10 @@ public class ChatCompletionRequestTests {
|
||||
// Override the default options function with one from the prompt
|
||||
request = client.createRequest(new Prompt("Test message content",
|
||||
OpenAiChatOptions.builder()
|
||||
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
|
||||
.withName(TOOL_FUNCTION_NAME)
|
||||
.withDescription("Overridden function description")
|
||||
.withFunctionCallbacks(List.of(FunctionCallback.builder()
|
||||
.description("Overridden function description")
|
||||
.function(TOOL_FUNCTION_NAME, new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build()))
|
||||
.build()),
|
||||
false);
|
||||
|
||||
@@ -36,7 +36,7 @@ import org.springframework.ai.chat.model.ChatResponse;
|
||||
import org.springframework.ai.chat.model.Generation;
|
||||
import org.springframework.ai.chat.model.ToolContext;
|
||||
import org.springframework.ai.chat.prompt.Prompt;
|
||||
import org.springframework.ai.model.function.FunctionCallbackWrapper;
|
||||
import org.springframework.ai.model.function.FunctionCallback;
|
||||
import org.springframework.ai.openai.OpenAiChatModel;
|
||||
import org.springframework.ai.openai.OpenAiChatOptions;
|
||||
import org.springframework.ai.openai.api.OpenAiApi;
|
||||
@@ -63,10 +63,10 @@ class OpenAiChatModelFunctionCallingIT {
|
||||
void functionCallTest() {
|
||||
functionCallTest(OpenAiChatOptions.builder()
|
||||
.withModel(OpenAiApi.ChatModel.GPT_4_O.getValue())
|
||||
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
|
||||
.withName("getCurrentWeather")
|
||||
.withDescription("Get the weather in location")
|
||||
.withResponseConverter(response -> "" + response.temp() + response.unit())
|
||||
.withFunctionCallbacks(List.of(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build()))
|
||||
.build());
|
||||
}
|
||||
@@ -99,10 +99,10 @@ class OpenAiChatModelFunctionCallingIT {
|
||||
|
||||
functionCallTest(OpenAiChatOptions.builder()
|
||||
.withModel(OpenAiApi.ChatModel.GPT_4_O.getValue())
|
||||
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(biFunction)
|
||||
.withName("getCurrentWeather")
|
||||
.withDescription("Get the weather in location")
|
||||
.withResponseConverter(response -> "" + response.temp() + response.unit())
|
||||
.withFunctionCallbacks(List.of(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.function("getCurrentWeather", biFunction)
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build()))
|
||||
.withToolContext(Map.of("sessionId", "123"))
|
||||
.build());
|
||||
@@ -125,10 +125,11 @@ class OpenAiChatModelFunctionCallingIT {
|
||||
void streamFunctionCallTest() {
|
||||
|
||||
streamFunctionCallTest(OpenAiChatOptions.builder()
|
||||
.withFunctionCallbacks(List.of((FunctionCallbackWrapper.builder(new MockWeatherService())
|
||||
.withName("getCurrentWeather")
|
||||
.withDescription("Get the weather in location")
|
||||
.withResponseConverter(response -> "" + response.temp() + response.unit())
|
||||
.withFunctionCallbacks(List.of((FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
// .responseConverter(response -> "" + response.temp() + response.unit())
|
||||
.build())))
|
||||
.build());
|
||||
}
|
||||
@@ -160,10 +161,10 @@ class OpenAiChatModelFunctionCallingIT {
|
||||
};
|
||||
|
||||
OpenAiChatOptions promptOptions = OpenAiChatOptions.builder()
|
||||
.withFunctionCallbacks(List.of((FunctionCallbackWrapper.builder(biFunction)
|
||||
.withName("getCurrentWeather")
|
||||
.withDescription("Get the weather in location")
|
||||
.withResponseConverter(response -> "" + response.temp() + response.unit())
|
||||
.withFunctionCallbacks(List.of((FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.function("getCurrentWeather", biFunction)
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build())))
|
||||
.withToolContext(Map.of("sessionId", "123"))
|
||||
.build();
|
||||
|
||||
@@ -48,7 +48,7 @@ import org.springframework.ai.converter.BeanOutputConverter;
|
||||
import org.springframework.ai.converter.ListOutputConverter;
|
||||
import org.springframework.ai.converter.MapOutputConverter;
|
||||
import org.springframework.ai.model.Media;
|
||||
import org.springframework.ai.model.function.FunctionCallbackWrapper;
|
||||
import org.springframework.ai.model.function.FunctionCallback;
|
||||
import org.springframework.ai.openai.OpenAiChatOptions;
|
||||
import org.springframework.ai.openai.OpenAiTestConfiguration;
|
||||
import org.springframework.ai.openai.api.OpenAiApi;
|
||||
@@ -328,10 +328,10 @@ public class OpenAiChatModelIT extends AbstractIT {
|
||||
|
||||
var promptOptions = OpenAiChatOptions.builder()
|
||||
.withModel(OpenAiApi.ChatModel.GPT_4_O.getValue())
|
||||
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
|
||||
.withName("getCurrentWeather")
|
||||
.withDescription("Get the weather in location")
|
||||
.withResponseConverter(response -> "" + response.temp() + response.unit())
|
||||
.withFunctionCallbacks(List.of(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
@@ -353,10 +353,10 @@ public class OpenAiChatModelIT extends AbstractIT {
|
||||
|
||||
var promptOptions = OpenAiChatOptions.builder()
|
||||
// .withModel(OpenAiApi.ChatModel.GPT_4_TURBO_PREVIEW.getValue())
|
||||
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
|
||||
.withName("getCurrentWeather")
|
||||
.withDescription("Get the weather in location")
|
||||
.withResponseConverter(response -> "" + response.temp() + response.unit())
|
||||
.withFunctionCallbacks(List.of(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ import org.springframework.ai.chat.model.Generation;
|
||||
import org.springframework.ai.chat.prompt.Prompt;
|
||||
import org.springframework.ai.model.ModelOptionsUtils;
|
||||
import org.springframework.ai.model.function.FunctionCallback;
|
||||
import org.springframework.ai.model.function.ToolCallHelper;
|
||||
import org.springframework.ai.model.function.FunctionCallingHelper;
|
||||
import org.springframework.ai.openai.OpenAiChatModel;
|
||||
import org.springframework.ai.openai.OpenAiChatOptions;
|
||||
import org.springframework.ai.openai.api.OpenAiApi;
|
||||
@@ -64,7 +64,7 @@ class OpenAiChatModelProxyToolCallsIT {
|
||||
|
||||
private static final String DEFAULT_MODEL = "gpt-4o-mini";
|
||||
|
||||
FunctionCallback functionDefinition = new ToolCallHelper.FunctionDefinition("getWeatherInLocation",
|
||||
FunctionCallback functionDefinition = new FunctionCallingHelper.FunctionDefinition("getWeatherInLocation",
|
||||
"Get the weather in location", """
|
||||
{
|
||||
"type": "object",
|
||||
@@ -87,7 +87,7 @@ class OpenAiChatModelProxyToolCallsIT {
|
||||
|
||||
// Helper class that reuses some of the {@link AbstractToolCallSupport} functionality
|
||||
// to help to implement the function call handling logic on the client side.
|
||||
private ToolCallHelper toolCallHelper = new ToolCallHelper();
|
||||
private FunctionCallingHelper functionCallingHelper = new FunctionCallingHelper();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static Map<String, String> getFunctionArguments(String functionArguments) {
|
||||
@@ -139,7 +139,7 @@ class OpenAiChatModelProxyToolCallsIT {
|
||||
|
||||
// Note that the tool call check could be platform specific because the finish
|
||||
// reasons.
|
||||
isToolCall = this.toolCallHelper.isToolCall(chatResponse,
|
||||
isToolCall = this.functionCallingHelper.isToolCall(chatResponse,
|
||||
Set.of(OpenAiApi.ChatCompletionFinishReason.TOOL_CALLS.name(),
|
||||
OpenAiApi.ChatCompletionFinishReason.STOP.name()));
|
||||
|
||||
@@ -176,7 +176,7 @@ class OpenAiChatModelProxyToolCallsIT {
|
||||
|
||||
ToolResponseMessage toolMessageResponse = new ToolResponseMessage(toolResponses, Map.of());
|
||||
|
||||
List<Message> toolCallConversation = this.toolCallHelper
|
||||
List<Message> toolCallConversation = this.functionCallingHelper
|
||||
.buildToolCallConversation(prompt.getInstructions(), assistantMessage, toolMessageResponse);
|
||||
|
||||
assertThat(toolCallConversation).isNotEmpty();
|
||||
@@ -236,7 +236,7 @@ class OpenAiChatModelProxyToolCallsIT {
|
||||
|
||||
return chatResponses.flatMap(chatResponse -> {
|
||||
|
||||
boolean isToolCall = this.toolCallHelper.isToolCall(chatResponse, finishReasons);
|
||||
boolean isToolCall = this.functionCallingHelper.isToolCall(chatResponse, finishReasons);
|
||||
|
||||
if (isToolCall) {
|
||||
|
||||
@@ -261,7 +261,7 @@ class OpenAiChatModelProxyToolCallsIT {
|
||||
|
||||
ToolResponseMessage toolMessageResponse = new ToolResponseMessage(toolResponses, Map.of());
|
||||
|
||||
List<Message> toolCallConversation = this.toolCallHelper
|
||||
List<Message> toolCallConversation = this.functionCallingHelper
|
||||
.buildToolCallConversation(prompt.getInstructions(), assistantMessage, toolMessageResponse);
|
||||
|
||||
assertThat(toolCallConversation).isNotEmpty();
|
||||
@@ -285,7 +285,7 @@ class OpenAiChatModelProxyToolCallsIT {
|
||||
|
||||
var prompt = new Prompt(messages, promptOptions);
|
||||
|
||||
ChatResponse chatResponse = this.toolCallHelper.processCall(this.chatModel, prompt,
|
||||
ChatResponse chatResponse = this.functionCallingHelper.processCall(this.chatModel, prompt,
|
||||
Set.of(OpenAiApi.ChatCompletionFinishReason.TOOL_CALLS.name(),
|
||||
OpenAiApi.ChatCompletionFinishReason.STOP.name()),
|
||||
toolCall -> {
|
||||
@@ -319,7 +319,7 @@ class OpenAiChatModelProxyToolCallsIT {
|
||||
|
||||
var prompt = new Prompt(messages, promptOptions);
|
||||
|
||||
Flux<ChatResponse> responses = this.toolCallHelper.processStream(this.chatModel, prompt,
|
||||
Flux<ChatResponse> responses = this.functionCallingHelper.processStream(this.chatModel, prompt,
|
||||
Set.of(OpenAiApi.ChatCompletionFinishReason.TOOL_CALLS.name(),
|
||||
OpenAiApi.ChatCompletionFinishReason.STOP.name()),
|
||||
toolCall -> {
|
||||
|
||||
@@ -37,6 +37,7 @@ import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
|
||||
import org.springframework.ai.chat.model.ChatResponse;
|
||||
import org.springframework.ai.converter.BeanOutputConverter;
|
||||
import org.springframework.ai.converter.ListOutputConverter;
|
||||
import org.springframework.ai.model.function.FunctionCallback;
|
||||
import org.springframework.ai.openai.OpenAiChatOptions;
|
||||
import org.springframework.ai.openai.OpenAiTestConfiguration;
|
||||
import org.springframework.ai.openai.api.OpenAiApi;
|
||||
@@ -244,10 +245,16 @@ class OpenAiChatClientIT extends AbstractIT {
|
||||
@Test
|
||||
void functionCallTest() {
|
||||
|
||||
FunctionCallback functionCallback = FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build();
|
||||
|
||||
// @formatter:off
|
||||
String response = ChatClient.create(this.chatModel).prompt()
|
||||
.user(u -> u.text("What's the weather like in San Francisco, Tokyo, and Paris?"))
|
||||
.function("getCurrentWeather", "Get the weather in location", new MockWeatherService())
|
||||
.functions(functionCallback)
|
||||
.call()
|
||||
.content();
|
||||
// @formatter:on
|
||||
@@ -262,7 +269,11 @@ class OpenAiChatClientIT extends AbstractIT {
|
||||
|
||||
// @formatter:off
|
||||
String response = ChatClient.builder(this.chatModel)
|
||||
.defaultFunction("getCurrentWeather", "Get the weather in location", new MockWeatherService())
|
||||
.defaultFunctions(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build())
|
||||
.defaultUser(u -> u.text("What's the weather like in San Francisco, Tokyo, and Paris?"))
|
||||
.build()
|
||||
.prompt().call().content();
|
||||
@@ -279,7 +290,11 @@ class OpenAiChatClientIT extends AbstractIT {
|
||||
// @formatter:off
|
||||
Flux<String> response = ChatClient.create(this.chatModel).prompt()
|
||||
.user("What's the weather like in San Francisco, Tokyo, and Paris?")
|
||||
.function("getCurrentWeather", "Get the weather in location", new MockWeatherService())
|
||||
.functions(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build())
|
||||
.stream()
|
||||
.content();
|
||||
// @formatter:on
|
||||
|
||||
@@ -28,12 +28,11 @@ import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ai.chat.client.ChatClient;
|
||||
import org.springframework.ai.chat.model.ChatModel;
|
||||
import org.springframework.ai.chat.model.ToolContext;
|
||||
import org.springframework.ai.model.function.MethodFunctionCallback;
|
||||
import org.springframework.ai.model.function.FunctionCallback;
|
||||
import org.springframework.ai.openai.OpenAiTestConfiguration;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;
|
||||
@@ -41,9 +40,10 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;
|
||||
@SpringBootTest(classes = OpenAiTestConfiguration.class)
|
||||
@EnabledIfEnvironmentVariable(named = "OPENAI_API_KEY", matches = ".+")
|
||||
@ActiveProfiles("logging-test")
|
||||
class OpenAiChatClientMethodFunctionCallbackIT {
|
||||
class OpenAiChatClientMethodInvokingFunctionCallbackIT {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(OpenAiChatClientMethodFunctionCallbackIT.class);
|
||||
private static final Logger logger = LoggerFactory
|
||||
.getLogger(OpenAiChatClientMethodInvokingFunctionCallbackIT.class);
|
||||
|
||||
public static Map<String, Object> arguments = new ConcurrentHashMap<>();
|
||||
|
||||
@@ -57,14 +57,13 @@ class OpenAiChatClientMethodFunctionCallbackIT {
|
||||
|
||||
@Test
|
||||
void methodGetWeatherStatic() {
|
||||
|
||||
var method = ReflectionUtils.findMethod(TestFunctionClass.class, "getWeatherStatic", String.class, Unit.class);
|
||||
// @formatter:off
|
||||
String response = ChatClient.create(this.chatModel).prompt()
|
||||
.user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.")
|
||||
.functions(MethodFunctionCallback.builder()
|
||||
.method(method)
|
||||
.functions(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.method("getWeatherStatic",String.class, Unit.class)
|
||||
.targetClass(TestFunctionClass.class)
|
||||
.build())
|
||||
.call()
|
||||
.content();
|
||||
@@ -80,15 +79,13 @@ class OpenAiChatClientMethodFunctionCallbackIT {
|
||||
|
||||
TestFunctionClass targetObject = new TestFunctionClass();
|
||||
|
||||
var method = ReflectionUtils.findMethod(TestFunctionClass.class, "turnLight", String.class, boolean.class);
|
||||
|
||||
// @formatter:off
|
||||
String response = ChatClient.create(this.chatModel).prompt()
|
||||
.user("Turn light on in the living room.")
|
||||
.functions(MethodFunctionCallback.builder()
|
||||
.functionObject(targetObject)
|
||||
.method(method)
|
||||
.functions(FunctionCallback.builder()
|
||||
.description("Can turn lights on or off by room name")
|
||||
.method("turnLight", String.class, boolean.class)
|
||||
.targetObject(targetObject)
|
||||
.build())
|
||||
.call()
|
||||
.content();
|
||||
@@ -105,16 +102,13 @@ class OpenAiChatClientMethodFunctionCallbackIT {
|
||||
|
||||
TestFunctionClass targetObject = new TestFunctionClass();
|
||||
|
||||
var method = ReflectionUtils.findMethod(TestFunctionClass.class, "getWeatherNonStatic", String.class,
|
||||
Unit.class);
|
||||
|
||||
// @formatter:off
|
||||
String response = ChatClient.create(this.chatModel).prompt()
|
||||
.user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.")
|
||||
.functions(MethodFunctionCallback.builder()
|
||||
.functionObject(targetObject)
|
||||
.method(method)
|
||||
.functions(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.method("getWeatherNonStatic",String.class, Unit.class)
|
||||
.targetObject(targetObject)
|
||||
.build())
|
||||
.call()
|
||||
.content();
|
||||
@@ -130,16 +124,13 @@ class OpenAiChatClientMethodFunctionCallbackIT {
|
||||
|
||||
TestFunctionClass targetObject = new TestFunctionClass();
|
||||
|
||||
var method = ReflectionUtils.findMethod(TestFunctionClass.class, "getWeatherWithContext", String.class,
|
||||
Unit.class, ToolContext.class);
|
||||
|
||||
// @formatter:off
|
||||
String response = ChatClient.create(this.chatModel).prompt()
|
||||
.user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.")
|
||||
.functions(MethodFunctionCallback.builder()
|
||||
.functionObject(targetObject)
|
||||
.method(method)
|
||||
.functions(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.method("getWeatherWithContext", String.class, Unit.class, ToolContext.class)
|
||||
.targetObject(targetObject)
|
||||
.build())
|
||||
.toolContext(Map.of("tool", "value"))
|
||||
.call()
|
||||
@@ -157,17 +148,14 @@ class OpenAiChatClientMethodFunctionCallbackIT {
|
||||
|
||||
TestFunctionClass targetObject = new TestFunctionClass();
|
||||
|
||||
var method = ReflectionUtils.findMethod(TestFunctionClass.class, "getWeatherNonStatic", String.class,
|
||||
Unit.class);
|
||||
|
||||
// @formatter:off
|
||||
assertThatThrownBy(() -> ChatClient.create(this.chatModel).prompt()
|
||||
.user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.")
|
||||
.functions(MethodFunctionCallback.builder()
|
||||
.functionObject(targetObject)
|
||||
.method(method)
|
||||
.description("Get the weather in location")
|
||||
.build())
|
||||
.functions(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.method("getWeatherNonStatic", String.class, Unit.class)
|
||||
.targetObject(targetObject)
|
||||
.build())
|
||||
.toolContext(Map.of("tool", "value"))
|
||||
.call()
|
||||
.content())
|
||||
@@ -181,16 +169,14 @@ class OpenAiChatClientMethodFunctionCallbackIT {
|
||||
|
||||
TestFunctionClass targetObject = new TestFunctionClass();
|
||||
|
||||
var method = ReflectionUtils.findMethod(TestFunctionClass.class, "turnLivingRoomLightOn");
|
||||
|
||||
// @formatter:off
|
||||
String response = ChatClient.create(this.chatModel).prompt()
|
||||
.user("Turn light on in the living room.")
|
||||
.functions(MethodFunctionCallback.builder()
|
||||
.functionObject(targetObject)
|
||||
.method(method)
|
||||
.functions(FunctionCallback.builder()
|
||||
.description("Can turn lights on in the Living Room")
|
||||
.build())
|
||||
.method("turnLivingRoomLightOn")
|
||||
.targetObject(targetObject)
|
||||
.build())
|
||||
.call()
|
||||
.content();
|
||||
// @formatter:on
|
||||
@@ -31,6 +31,7 @@ import reactor.core.publisher.Flux;
|
||||
|
||||
import org.springframework.ai.chat.client.ChatClient;
|
||||
import org.springframework.ai.chat.model.ToolContext;
|
||||
import org.springframework.ai.model.function.FunctionCallback;
|
||||
import org.springframework.ai.openai.OpenAiTestConfiguration;
|
||||
import org.springframework.ai.openai.api.tool.MockWeatherService;
|
||||
import org.springframework.ai.openai.api.tool.MockWeatherService.Request;
|
||||
@@ -83,7 +84,11 @@ class OpenAiChatClientMultipleFunctionCallsIT extends AbstractIT {
|
||||
// @formatter:off
|
||||
response = chatClientBuilder.build().prompt()
|
||||
.user(u -> u.text("What's the weather like in San Francisco, Tokyo, and Paris?"))
|
||||
.function("getCurrentWeather", "Get the weather in location", new MockWeatherService())
|
||||
.functions(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build())
|
||||
.call()
|
||||
.content();
|
||||
// @formatter:on
|
||||
@@ -110,7 +115,11 @@ class OpenAiChatClientMultipleFunctionCallsIT extends AbstractIT {
|
||||
|
||||
// @formatter:off
|
||||
String response = ChatClient.builder(this.chatModel)
|
||||
.defaultFunction("getCurrentWeather", "Get the weather in location", new MockWeatherService())
|
||||
.defaultFunctions(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build())
|
||||
.defaultUser(u -> u.text("What's the weather like in San Francisco, Tokyo, and Paris?"))
|
||||
.build()
|
||||
.prompt().call().content();
|
||||
@@ -149,7 +158,11 @@ class OpenAiChatClientMultipleFunctionCallsIT extends AbstractIT {
|
||||
|
||||
// @formatter:off
|
||||
String response = ChatClient.builder(this.chatModel)
|
||||
.defaultFunction("getCurrentWeather", "Get the weather in location", biFunction)
|
||||
.defaultFunctions(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.function("getCurrentWeather", biFunction)
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build())
|
||||
.defaultUser(u -> u.text("What's the weather like in San Francisco, Tokyo, and Paris?"))
|
||||
.defaultToolContext(Map.of("sessionId", "123"))
|
||||
.build()
|
||||
@@ -189,7 +202,11 @@ class OpenAiChatClientMultipleFunctionCallsIT extends AbstractIT {
|
||||
|
||||
// @formatter:off
|
||||
String response = ChatClient.builder(this.chatModel)
|
||||
.defaultFunction("getCurrentWeather", "Get the weather in location", biFunction)
|
||||
.defaultFunctions(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.function("getCurrentWeather", biFunction)
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build())
|
||||
.defaultUser(u -> u.text("What's the weather like in San Francisco, Tokyo, and Paris?"))
|
||||
.build()
|
||||
.prompt()
|
||||
@@ -208,7 +225,11 @@ class OpenAiChatClientMultipleFunctionCallsIT extends AbstractIT {
|
||||
// @formatter:off
|
||||
Flux<String> response = ChatClient.create(this.chatModel).prompt()
|
||||
.user("What's the weather like in San Francisco, Tokyo, and Paris?")
|
||||
.function("getCurrentWeather", "Get the weather in location", new MockWeatherService())
|
||||
.functions(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build())
|
||||
.stream()
|
||||
.content();
|
||||
// @formatter:on
|
||||
|
||||
@@ -39,7 +39,7 @@ import org.springframework.ai.chat.model.ChatResponse;
|
||||
import org.springframework.ai.chat.model.Generation;
|
||||
import org.springframework.ai.model.ModelOptionsUtils;
|
||||
import org.springframework.ai.model.function.FunctionCallback;
|
||||
import org.springframework.ai.model.function.ToolCallHelper;
|
||||
import org.springframework.ai.model.function.FunctionCallingHelper;
|
||||
import org.springframework.ai.openai.OpenAiChatModel;
|
||||
import org.springframework.ai.openai.OpenAiChatOptions;
|
||||
import org.springframework.ai.openai.OpenAiTestConfiguration;
|
||||
@@ -64,7 +64,7 @@ class OpenAiChatClientProxyFunctionCallsIT extends AbstractIT {
|
||||
@Value("classpath:/prompts/system-message.st")
|
||||
private Resource systemTextResource;
|
||||
|
||||
FunctionCallback functionDefinition = new ToolCallHelper.FunctionDefinition("getWeatherInLocation",
|
||||
FunctionCallback functionDefinition = new FunctionCallingHelper.FunctionDefinition("getWeatherInLocation",
|
||||
"Get the weather in location", """
|
||||
{
|
||||
"type": "object",
|
||||
@@ -87,7 +87,7 @@ class OpenAiChatClientProxyFunctionCallsIT extends AbstractIT {
|
||||
|
||||
// Helper class that reuses some of the {@link AbstractToolCallSupport} functionality
|
||||
// to help to implement the function call handling logic on the client side.
|
||||
private ToolCallHelper toolCallHelper = new ToolCallHelper();
|
||||
private FunctionCallingHelper functionCallingHelper = new FunctionCallingHelper();
|
||||
|
||||
// Function which will be called by the AI model.
|
||||
private String getWeatherInLocation(String location, String unit) {
|
||||
@@ -130,7 +130,7 @@ class OpenAiChatClientProxyFunctionCallsIT extends AbstractIT {
|
||||
|
||||
// Note that the tool call check could be platform specific because the finish
|
||||
// reasons.
|
||||
isToolCall = this.toolCallHelper.isToolCall(chatResponse,
|
||||
isToolCall = this.functionCallingHelper.isToolCall(chatResponse,
|
||||
Set.of(OpenAiApi.ChatCompletionFinishReason.TOOL_CALLS.name(),
|
||||
OpenAiApi.ChatCompletionFinishReason.STOP.name()));
|
||||
|
||||
@@ -167,7 +167,7 @@ class OpenAiChatClientProxyFunctionCallsIT extends AbstractIT {
|
||||
|
||||
ToolResponseMessage toolMessageResponse = new ToolResponseMessage(toolResponses, Map.of());
|
||||
|
||||
messages = this.toolCallHelper.buildToolCallConversation(messages, assistantMessage,
|
||||
messages = this.functionCallingHelper.buildToolCallConversation(messages, assistantMessage,
|
||||
toolMessageResponse);
|
||||
|
||||
assertThat(messages).isNotEmpty();
|
||||
|
||||
@@ -46,7 +46,7 @@ import org.springframework.ai.converter.BeanOutputConverter;
|
||||
import org.springframework.ai.converter.ListOutputConverter;
|
||||
import org.springframework.ai.converter.MapOutputConverter;
|
||||
import org.springframework.ai.model.Media;
|
||||
import org.springframework.ai.model.function.FunctionCallbackWrapper;
|
||||
import org.springframework.ai.model.function.FunctionCallback;
|
||||
import org.springframework.ai.openai.OpenAiChatModel;
|
||||
import org.springframework.ai.openai.OpenAiChatOptions;
|
||||
import org.springframework.ai.openai.api.OpenAiApi;
|
||||
@@ -249,10 +249,10 @@ class GroqWithOpenAiChatModelIT {
|
||||
List<Message> messages = new ArrayList<>(List.of(userMessage));
|
||||
|
||||
var promptOptions = OpenAiChatOptions.builder()
|
||||
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
|
||||
.withName("getCurrentWeather")
|
||||
.withDescription("Get the weather in location")
|
||||
.withResponseConverter(response -> "" + response.temp() + response.unit())
|
||||
.withFunctionCallbacks(List.of(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
@@ -272,10 +272,10 @@ class GroqWithOpenAiChatModelIT {
|
||||
List<Message> messages = new ArrayList<>(List.of(userMessage));
|
||||
|
||||
var promptOptions = OpenAiChatOptions.builder()
|
||||
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
|
||||
.withName("getCurrentWeather")
|
||||
.withDescription("Get the weather in location")
|
||||
.withResponseConverter(response -> "" + response.temp() + response.unit())
|
||||
.withFunctionCallbacks(List.of(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ import org.springframework.ai.converter.BeanOutputConverter;
|
||||
import org.springframework.ai.converter.ListOutputConverter;
|
||||
import org.springframework.ai.converter.MapOutputConverter;
|
||||
import org.springframework.ai.model.Media;
|
||||
import org.springframework.ai.model.function.FunctionCallbackWrapper;
|
||||
import org.springframework.ai.model.function.FunctionCallback;
|
||||
import org.springframework.ai.openai.OpenAiChatModel;
|
||||
import org.springframework.ai.openai.OpenAiChatOptions;
|
||||
import org.springframework.ai.openai.api.OpenAiApi;
|
||||
@@ -251,10 +251,10 @@ class MistralWithOpenAiChatModelIT {
|
||||
|
||||
var promptOptions = OpenAiChatOptions.builder()
|
||||
.withModel(modelName)
|
||||
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
|
||||
.withName("getCurrentWeather")
|
||||
.withDescription("Get the weather in location")
|
||||
.withResponseConverter(response -> "" + response.temp() + response.unit())
|
||||
.withFunctionCallbacks(List.of(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
@@ -276,10 +276,10 @@ class MistralWithOpenAiChatModelIT {
|
||||
|
||||
var promptOptions = OpenAiChatOptions.builder()
|
||||
.withModel(modelName)
|
||||
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
|
||||
.withName("getCurrentWeather")
|
||||
.withDescription("Get the weather in location")
|
||||
.withResponseConverter(response -> "" + response.temp() + response.unit())
|
||||
.withFunctionCallbacks(List.of(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ import org.springframework.ai.chat.prompt.SystemPromptTemplate;
|
||||
import org.springframework.ai.converter.BeanOutputConverter;
|
||||
import org.springframework.ai.converter.ListOutputConverter;
|
||||
import org.springframework.ai.converter.MapOutputConverter;
|
||||
import org.springframework.ai.model.function.FunctionCallbackWrapper;
|
||||
import org.springframework.ai.model.function.FunctionCallback;
|
||||
import org.springframework.ai.openai.OpenAiChatModel;
|
||||
import org.springframework.ai.openai.OpenAiChatOptions;
|
||||
import org.springframework.ai.openai.api.OpenAiApi;
|
||||
@@ -246,10 +246,10 @@ class NvidiaWithOpenAiChatModelIT {
|
||||
List<Message> messages = new ArrayList<>(List.of(userMessage));
|
||||
|
||||
var promptOptions = OpenAiChatOptions.builder()
|
||||
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
|
||||
.withName("getCurrentWeather")
|
||||
.withDescription("Get the weather in location")
|
||||
.withResponseConverter(response -> "" + response.temp() + response.unit())
|
||||
.withFunctionCallbacks(List.of(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
@@ -269,10 +269,10 @@ class NvidiaWithOpenAiChatModelIT {
|
||||
List<Message> messages = new ArrayList<>(List.of(userMessage));
|
||||
|
||||
var promptOptions = OpenAiChatOptions.builder()
|
||||
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
|
||||
.withName("getCurrentWeather")
|
||||
.withDescription("Get the weather in location")
|
||||
.withResponseConverter(response -> "" + response.temp() + response.unit())
|
||||
.withFunctionCallbacks(List.of(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ import org.springframework.ai.converter.BeanOutputConverter;
|
||||
import org.springframework.ai.converter.ListOutputConverter;
|
||||
import org.springframework.ai.converter.MapOutputConverter;
|
||||
import org.springframework.ai.model.Media;
|
||||
import org.springframework.ai.model.function.FunctionCallbackWrapper;
|
||||
import org.springframework.ai.model.function.FunctionCallback;
|
||||
import org.springframework.ai.openai.OpenAiChatModel;
|
||||
import org.springframework.ai.openai.OpenAiChatOptions;
|
||||
import org.springframework.ai.openai.api.OpenAiApi;
|
||||
@@ -268,10 +268,10 @@ class OllamaWithOpenAiChatModelIT {
|
||||
List<Message> messages = new ArrayList<>(List.of(userMessage));
|
||||
|
||||
var promptOptions = OpenAiChatOptions.builder()
|
||||
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
|
||||
.withName("getCurrentWeather")
|
||||
.withDescription("Get the weather in location")
|
||||
.withResponseConverter(response -> "" + response.temp() + response.unit())
|
||||
.withFunctionCallbacks(List.of(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
@@ -292,10 +292,9 @@ class OllamaWithOpenAiChatModelIT {
|
||||
List<Message> messages = new ArrayList<>(List.of(userMessage));
|
||||
|
||||
var promptOptions = OpenAiChatOptions.builder()
|
||||
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
|
||||
.withName("getCurrentWeather")
|
||||
.withDescription("Get the weather in location")
|
||||
.withResponseConverter(response -> "" + response.temp() + response.unit())
|
||||
.withFunctionCallbacks(List.of(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ import org.springframework.ai.chat.messages.SystemMessage;
|
||||
import org.springframework.ai.chat.messages.UserMessage;
|
||||
import org.springframework.ai.chat.prompt.Prompt;
|
||||
import org.springframework.ai.model.Media;
|
||||
import org.springframework.ai.model.function.FunctionCallbackWrapper;
|
||||
import org.springframework.ai.model.function.FunctionCallback;
|
||||
import org.springframework.ai.vertexai.gemini.VertexAiGeminiChatModel.GeminiRequest;
|
||||
import org.springframework.ai.vertexai.gemini.function.MockWeatherService;
|
||||
import org.springframework.util.MimeTypeUtils;
|
||||
@@ -117,10 +117,10 @@ public class CreateGeminiRequestTests {
|
||||
var request = client.createGeminiRequest(new Prompt("Test message content",
|
||||
VertexAiGeminiChatOptions.builder()
|
||||
.withModel("PROMPT_MODEL")
|
||||
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
|
||||
.withName(TOOL_FUNCTION_NAME)
|
||||
.withDescription("Get the weather in location")
|
||||
.withResponseConverter(response -> "" + response.temp() + response.unit())
|
||||
.withFunctionCallbacks(List.of(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.function(TOOL_FUNCTION_NAME, new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build()))
|
||||
.build()),
|
||||
null);
|
||||
@@ -145,10 +145,10 @@ public class CreateGeminiRequestTests {
|
||||
var client = new VertexAiGeminiChatModel(this.vertexAI,
|
||||
VertexAiGeminiChatOptions.builder()
|
||||
.withModel("DEFAULT_MODEL")
|
||||
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
|
||||
.withName(TOOL_FUNCTION_NAME)
|
||||
.withDescription("Get the weather in location")
|
||||
.withResponseConverter(response -> "" + response.temp() + response.unit())
|
||||
.withFunctionCallbacks(List.of(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.function(TOOL_FUNCTION_NAME, new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build()))
|
||||
.build());
|
||||
|
||||
@@ -178,9 +178,10 @@ public class CreateGeminiRequestTests {
|
||||
// Override the default options function with one from the prompt
|
||||
request = client.createGeminiRequest(new Prompt("Test message content",
|
||||
VertexAiGeminiChatOptions.builder()
|
||||
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
|
||||
.withName(TOOL_FUNCTION_NAME)
|
||||
.withDescription("Overridden function description")
|
||||
.withFunctionCallbacks(List.of(FunctionCallback.builder()
|
||||
.description("Overridden function description")
|
||||
.function(TOOL_FUNCTION_NAME, new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build()))
|
||||
.build()),
|
||||
null);
|
||||
|
||||
@@ -35,8 +35,8 @@ import org.springframework.ai.chat.messages.UserMessage;
|
||||
import org.springframework.ai.chat.model.ChatResponse;
|
||||
import org.springframework.ai.chat.model.Generation;
|
||||
import org.springframework.ai.chat.prompt.Prompt;
|
||||
import org.springframework.ai.model.function.FunctionCallback;
|
||||
import org.springframework.ai.model.function.FunctionCallbackContext.SchemaType;
|
||||
import org.springframework.ai.model.function.FunctionCallbackWrapper;
|
||||
import org.springframework.ai.vertexai.gemini.VertexAiGeminiChatModel;
|
||||
import org.springframework.ai.vertexai.gemini.VertexAiGeminiChatOptions;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -83,11 +83,11 @@ public class VertexAiGeminiChatModelFunctionCallingIT {
|
||||
""";
|
||||
|
||||
var promptOptions = VertexAiGeminiChatOptions.builder()
|
||||
// .withModel(VertexAiGeminiChatModel.ChatModel.GEMINI_1_5_FLASH)
|
||||
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
|
||||
.withName("get_current_weather")
|
||||
.withDescription("Get the current weather in a given location")
|
||||
.withInputTypeSchema(openApiSchema)
|
||||
.withFunctionCallbacks(List.of(FunctionCallback.builder()
|
||||
.description("Get the current weather in a given location")
|
||||
.inputTypeSchema(openApiSchema)
|
||||
.function("get_current_weather", new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
@@ -108,16 +108,18 @@ public class VertexAiGeminiChatModelFunctionCallingIT {
|
||||
var promptOptions = VertexAiGeminiChatOptions.builder()
|
||||
.withModel(VertexAiGeminiChatModel.ChatModel.GEMINI_1_5_FLASH)
|
||||
.withFunctionCallbacks(List.of(
|
||||
FunctionCallbackWrapper.builder(new MockWeatherService())
|
||||
.withSchemaType(SchemaType.OPEN_API_SCHEMA)
|
||||
.withName("get_current_weather")
|
||||
.withDescription("Get the current weather in a given location.")
|
||||
FunctionCallback.builder()
|
||||
.schemaType(SchemaType.OPEN_API_SCHEMA)
|
||||
.description("Get the current weather in a given location.")
|
||||
.function("get_current_weather", new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build(),
|
||||
FunctionCallbackWrapper.builder(new PaymentStatus())
|
||||
.withSchemaType(SchemaType.OPEN_API_SCHEMA)
|
||||
.withName("get_payment_status")
|
||||
.withDescription(
|
||||
FunctionCallback.builder()
|
||||
.schemaType(SchemaType.OPEN_API_SCHEMA)
|
||||
.description(
|
||||
"Retrieves the payment status for transaction. For example what is the payment status for transaction 700?")
|
||||
.function("get_payment_status", new PaymentStatus())
|
||||
.inputType(PaymentInfoRequest.class)
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
@@ -147,16 +149,18 @@ public class VertexAiGeminiChatModelFunctionCallingIT {
|
||||
var promptOptions = VertexAiGeminiChatOptions.builder()
|
||||
.withModel(VertexAiGeminiChatModel.ChatModel.GEMINI_1_5_FLASH)
|
||||
.withFunctionCallbacks(List.of(
|
||||
FunctionCallbackWrapper.builder(new MockWeatherService())
|
||||
.withSchemaType(SchemaType.OPEN_API_SCHEMA)
|
||||
.withName("get_current_weather")
|
||||
.withDescription("Get the current weather in a given location.")
|
||||
FunctionCallback.builder()
|
||||
.schemaType(SchemaType.OPEN_API_SCHEMA)
|
||||
.description("Get the current weather in a given location.")
|
||||
.function("get_current_weather", new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build(),
|
||||
FunctionCallbackWrapper.builder(new PaymentStatus())
|
||||
.withSchemaType(SchemaType.OPEN_API_SCHEMA)
|
||||
.withName("get_payment_status")
|
||||
.withDescription(
|
||||
FunctionCallback.builder()
|
||||
.schemaType(SchemaType.OPEN_API_SCHEMA)
|
||||
.description(
|
||||
"Retrieves the payment status for transaction. For example what is the payment status for transaction 700?")
|
||||
.function("get_payment_status", new PaymentStatus())
|
||||
.inputType(PaymentInfoRequest.class)
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
@@ -185,10 +189,11 @@ public class VertexAiGeminiChatModelFunctionCallingIT {
|
||||
|
||||
var promptOptions = VertexAiGeminiChatOptions.builder()
|
||||
.withModel(VertexAiGeminiChatModel.ChatModel.GEMINI_1_5_FLASH)
|
||||
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
|
||||
.withSchemaType(SchemaType.OPEN_API_SCHEMA)
|
||||
.withName("getCurrentWeather")
|
||||
.withDescription("Get the current weather in a given location")
|
||||
.withFunctionCallbacks(List.of(FunctionCallback.builder()
|
||||
.schemaType(SchemaType.OPEN_API_SCHEMA)
|
||||
.description("Get the current weather in a given location")
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ import java.util.List;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.ai.chat.prompt.Prompt;
|
||||
import org.springframework.ai.model.function.FunctionCallbackWrapper;
|
||||
import org.springframework.ai.model.function.FunctionCallback;
|
||||
import org.springframework.ai.zhipuai.api.MockWeatherService;
|
||||
import org.springframework.ai.zhipuai.api.ZhiPuAiApi;
|
||||
|
||||
@@ -67,10 +67,10 @@ public class ChatCompletionRequestTests {
|
||||
var request = client.createRequest(new Prompt("Test message content",
|
||||
ZhiPuAiChatOptions.builder()
|
||||
.withModel("PROMPT_MODEL")
|
||||
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
|
||||
.withName(TOOL_FUNCTION_NAME)
|
||||
.withDescription("Get the weather in location")
|
||||
.withResponseConverter(response -> "" + response.temp() + response.unit())
|
||||
.withFunctionCallbacks(List.of(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.function(TOOL_FUNCTION_NAME, new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build()))
|
||||
.build()),
|
||||
false);
|
||||
@@ -94,10 +94,10 @@ public class ChatCompletionRequestTests {
|
||||
var client = new ZhiPuAiChatModel(new ZhiPuAiApi("TEST"),
|
||||
ZhiPuAiChatOptions.builder()
|
||||
.withModel("DEFAULT_MODEL")
|
||||
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
|
||||
.withName(TOOL_FUNCTION_NAME)
|
||||
.withDescription("Get the weather in location")
|
||||
.withResponseConverter(response -> "" + response.temp() + response.unit())
|
||||
.withFunctionCallbacks(List.of(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.function(TOOL_FUNCTION_NAME, new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build()))
|
||||
.build());
|
||||
|
||||
@@ -126,9 +126,10 @@ public class ChatCompletionRequestTests {
|
||||
// Override the default options function with one from the prompt
|
||||
request = client.createRequest(new Prompt("Test message content",
|
||||
ZhiPuAiChatOptions.builder()
|
||||
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
|
||||
.withName(TOOL_FUNCTION_NAME)
|
||||
.withDescription("Overridden function description")
|
||||
.withFunctionCallbacks(List.of(FunctionCallback.builder()
|
||||
.description("Overridden function description")
|
||||
.function(TOOL_FUNCTION_NAME, new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build()))
|
||||
.build()),
|
||||
false);
|
||||
|
||||
@@ -47,7 +47,7 @@ import org.springframework.ai.converter.BeanOutputConverter;
|
||||
import org.springframework.ai.converter.ListOutputConverter;
|
||||
import org.springframework.ai.converter.MapOutputConverter;
|
||||
import org.springframework.ai.model.Media;
|
||||
import org.springframework.ai.model.function.FunctionCallbackWrapper;
|
||||
import org.springframework.ai.model.function.FunctionCallback;
|
||||
import org.springframework.ai.zhipuai.ZhiPuAiChatOptions;
|
||||
import org.springframework.ai.zhipuai.ZhiPuAiTestConfiguration;
|
||||
import org.springframework.ai.zhipuai.api.MockWeatherService;
|
||||
@@ -230,10 +230,10 @@ class ZhiPuAiChatModelIT {
|
||||
|
||||
var promptOptions = ZhiPuAiChatOptions.builder()
|
||||
.withModel(ZhiPuAiApi.ChatModel.GLM_4.getValue())
|
||||
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
|
||||
.withName("getCurrentWeather")
|
||||
.withDescription("Get the weather in location")
|
||||
.withResponseConverter(response -> "" + response.temp() + response.unit())
|
||||
.withFunctionCallbacks(List.of(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
@@ -256,10 +256,10 @@ class ZhiPuAiChatModelIT {
|
||||
|
||||
var promptOptions = ZhiPuAiChatOptions.builder()
|
||||
.withModel(ZhiPuAiApi.ChatModel.GLM_4.getValue())
|
||||
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
|
||||
.withName("getCurrentWeather")
|
||||
.withDescription("Get the weather in location")
|
||||
.withResponseConverter(response -> "" + response.temp() + response.unit())
|
||||
.withFunctionCallbacks(List.of(FunctionCallback.builder()
|
||||
.description("Get the weather in location")
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user