Refactor FunctionCallingOptions Builder
- Deprecate existing FunctionCallingOptionsBuilder - Create FunctionCallingOptions.Builder which extends ChatOptions.Builder - Create DefaultFunctionCallingOptions which extends DefaultChatOptions and implements FunctionCallingOptions to serve the default FunctionCalling options - Create DefaultFunctionCallingOptionsBuilder to build the default functioncalling options - Update the usage of functioncalling options builder to use the newly added builder including the tests Improve extensibility of DefaultChatOptionsBuilder - Enable DefaultChatOptionsBuilder to accommodate any other sub types - Introduce generics to support sub types that extend DefaultChatOptionsBuilder - Update builder methods to return the sub type - Make FunctionCallingOptions' builder()'s return type to accommodate sub types which can extend FunctionCallingOptions.Builder
This commit is contained in:
committed by
Mark Pollack
parent
627fb79e5e
commit
b25d6e8d2d
@@ -50,7 +50,7 @@ import org.springframework.ai.converter.ListOutputConverter;
|
||||
import org.springframework.ai.converter.MapOutputConverter;
|
||||
import org.springframework.ai.model.Media;
|
||||
import org.springframework.ai.model.function.FunctionCallback;
|
||||
import org.springframework.ai.model.function.FunctionCallingOptionsBuilder.PortableFunctionCallingOptions;
|
||||
import org.springframework.ai.model.function.FunctionCallingOptions;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
@@ -259,9 +259,7 @@ class AnthropicChatModelIT {
|
||||
List.of(new Media(new MimeType("application", "pdf"), pdfData)));
|
||||
|
||||
var response = this.chatModel.call(new Prompt(List.of(userMessage),
|
||||
PortableFunctionCallingOptions.builder()
|
||||
.withModel(AnthropicApi.ChatModel.CLAUDE_3_5_SONNET.getName())
|
||||
.build()));
|
||||
FunctionCallingOptions.builder().model(AnthropicApi.ChatModel.CLAUDE_3_5_SONNET.getName()).build()));
|
||||
|
||||
assertThat(response.getResult().getOutput().getText()).containsAnyOf("Spring AI", "portable API");
|
||||
}
|
||||
|
||||
@@ -96,11 +96,10 @@ import org.springframework.ai.chat.prompt.ChatOptions;
|
||||
import org.springframework.ai.chat.prompt.Prompt;
|
||||
import org.springframework.ai.model.Media;
|
||||
import org.springframework.ai.model.ModelOptionsUtils;
|
||||
import org.springframework.ai.model.function.DefaultFunctionCallingOptions;
|
||||
import org.springframework.ai.model.function.FunctionCallback;
|
||||
import org.springframework.ai.model.function.FunctionCallbackResolver;
|
||||
import org.springframework.ai.model.function.FunctionCallingOptions;
|
||||
import org.springframework.ai.model.function.FunctionCallingOptionsBuilder;
|
||||
import org.springframework.ai.model.function.FunctionCallingOptionsBuilder.PortableFunctionCallingOptions;
|
||||
import org.springframework.ai.observation.conventions.AiProvider;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
@@ -322,12 +321,12 @@ public class BedrockProxyChatModel extends AbstractToolCallSupport implements Ch
|
||||
if (prompt.getOptions() != null) {
|
||||
if (prompt.getOptions() instanceof FunctionCallingOptions) {
|
||||
var functionCallingOptions = (FunctionCallingOptions) prompt.getOptions();
|
||||
updatedRuntimeOptions = ((PortableFunctionCallingOptions) updatedRuntimeOptions)
|
||||
updatedRuntimeOptions = ((DefaultFunctionCallingOptions) updatedRuntimeOptions)
|
||||
.merge(functionCallingOptions);
|
||||
}
|
||||
else if (prompt.getOptions() instanceof ChatOptions) {
|
||||
var chatOptions = (ChatOptions) prompt.getOptions();
|
||||
updatedRuntimeOptions = ((PortableFunctionCallingOptions) updatedRuntimeOptions).merge(chatOptions);
|
||||
updatedRuntimeOptions = ((DefaultFunctionCallingOptions) updatedRuntimeOptions).merge(chatOptions);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -697,7 +696,7 @@ public class BedrockProxyChatModel extends AbstractToolCallSupport implements Ch
|
||||
|
||||
private Duration timeout = Duration.ofMinutes(10);
|
||||
|
||||
private FunctionCallingOptions defaultOptions = new FunctionCallingOptionsBuilder().build();
|
||||
private FunctionCallingOptions defaultOptions = new DefaultFunctionCallingOptions();
|
||||
|
||||
private FunctionCallbackResolver functionCallbackResolver;
|
||||
|
||||
|
||||
@@ -372,7 +372,7 @@ class BedrockConverseChatClientIT {
|
||||
|
||||
// @formatter:off
|
||||
String response = ChatClient.create(this.chatModel).prompt()
|
||||
.options(FunctionCallingOptions.builder().withModel(modelName).build())
|
||||
.options(FunctionCallingOptions.builder().model(modelName).build())
|
||||
.user(u -> u.text("Explain what do you see on this picture?")
|
||||
.media(MimeTypeUtils.IMAGE_PNG, new ClassPathResource("/test.png")))
|
||||
.call()
|
||||
@@ -394,7 +394,7 @@ class BedrockConverseChatClientIT {
|
||||
// @formatter:off
|
||||
String response = ChatClient.create(this.chatModel).prompt()
|
||||
// TODO consider adding model(...) method to ChatClient as a shortcut to
|
||||
.options(FunctionCallingOptions.builder().withModel(modelName).build())
|
||||
.options(FunctionCallingOptions.builder().model(modelName).build())
|
||||
.user(u -> u.text("Explain what do you see on this picture?").media(MimeTypeUtils.IMAGE_PNG, url))
|
||||
.call()
|
||||
.content();
|
||||
|
||||
@@ -42,7 +42,7 @@ public class BedrockConverseTestConfiguration {
|
||||
.withRegion(Region.US_EAST_1)
|
||||
.withTimeout(Duration.ofSeconds(120))
|
||||
// .withRegion(Region.US_EAST_1)
|
||||
.withDefaultOptions(FunctionCallingOptions.builder().withModel(modelId).build())
|
||||
.withDefaultOptions(FunctionCallingOptions.builder().model(modelId).build())
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,6 @@ import software.amazon.awssdk.services.bedrockruntime.model.ToolUseBlock;
|
||||
import org.springframework.ai.chat.prompt.Prompt;
|
||||
import org.springframework.ai.model.function.FunctionCallback;
|
||||
import org.springframework.ai.model.function.FunctionCallingOptions;
|
||||
import org.springframework.ai.model.function.FunctionCallingOptionsBuilder.PortableFunctionCallingOptions;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.isA;
|
||||
@@ -145,7 +144,7 @@ public class BedrockConverseUsageAggregationTests {
|
||||
.build();
|
||||
|
||||
var result = this.chatModel.call(new Prompt("What is the weather in Paris?",
|
||||
PortableFunctionCallingOptions.builder().withFunctionCallbacks(functionCallback).build()));
|
||||
FunctionCallingOptions.builder().functionCallbacks(functionCallback).build()));
|
||||
|
||||
assertThat(result).isNotNull();
|
||||
assertThat(result.getResult().getOutput().getText())
|
||||
|
||||
@@ -90,7 +90,7 @@ class BedrockProxyChatModelIT {
|
||||
SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(this.systemResource);
|
||||
Message systemMessage = systemPromptTemplate.createMessage(Map.of("name", "Bob", "voice", "pirate"));
|
||||
Prompt prompt = new Prompt(List.of(userMessage, systemMessage),
|
||||
FunctionCallingOptions.builder().withModel(modelName).build());
|
||||
FunctionCallingOptions.builder().model(modelName).build());
|
||||
ChatResponse response = this.chatModel.call(prompt);
|
||||
assertThat(response.getResults()).hasSize(1);
|
||||
assertThat(response.getMetadata().getUsage().getGenerationTokens()).isGreaterThan(0);
|
||||
@@ -126,7 +126,7 @@ class BedrockProxyChatModelIT {
|
||||
|
||||
@Test
|
||||
void streamingWithTokenUsage() {
|
||||
var promptOptions = FunctionCallingOptions.builder().withTemperature(0.0).build();
|
||||
var promptOptions = FunctionCallingOptions.builder().temperature(0.0).build();
|
||||
|
||||
var prompt = new Prompt("List two colors of the Polish flag. Be brief.", promptOptions);
|
||||
var streamingTokenUsage = this.chatModel.stream(prompt).blockLast().getMetadata().getUsage();
|
||||
@@ -252,7 +252,7 @@ class BedrockProxyChatModelIT {
|
||||
List<Message> messages = new ArrayList<>(List.of(userMessage));
|
||||
|
||||
var promptOptions = FunctionCallingOptions.builder()
|
||||
.withFunctionCallbacks(List.of(FunctionCallback.builder()
|
||||
.functionCallbacks(List.of(FunctionCallback.builder()
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.description(
|
||||
"Get the weather in location. Return temperature in 36°F or 36°C format. Use multi-turn if needed.")
|
||||
@@ -279,8 +279,8 @@ class BedrockProxyChatModelIT {
|
||||
List<Message> messages = new ArrayList<>(List.of(userMessage));
|
||||
|
||||
var promptOptions = FunctionCallingOptions.builder()
|
||||
.withModel("anthropic.claude-3-5-sonnet-20240620-v1:0")
|
||||
.withFunctionCallbacks(List.of(FunctionCallback.builder()
|
||||
.model("anthropic.claude-3-5-sonnet-20240620-v1:0")
|
||||
.functionCallbacks(List.of(FunctionCallback.builder()
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.description(
|
||||
"Get the weather in location. Return temperature in 36°F or 36°C format. Use multi-turn if needed.")
|
||||
@@ -306,7 +306,7 @@ class BedrockProxyChatModelIT {
|
||||
String model = "anthropic.claude-3-5-sonnet-20240620-v1:0";
|
||||
// @formatter:off
|
||||
ChatResponse response = ChatClient.create(this.chatModel).prompt()
|
||||
.options(FunctionCallingOptions.builder().withModel(model).build())
|
||||
.options(FunctionCallingOptions.builder().model(model).build())
|
||||
.user("Tell me about 3 famous pirates from the Golden Age of Piracy and what they did")
|
||||
.call()
|
||||
.chatResponse();
|
||||
@@ -321,7 +321,7 @@ class BedrockProxyChatModelIT {
|
||||
String model = "anthropic.claude-3-5-sonnet-20240620-v1:0";
|
||||
// @formatter:off
|
||||
ChatResponse response = ChatClient.create(this.chatModel).prompt()
|
||||
.options(FunctionCallingOptions.builder().withModel(model).build())
|
||||
.options(FunctionCallingOptions.builder().model(model).build())
|
||||
.user("Tell me about 3 famous pirates from the Golden Age of Piracy and what they did")
|
||||
.stream()
|
||||
.chatResponse()
|
||||
|
||||
@@ -35,7 +35,6 @@ import org.springframework.ai.chat.observation.ChatModelObservationDocumentation
|
||||
import org.springframework.ai.chat.observation.DefaultChatModelObservationConvention;
|
||||
import org.springframework.ai.chat.prompt.Prompt;
|
||||
import org.springframework.ai.model.function.FunctionCallingOptions;
|
||||
import org.springframework.ai.model.function.FunctionCallingOptionsBuilder.PortableFunctionCallingOptions;
|
||||
import org.springframework.ai.observation.conventions.AiOperationType;
|
||||
import org.springframework.ai.observation.conventions.AiProvider;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -68,13 +67,13 @@ public class BedrockProxyChatModelObservationIT {
|
||||
|
||||
@Test
|
||||
void observationForChatOperation() {
|
||||
var options = PortableFunctionCallingOptions.builder()
|
||||
.withModel("anthropic.claude-3-5-sonnet-20240620-v1:0")
|
||||
.withMaxTokens(2048)
|
||||
.withStopSequences(List.of("this-is-the-end"))
|
||||
.withTemperature(0.7)
|
||||
var options = FunctionCallingOptions.builder()
|
||||
.model("anthropic.claude-3-5-sonnet-20240620-v1:0")
|
||||
.maxTokens(2048)
|
||||
.stopSequences(List.of("this-is-the-end"))
|
||||
.temperature(0.7)
|
||||
// .withTopK(1)
|
||||
.withTopP(1.0)
|
||||
.topP(1.0)
|
||||
.build();
|
||||
|
||||
Prompt prompt = new Prompt("Why does a raven look like a desk?", options);
|
||||
@@ -90,12 +89,12 @@ public class BedrockProxyChatModelObservationIT {
|
||||
|
||||
@Test
|
||||
void observationForStreamingChatOperation() {
|
||||
var options = PortableFunctionCallingOptions.builder()
|
||||
.withModel("anthropic.claude-3-5-sonnet-20240620-v1:0")
|
||||
.withMaxTokens(2048)
|
||||
.withStopSequences(List.of("this-is-the-end"))
|
||||
.withTemperature(0.7)
|
||||
.withTopP(1.0)
|
||||
var options = FunctionCallingOptions.builder()
|
||||
.model("anthropic.claude-3-5-sonnet-20240620-v1:0")
|
||||
.maxTokens(2048)
|
||||
.stopSequences(List.of("this-is-the-end"))
|
||||
.temperature(0.7)
|
||||
.topP(1.0)
|
||||
.build();
|
||||
|
||||
Prompt prompt = new Prompt("Why does a raven look like a desk?", options);
|
||||
@@ -174,7 +173,7 @@ public class BedrockProxyChatModelObservationIT {
|
||||
.withCredentialsProvider(EnvironmentVariableCredentialsProvider.create())
|
||||
.withRegion(Region.US_EAST_1)
|
||||
.withObservationRegistry(observationRegistry)
|
||||
.withDefaultOptions(FunctionCallingOptions.builder().withModel(modelId).build())
|
||||
.withDefaultOptions(FunctionCallingOptions.builder().model(modelId).build())
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
@@ -184,7 +184,7 @@ public class BedrockNovaChatClientIT {
|
||||
.withCredentialsProvider(EnvironmentVariableCredentialsProvider.create())
|
||||
.withRegion(Region.US_EAST_1)
|
||||
.withTimeout(Duration.ofSeconds(120))
|
||||
.withDefaultOptions(FunctionCallingOptions.builder().withModel(modelId).build())
|
||||
.withDefaultOptions(FunctionCallingOptions.builder().model(modelId).build())
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ 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.FunctionCallback;
|
||||
import org.springframework.ai.model.function.FunctionCallingOptionsBuilder.PortableFunctionCallingOptions;
|
||||
import org.springframework.ai.model.function.FunctionCallingOptions;
|
||||
|
||||
/**
|
||||
* Used for reverse engineering the protocol
|
||||
@@ -50,9 +50,9 @@ public final class BedrockConverseChatModelMain2 {
|
||||
// "What's the weather like in San Francisco, Tokyo, and Paris? Return the
|
||||
// temperature in Celsius.",
|
||||
"What's the weather like in Paris? Return the temperature in Celsius.",
|
||||
PortableFunctionCallingOptions.builder()
|
||||
.withModel(modelId)
|
||||
.withFunctionCallbacks(List.of(FunctionCallback.builder()
|
||||
FunctionCallingOptions.builder()
|
||||
.model(modelId)
|
||||
.functionCallbacks(List.of(FunctionCallback.builder()
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.description("Get the weather in location")
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
|
||||
@@ -25,7 +25,7 @@ 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.FunctionCallback;
|
||||
import org.springframework.ai.model.function.FunctionCallingOptionsBuilder.PortableFunctionCallingOptions;
|
||||
import org.springframework.ai.model.function.FunctionCallingOptions;
|
||||
|
||||
/**
|
||||
* Used for reverse engineering the protocol
|
||||
@@ -48,9 +48,9 @@ public final class BedrockConverseChatModelMain3 {
|
||||
// "What's the weather like in San Francisco, Tokyo, and Paris? Return the
|
||||
// temperature in Celsius.",
|
||||
"What's the weather like in Paris? Return the temperature in Celsius.",
|
||||
PortableFunctionCallingOptions.builder()
|
||||
.withModel(modelId)
|
||||
.withFunctionCallbacks(List.of(FunctionCallback.builder()
|
||||
FunctionCallingOptions.builder()
|
||||
.model(modelId)
|
||||
.functionCallbacks(List.of(FunctionCallback.builder()
|
||||
.function("getCurrentWeather", new MockWeatherService())
|
||||
.description("Get the weather in location")
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
|
||||
@@ -94,70 +94,70 @@ public interface ChatOptions extends ModelOptions {
|
||||
* {@link ChatOptions}.
|
||||
* @return Returns a new {@link ChatOptions.Builder}.
|
||||
*/
|
||||
static ChatOptions.Builder builder() {
|
||||
static ChatOptions.Builder<? extends DefaultChatOptionsBuilder> builder() {
|
||||
return new DefaultChatOptionsBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder for creating {@link ChatOptions} instance.
|
||||
*/
|
||||
interface Builder {
|
||||
interface Builder<B extends Builder<B>> {
|
||||
|
||||
/**
|
||||
* Builds with the model to use for the chat.
|
||||
* @param model
|
||||
* @return the builder
|
||||
*/
|
||||
Builder model(String model);
|
||||
B model(String model);
|
||||
|
||||
/**
|
||||
* Builds with the frequency penalty to use for the chat.
|
||||
* @param frequencyPenalty
|
||||
* @return the builder.
|
||||
*/
|
||||
Builder frequencyPenalty(Double frequencyPenalty);
|
||||
B frequencyPenalty(Double frequencyPenalty);
|
||||
|
||||
/**
|
||||
* Builds with the maximum number of tokens to use for the chat.
|
||||
* @param maxTokens
|
||||
* @return the builder.
|
||||
*/
|
||||
Builder maxTokens(Integer maxTokens);
|
||||
B maxTokens(Integer maxTokens);
|
||||
|
||||
/**
|
||||
* Builds with the presence penalty to use for the chat.
|
||||
* @param presencePenalty
|
||||
* @return the builder.
|
||||
*/
|
||||
Builder presencePenalty(Double presencePenalty);
|
||||
B presencePenalty(Double presencePenalty);
|
||||
|
||||
/**
|
||||
* Builds with the stop sequences to use for the chat.
|
||||
* @param stopSequences
|
||||
* @return the builder.
|
||||
*/
|
||||
Builder stopSequences(List<String> stopSequences);
|
||||
B stopSequences(List<String> stopSequences);
|
||||
|
||||
/**
|
||||
* Builds with the temperature to use for the chat.
|
||||
* @param temperature
|
||||
* @return the builder.
|
||||
*/
|
||||
Builder temperature(Double temperature);
|
||||
B temperature(Double temperature);
|
||||
|
||||
/**
|
||||
* Builds with the top K to use for the chat.
|
||||
* @param topK
|
||||
* @return the builder.
|
||||
*/
|
||||
Builder topK(Integer topK);
|
||||
B topK(Integer topK);
|
||||
|
||||
/**
|
||||
* Builds with the top P to use for the chat.
|
||||
* @param topP
|
||||
* @return the builder.
|
||||
*/
|
||||
Builder topP(Double topP);
|
||||
B topP(Double topP);
|
||||
|
||||
/**
|
||||
* Build the {@link ChatOptions}.
|
||||
|
||||
@@ -21,48 +21,52 @@ import java.util.List;
|
||||
/**
|
||||
* Implementation of {@link ChatOptions.Builder} to create {@link DefaultChatOptions}.
|
||||
*/
|
||||
public class DefaultChatOptionsBuilder implements ChatOptions.Builder {
|
||||
public class DefaultChatOptionsBuilder<T extends DefaultChatOptionsBuilder<T>> implements ChatOptions.Builder<T> {
|
||||
|
||||
private final DefaultChatOptions options = new DefaultChatOptions();
|
||||
|
||||
public ChatOptions.Builder model(String model) {
|
||||
protected T self() {
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
public T model(String model) {
|
||||
this.options.setModel(model);
|
||||
return this;
|
||||
return self();
|
||||
}
|
||||
|
||||
public ChatOptions.Builder frequencyPenalty(Double frequencyPenalty) {
|
||||
public T frequencyPenalty(Double frequencyPenalty) {
|
||||
this.options.setFrequencyPenalty(frequencyPenalty);
|
||||
return this;
|
||||
return self();
|
||||
}
|
||||
|
||||
public ChatOptions.Builder maxTokens(Integer maxTokens) {
|
||||
public T maxTokens(Integer maxTokens) {
|
||||
this.options.setMaxTokens(maxTokens);
|
||||
return this;
|
||||
return self();
|
||||
}
|
||||
|
||||
public ChatOptions.Builder presencePenalty(Double presencePenalty) {
|
||||
public T presencePenalty(Double presencePenalty) {
|
||||
this.options.setPresencePenalty(presencePenalty);
|
||||
return this;
|
||||
return self();
|
||||
}
|
||||
|
||||
public ChatOptions.Builder stopSequences(List<String> stop) {
|
||||
public T stopSequences(List<String> stop) {
|
||||
this.options.setStopSequences(stop);
|
||||
return this;
|
||||
return self();
|
||||
}
|
||||
|
||||
public ChatOptions.Builder temperature(Double temperature) {
|
||||
public T temperature(Double temperature) {
|
||||
this.options.setTemperature(temperature);
|
||||
return this;
|
||||
return self();
|
||||
}
|
||||
|
||||
public ChatOptions.Builder topK(Integer topK) {
|
||||
public T topK(Integer topK) {
|
||||
this.options.setTopK(topK);
|
||||
return this;
|
||||
return self();
|
||||
}
|
||||
|
||||
public ChatOptions.Builder topP(Double topP) {
|
||||
public T topP(Double topP) {
|
||||
this.options.setTopP(topP);
|
||||
return this;
|
||||
return self();
|
||||
}
|
||||
|
||||
public ChatOptions build() {
|
||||
|
||||
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright 2024-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.ai.model.function;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.ai.chat.prompt.ChatOptions;
|
||||
import org.springframework.ai.chat.prompt.DefaultChatOptions;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link FunctionCallingOptions}.
|
||||
*
|
||||
* @author Christian Tzolov
|
||||
* @author Thomas Vitale
|
||||
* @author Ilayaperumal Gopinathan
|
||||
*/
|
||||
public class DefaultFunctionCallingOptions extends DefaultChatOptions implements FunctionCallingOptions {
|
||||
|
||||
private List<FunctionCallback> functionCallbacks = new ArrayList<>();
|
||||
|
||||
private Set<String> functions = new HashSet<>();
|
||||
|
||||
private Boolean proxyToolCalls = false;
|
||||
|
||||
private Map<String, Object> context = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public List<FunctionCallback> getFunctionCallbacks() {
|
||||
return Collections.unmodifiableList(this.functionCallbacks);
|
||||
}
|
||||
|
||||
public void setFunctionCallbacks(List<FunctionCallback> functionCallbacks) {
|
||||
Assert.notNull(functionCallbacks, "FunctionCallbacks must not be null");
|
||||
this.functionCallbacks = new ArrayList<>(functionCallbacks);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getFunctions() {
|
||||
return Collections.unmodifiableSet(this.functions);
|
||||
}
|
||||
|
||||
public void setFunctions(Set<String> functions) {
|
||||
Assert.notNull(functions, "Functions must not be null");
|
||||
this.functions = new HashSet<>(functions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean getProxyToolCalls() {
|
||||
return this.proxyToolCalls;
|
||||
}
|
||||
|
||||
public void setProxyToolCalls(Boolean proxyToolCalls) {
|
||||
this.proxyToolCalls = proxyToolCalls;
|
||||
}
|
||||
|
||||
public Map<String, Object> getToolContext() {
|
||||
return Collections.unmodifiableMap(this.context);
|
||||
}
|
||||
|
||||
public void setToolContext(Map<String, Object> context) {
|
||||
Assert.notNull(context, "Context must not be null");
|
||||
this.context = new HashMap<>(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FunctionCallingOptions copy() {
|
||||
return FunctionCallingOptions.builder()
|
||||
.model(this.getModel())
|
||||
.frequencyPenalty(this.getFrequencyPenalty())
|
||||
.maxTokens(this.getMaxTokens())
|
||||
.presencePenalty(this.getPresencePenalty())
|
||||
.stopSequences(this.getStopSequences() != null ? new ArrayList<>(this.getStopSequences()) : null)
|
||||
.temperature(this.getTemperature())
|
||||
.topK(this.getTopK())
|
||||
.topP(this.getTopP())
|
||||
.functions(new HashSet<>(this.functions))
|
||||
.functionCallbacks(new ArrayList<>(this.functionCallbacks))
|
||||
.proxyToolCalls(this.proxyToolCalls)
|
||||
.toolContext(new HashMap<>(this.getToolContext()))
|
||||
.build();
|
||||
}
|
||||
|
||||
public FunctionCallingOptions merge(FunctionCallingOptions options) {
|
||||
|
||||
var builder = FunctionCallingOptions.builder()
|
||||
.model(StringUtils.hasText(options.getModel()) ? options.getModel() : this.getModel())
|
||||
.frequencyPenalty(
|
||||
options.getFrequencyPenalty() != null ? options.getFrequencyPenalty() : this.getFrequencyPenalty())
|
||||
.maxTokens(options.getMaxTokens() != null ? options.getMaxTokens() : this.getMaxTokens())
|
||||
.presencePenalty(
|
||||
options.getPresencePenalty() != null ? options.getPresencePenalty() : this.getPresencePenalty())
|
||||
.stopSequences(options.getStopSequences() != null ? options.getStopSequences() : this.getStopSequences())
|
||||
.temperature(options.getTemperature() != null ? options.getTemperature() : this.getTemperature())
|
||||
.topK(options.getTopK() != null ? options.getTopK() : this.getTopK())
|
||||
.topP(options.getTopP() != null ? options.getTopP() : this.getTopP());
|
||||
|
||||
builder.proxyToolCalls(options.getProxyToolCalls() != null ? options.getProxyToolCalls() : this.proxyToolCalls);
|
||||
|
||||
Set<String> functions = new HashSet<>();
|
||||
if (!CollectionUtils.isEmpty(this.functions)) {
|
||||
functions.addAll(this.functions);
|
||||
}
|
||||
if (!CollectionUtils.isEmpty(options.getFunctions())) {
|
||||
functions.addAll(options.getFunctions());
|
||||
}
|
||||
builder.functions(functions);
|
||||
|
||||
List<FunctionCallback> functionCallbacks = new ArrayList<>();
|
||||
if (!CollectionUtils.isEmpty(this.functionCallbacks)) {
|
||||
functionCallbacks.addAll(this.functionCallbacks);
|
||||
}
|
||||
if (!CollectionUtils.isEmpty(options.getFunctionCallbacks())) {
|
||||
functionCallbacks.addAll(options.getFunctionCallbacks());
|
||||
}
|
||||
builder.functionCallbacks(functionCallbacks);
|
||||
|
||||
Map<String, Object> context = new HashMap<>();
|
||||
if (!CollectionUtils.isEmpty(this.context)) {
|
||||
context.putAll(this.context);
|
||||
}
|
||||
if (!CollectionUtils.isEmpty(options.getToolContext())) {
|
||||
context.putAll(options.getToolContext());
|
||||
}
|
||||
builder.toolContext(context);
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
public FunctionCallingOptions merge(ChatOptions options) {
|
||||
|
||||
var builder = FunctionCallingOptions.builder()
|
||||
.model(StringUtils.hasText(options.getModel()) ? options.getModel() : this.getModel())
|
||||
.frequencyPenalty(
|
||||
options.getFrequencyPenalty() != null ? options.getFrequencyPenalty() : this.getFrequencyPenalty())
|
||||
.maxTokens(options.getMaxTokens() != null ? options.getMaxTokens() : this.getMaxTokens())
|
||||
.presencePenalty(
|
||||
options.getPresencePenalty() != null ? options.getPresencePenalty() : this.getPresencePenalty())
|
||||
.stopSequences(options.getStopSequences() != null ? options.getStopSequences() : this.getStopSequences())
|
||||
.temperature(options.getTemperature() != null ? options.getTemperature() : this.getTemperature())
|
||||
.topK(options.getTopK() != null ? options.getTopK() : this.getTopK())
|
||||
.topP(options.getTopP() != null ? options.getTopP() : this.getTopP());
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright 2024-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.ai.model.function;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.ai.chat.prompt.DefaultChatOptionsBuilder;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link FunctionCallingOptions.Builder}.
|
||||
*
|
||||
* @author Christian Tzolov
|
||||
* @author Thomas Vitale
|
||||
* @author Ilayaperumal Gopinathan
|
||||
*/
|
||||
public class DefaultFunctionCallingOptionsBuilder
|
||||
extends DefaultChatOptionsBuilder<DefaultFunctionCallingOptionsBuilder>
|
||||
implements FunctionCallingOptions.Builder<DefaultFunctionCallingOptionsBuilder> {
|
||||
|
||||
private final DefaultFunctionCallingOptions functionCallingOptions = new DefaultFunctionCallingOptions();
|
||||
|
||||
public DefaultFunctionCallingOptionsBuilder functionCallbacks(List<FunctionCallback> functionCallbacks) {
|
||||
this.functionCallingOptions.setFunctionCallbacks(functionCallbacks);
|
||||
return this;
|
||||
}
|
||||
|
||||
public DefaultFunctionCallingOptionsBuilder functionCallbacks(FunctionCallback... functionCallbacks) {
|
||||
Assert.notNull(functionCallbacks, "FunctionCallbacks must not be null");
|
||||
this.functionCallingOptions.setFunctionCallbacks(List.of(functionCallbacks));
|
||||
return this;
|
||||
}
|
||||
|
||||
public DefaultFunctionCallingOptionsBuilder functions(Set<String> functions) {
|
||||
this.functionCallingOptions.setFunctions(functions);
|
||||
return this;
|
||||
}
|
||||
|
||||
public DefaultFunctionCallingOptionsBuilder function(String function) {
|
||||
Assert.notNull(function, "Function must not be null");
|
||||
var set = new HashSet<>(this.functionCallingOptions.getFunctions());
|
||||
set.add(function);
|
||||
this.functionCallingOptions.setFunctions(set);
|
||||
return this;
|
||||
}
|
||||
|
||||
public DefaultFunctionCallingOptionsBuilder proxyToolCalls(Boolean proxyToolCalls) {
|
||||
this.functionCallingOptions.setProxyToolCalls(proxyToolCalls);
|
||||
return this;
|
||||
}
|
||||
|
||||
public DefaultFunctionCallingOptionsBuilder toolContext(Map<String, Object> context) {
|
||||
Assert.notNull(context, "Tool context must not be null");
|
||||
Map<String, Object> newContext = new HashMap<>(this.functionCallingOptions.getToolContext());
|
||||
newContext.putAll(context);
|
||||
this.functionCallingOptions.setToolContext(newContext);
|
||||
return this;
|
||||
}
|
||||
|
||||
public DefaultFunctionCallingOptionsBuilder toolContext(String key, Object value) {
|
||||
Assert.notNull(key, "Key must not be null");
|
||||
Assert.notNull(value, "Value must not be null");
|
||||
Map<String, Object> newContext = new HashMap<>(this.functionCallingOptions.getToolContext());
|
||||
newContext.put(key, value);
|
||||
this.functionCallingOptions.setToolContext(newContext);
|
||||
return this;
|
||||
}
|
||||
|
||||
public FunctionCallingOptions build() {
|
||||
return this.functionCallingOptions;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -34,7 +34,6 @@ 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.ModelOptionsUtils;
|
||||
import org.springframework.ai.model.function.FunctionCallingOptionsBuilder.PortableFunctionCallingOptions;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
@@ -45,7 +44,7 @@ import org.springframework.util.CollectionUtils;
|
||||
public class FunctionCallingHelper extends AbstractToolCallSupport {
|
||||
|
||||
public FunctionCallingHelper() {
|
||||
this(null, PortableFunctionCallingOptions.builder().build(), List.of());
|
||||
this(null, FunctionCallingOptions.builder().build(), List.of());
|
||||
}
|
||||
|
||||
public FunctionCallingHelper(FunctionCallbackResolver functionCallbackResolver,
|
||||
|
||||
@@ -27,15 +27,16 @@ import org.springframework.ai.chat.prompt.ChatOptions;
|
||||
* calling behavior of the ChatModel.
|
||||
*
|
||||
* @author Christian Tzolov
|
||||
* @author Ilayaperumal Gopinathan
|
||||
*/
|
||||
public interface FunctionCallingOptions extends ChatOptions {
|
||||
|
||||
/**
|
||||
* @return Returns FunctionCallingOptionsBuilder to create a new instance of
|
||||
* FunctionCallingOptions.
|
||||
* @return Returns {@link DefaultFunctionCallingOptionsBuilder} to create a new
|
||||
* instance of {@link FunctionCallingOptions}.
|
||||
*/
|
||||
static FunctionCallingOptionsBuilder builder() {
|
||||
return new FunctionCallingOptionsBuilder();
|
||||
static FunctionCallingOptions.Builder<? extends FunctionCallingOptions.Builder> builder() {
|
||||
return new DefaultFunctionCallingOptionsBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -83,4 +84,67 @@ public interface FunctionCallingOptions extends ChatOptions {
|
||||
|
||||
void setToolContext(Map<String, Object> tooContext);
|
||||
|
||||
/**
|
||||
* Builder for creating {@link FunctionCallingOptions} instance.
|
||||
*/
|
||||
interface Builder<T extends Builder<T>> extends ChatOptions.Builder<T> {
|
||||
|
||||
/**
|
||||
* The list of Function Callbacks to be registered with the Chat model.
|
||||
* @param functionCallbacks the list of Function Callbacks.
|
||||
* @return the FunctionCallOptions Builder.
|
||||
*/
|
||||
T functionCallbacks(List<FunctionCallback> functionCallbacks);
|
||||
|
||||
/**
|
||||
* The Function Callbacks to be registered with the Chat model.
|
||||
* @param functionCallbacks the function callbacks.
|
||||
* @return the FunctionCallOptions Builder.
|
||||
*/
|
||||
T functionCallbacks(FunctionCallback... functionCallbacks);
|
||||
|
||||
/**
|
||||
* {@link Set} of function names to be registered with the Chat model.
|
||||
* @param functions the {@link Set} of function names
|
||||
* @return the FunctionCallOptions Builder.
|
||||
*/
|
||||
T functions(Set<String> functions);
|
||||
|
||||
/**
|
||||
* The function name to be registered with the chat model.
|
||||
* @param function the name of the function.
|
||||
* @return the FunctionCallOptions Builder.
|
||||
*/
|
||||
T function(String function);
|
||||
|
||||
/**
|
||||
* Boolean flag to indicate if the proxy ToolCalls is enabled.
|
||||
* @param proxyToolCalls boolean value to enable proxy ToolCalls.
|
||||
* @return the FunctionCallOptions Builder.
|
||||
*/
|
||||
T proxyToolCalls(Boolean proxyToolCalls);
|
||||
|
||||
/**
|
||||
* Add a {@link Map} of context values into tool context.
|
||||
* @param context the map representing the tool context.
|
||||
* @return the FunctionCallOptions Builder.
|
||||
*/
|
||||
T toolContext(Map<String, Object> context);
|
||||
|
||||
/**
|
||||
* Add a specific key/value pair to the tool context.
|
||||
* @param key the key to use.
|
||||
* @param value the corresponding value.
|
||||
* @return the FunctionCallOptions Builder.
|
||||
*/
|
||||
T toolContext(String key, Object value);
|
||||
|
||||
/**
|
||||
* Builds the {@link FunctionCallingOptions}.
|
||||
* @return the FunctionCalling options.
|
||||
*/
|
||||
FunctionCallingOptions build();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -34,10 +34,12 @@ import org.springframework.util.StringUtils;
|
||||
* permits options portability between different AI providers that support
|
||||
* function-calling.
|
||||
*
|
||||
* @deprecated Use {@link FunctionCallingOptions.Builder} instead.
|
||||
* @author Christian Tzolov
|
||||
* @author Thomas Vitale
|
||||
* @since 0.8.1
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "1.0.0-M5")
|
||||
public class FunctionCallingOptionsBuilder {
|
||||
|
||||
private final PortableFunctionCallingOptions options;
|
||||
@@ -136,6 +138,10 @@ public class FunctionCallingOptionsBuilder {
|
||||
return this.options;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use {@link DefaultFunctionCallingOptions} instead.
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "1.0.0-M5")
|
||||
public static class PortableFunctionCallingOptions implements FunctionCallingOptions {
|
||||
|
||||
private List<FunctionCallback> functionCallbacks = new ArrayList<>();
|
||||
|
||||
@@ -86,11 +86,11 @@ public class ChatBuilderTests {
|
||||
functionCallbacks.add(cb);
|
||||
|
||||
FunctionCallingOptions options = FunctionCallingOptions.builder()
|
||||
.withFunctionCallbacks(functionCallbacks)
|
||||
.withFunctions(functions)
|
||||
.withTopK(topK)
|
||||
.withTopP(topP)
|
||||
.withTemperature(temperature)
|
||||
.functionCallbacks(functionCallbacks)
|
||||
.functions(functions)
|
||||
.topK(topK)
|
||||
.topP(topP)
|
||||
.temperature(temperature)
|
||||
.build();
|
||||
|
||||
// Callback Functions
|
||||
|
||||
@@ -40,10 +40,9 @@ 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.Media;
|
||||
import org.springframework.ai.model.function.DefaultFunctionCallingOptions;
|
||||
import org.springframework.ai.model.function.FunctionCallback;
|
||||
import org.springframework.ai.model.function.FunctionCallingOptions;
|
||||
import org.springframework.ai.model.function.FunctionCallingOptionsBuilder;
|
||||
import org.springframework.ai.model.function.FunctionCallingOptionsBuilder.PortableFunctionCallingOptions;
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
import org.springframework.util.MimeTypeUtils;
|
||||
|
||||
@@ -199,7 +198,7 @@ public class ChatClientTest {
|
||||
@Test
|
||||
void mutateDefaults() {
|
||||
|
||||
PortableFunctionCallingOptions options = new FunctionCallingOptionsBuilder().build();
|
||||
FunctionCallingOptions options = new DefaultFunctionCallingOptions();
|
||||
given(this.chatModel.getDefaultOptions()).willReturn(options);
|
||||
|
||||
given(this.chatModel.call(this.promptCaptor.capture()))
|
||||
@@ -331,7 +330,7 @@ public class ChatClientTest {
|
||||
@Test
|
||||
void mutatePrompt() {
|
||||
|
||||
PortableFunctionCallingOptions options = new FunctionCallingOptionsBuilder().build();
|
||||
FunctionCallingOptions options = new DefaultFunctionCallingOptions();
|
||||
given(this.chatModel.getDefaultOptions()).willReturn(options);
|
||||
|
||||
given(this.chatModel.call(this.promptCaptor.capture()))
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
package org.springframework.ai.autoconfigure.bedrock.converse;
|
||||
|
||||
import org.springframework.ai.model.function.FunctionCallingOptionsBuilder.PortableFunctionCallingOptions;
|
||||
import org.springframework.ai.model.function.FunctionCallingOptions;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -38,10 +38,10 @@ public class BedrockConverseProxyChatProperties {
|
||||
private boolean enabled = true;
|
||||
|
||||
@NestedConfigurationProperty
|
||||
private PortableFunctionCallingOptions options = PortableFunctionCallingOptions.builder()
|
||||
.withTemperature(0.7)
|
||||
.withMaxTokens(300)
|
||||
.withTopK(10)
|
||||
private FunctionCallingOptions options = FunctionCallingOptions.builder()
|
||||
.temperature(0.7)
|
||||
.maxTokens(300)
|
||||
.topK(10)
|
||||
.build();
|
||||
|
||||
public boolean isEnabled() {
|
||||
@@ -52,12 +52,12 @@ public class BedrockConverseProxyChatProperties {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public PortableFunctionCallingOptions getOptions() {
|
||||
public FunctionCallingOptions getOptions() {
|
||||
return this.options;
|
||||
}
|
||||
|
||||
public void setOptions(PortableFunctionCallingOptions options) {
|
||||
Assert.notNull(options, "PortableFunctionCallingOptions must not be null");
|
||||
public void setOptions(FunctionCallingOptions options) {
|
||||
Assert.notNull(options, "FunctionCallingOptions must not be null");
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ import org.springframework.ai.autoconfigure.anthropic.tool.MockWeatherService.Re
|
||||
import org.springframework.ai.chat.messages.UserMessage;
|
||||
import org.springframework.ai.chat.model.ChatResponse;
|
||||
import org.springframework.ai.chat.prompt.Prompt;
|
||||
import org.springframework.ai.model.function.FunctionCallingOptionsBuilder.PortableFunctionCallingOptions;
|
||||
import org.springframework.ai.model.function.FunctionCallingOptions;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@@ -96,7 +96,7 @@ class FunctionCallWithFunctionBeanIT {
|
||||
"What's the weather like in San Francisco, in Paris, France and in Tokyo, Japan? Return the temperature in Celsius.");
|
||||
|
||||
ChatResponse response = chatModel.call(new Prompt(List.of(userMessage),
|
||||
PortableFunctionCallingOptions.builder().withFunction("weatherFunction").build()));
|
||||
FunctionCallingOptions.builder().function("weatherFunction").build()));
|
||||
|
||||
logger.info("Response: {}", response);
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ import org.springframework.ai.chat.messages.UserMessage;
|
||||
import org.springframework.ai.chat.model.ChatModel;
|
||||
import org.springframework.ai.chat.model.ChatResponse;
|
||||
import org.springframework.ai.chat.prompt.Prompt;
|
||||
import org.springframework.ai.model.function.FunctionCallingOptionsBuilder.PortableFunctionCallingOptions;
|
||||
import org.springframework.ai.model.function.FunctionCallingOptions;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@@ -96,7 +96,7 @@ class FunctionCallWithFunctionBeanIT {
|
||||
"What's the weather like in San Francisco, Paris and in Tokyo? Use Multi-turn function calling.");
|
||||
|
||||
ChatResponse response = chatModel.call(new Prompt(List.of(userMessage),
|
||||
PortableFunctionCallingOptions.builder().withFunction("weatherFunction").build()));
|
||||
FunctionCallingOptions.builder().function("weatherFunction").build()));
|
||||
|
||||
logger.info("Response: {}", response);
|
||||
|
||||
|
||||
@@ -33,7 +33,6 @@ import org.springframework.ai.chat.messages.UserMessage;
|
||||
import org.springframework.ai.chat.model.ChatResponse;
|
||||
import org.springframework.ai.chat.prompt.Prompt;
|
||||
import org.springframework.ai.model.function.FunctionCallingOptions;
|
||||
import org.springframework.ai.model.function.FunctionCallingOptionsBuilder.PortableFunctionCallingOptions;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@@ -65,14 +64,14 @@ class FunctionCallWithFunctionBeanIT {
|
||||
"What's the weather like in San Francisco, in Paris, France and in Tokyo, Japan? Return the temperature in Celsius.");
|
||||
|
||||
ChatResponse response = chatModel.call(new Prompt(List.of(userMessage),
|
||||
PortableFunctionCallingOptions.builder().withFunction("weatherFunction").build()));
|
||||
FunctionCallingOptions.builder().function("weatherFunction").build()));
|
||||
|
||||
logger.info("Response: {}", response);
|
||||
|
||||
assertThat(response.getResult().getOutput().getText()).contains("30", "10", "15");
|
||||
|
||||
response = chatModel.call(new Prompt(List.of(userMessage),
|
||||
FunctionCallingOptions.builder().withFunction("weatherFunction3").build()));
|
||||
FunctionCallingOptions.builder().function("weatherFunction3").build()));
|
||||
|
||||
logger.info("Response: {}", response);
|
||||
|
||||
@@ -94,7 +93,7 @@ class FunctionCallWithFunctionBeanIT {
|
||||
"What's the weather like in San Francisco, in Paris, France and in Tokyo, Japan? Return the temperature in Celsius.");
|
||||
|
||||
Flux<ChatResponse> responses = chatModel.stream(new Prompt(List.of(userMessage),
|
||||
FunctionCallingOptions.builder().withFunction("weatherFunction").build()));
|
||||
FunctionCallingOptions.builder().function("weatherFunction").build()));
|
||||
|
||||
String content = responses.collectList()
|
||||
.block()
|
||||
|
||||
@@ -57,7 +57,7 @@ public class FunctionCallWithPromptFunctionIT {
|
||||
"What's the weather like in San Francisco, in Paris and in Tokyo? Return the temperature in Celsius.");
|
||||
|
||||
var promptOptions = FunctionCallingOptions.builder()
|
||||
.withFunctionCallbacks(List.of(FunctionCallback.builder()
|
||||
.functionCallbacks(List.of(FunctionCallback.builder()
|
||||
.function("CurrentWeatherService", new MockWeatherService())
|
||||
.description("Get the weather in location. Return temperature in 36°F or 36°C format.")
|
||||
.inputType(MockWeatherService.Request.class)
|
||||
|
||||
@@ -35,7 +35,6 @@ import org.springframework.ai.chat.prompt.Prompt;
|
||||
import org.springframework.ai.minimax.MiniMaxChatModel;
|
||||
import org.springframework.ai.minimax.MiniMaxChatOptions;
|
||||
import org.springframework.ai.model.function.FunctionCallingOptions;
|
||||
import org.springframework.ai.model.function.FunctionCallingOptionsBuilder.PortableFunctionCallingOptions;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
@@ -98,8 +97,8 @@ class FunctionCallbackWithPlainFunctionBeanIT {
|
||||
UserMessage userMessage = new UserMessage(
|
||||
"What's the weather like in San Francisco, Tokyo, and Paris? Return the temperature in Celsius.");
|
||||
|
||||
PortableFunctionCallingOptions functionOptions = FunctionCallingOptions.builder()
|
||||
.withFunction("weatherFunction")
|
||||
FunctionCallingOptions functionOptions = FunctionCallingOptions.builder()
|
||||
.function("weatherFunction")
|
||||
.build();
|
||||
|
||||
ChatResponse response = chatModel.call(new Prompt(List.of(userMessage), functionOptions));
|
||||
|
||||
@@ -39,7 +39,6 @@ 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.ai.model.function.FunctionCallingOptions;
|
||||
import org.springframework.ai.model.function.FunctionCallingOptionsBuilder.PortableFunctionCallingOptions;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
|
||||
@@ -98,8 +97,8 @@ public class WeatherServicePromptIT {
|
||||
|
||||
UserMessage userMessage = new UserMessage("What's the weather like in Paris? Use Celsius.");
|
||||
|
||||
PortableFunctionCallingOptions functionOptions = FunctionCallingOptions.builder()
|
||||
.withFunctionCallbacks(List.of(FunctionCallback.builder()
|
||||
FunctionCallingOptions functionOptions = FunctionCallingOptions.builder()
|
||||
.functionCallbacks(List.of(FunctionCallback.builder()
|
||||
.function("CurrentWeatherService", new MyWeatherService())
|
||||
.description("Get the current weather in requested location")
|
||||
.inputType(MyWeatherService.Request.class)
|
||||
|
||||
@@ -34,7 +34,6 @@ 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.FunctionCallingOptions;
|
||||
import org.springframework.ai.model.function.FunctionCallingOptionsBuilder.PortableFunctionCallingOptions;
|
||||
import org.springframework.ai.moonshot.MoonshotChatModel;
|
||||
import org.springframework.ai.moonshot.MoonshotChatOptions;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
@@ -98,8 +97,8 @@ class FunctionCallbackWithPlainFunctionBeanIT {
|
||||
UserMessage userMessage = new UserMessage(
|
||||
"What's the weather like in San Francisco, Tokyo, and Paris? Return the temperature in Celsius");
|
||||
|
||||
PortableFunctionCallingOptions functionOptions = FunctionCallingOptions.builder()
|
||||
.withFunction("weatherFunction")
|
||||
FunctionCallingOptions functionOptions = FunctionCallingOptions.builder()
|
||||
.function("weatherFunction")
|
||||
.build();
|
||||
|
||||
ChatResponse response = chatModel.call(new Prompt(List.of(userMessage), functionOptions));
|
||||
|
||||
@@ -20,7 +20,6 @@ import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -35,7 +34,6 @@ 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.FunctionCallingOptions;
|
||||
import org.springframework.ai.model.function.FunctionCallingOptionsBuilder.PortableFunctionCallingOptions;
|
||||
import org.springframework.ai.ollama.OllamaChatModel;
|
||||
import org.springframework.ai.ollama.api.OllamaOptions;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
@@ -120,9 +118,7 @@ public class OllamaFunctionCallbackIT extends BaseOllamaIT {
|
||||
UserMessage userMessage = new UserMessage(
|
||||
"What are the weather conditions in San Francisco, Tokyo, and Paris? Find the temperature in Celsius for each of the three locations.");
|
||||
|
||||
PortableFunctionCallingOptions functionOptions = FunctionCallingOptions.builder()
|
||||
.withFunction("WeatherInfo")
|
||||
.build();
|
||||
FunctionCallingOptions functionOptions = FunctionCallingOptions.builder().function("WeatherInfo").build();
|
||||
|
||||
ChatResponse response = chatModel.call(new Prompt(List.of(userMessage), functionOptions));
|
||||
|
||||
|
||||
@@ -41,7 +41,6 @@ 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.FunctionCallingOptions;
|
||||
import org.springframework.ai.model.function.FunctionCallingOptionsBuilder.PortableFunctionCallingOptions;
|
||||
import org.springframework.ai.openai.OpenAiChatModel;
|
||||
import org.springframework.ai.openai.OpenAiChatOptions;
|
||||
import org.springframework.ai.openai.api.OpenAiApi.ChatModel;
|
||||
@@ -156,8 +155,8 @@ class FunctionCallbackWithPlainFunctionBeanIT {
|
||||
UserMessage userMessage = new UserMessage(
|
||||
"Please schedule a train from San Francisco to Los Angeles on 2023-12-25");
|
||||
|
||||
PortableFunctionCallingOptions functionOptions = FunctionCallingOptions.builder()
|
||||
.withFunction("trainReservation")
|
||||
FunctionCallingOptions functionOptions = FunctionCallingOptions.builder()
|
||||
.function("trainReservation")
|
||||
.build();
|
||||
|
||||
ChatResponse response = chatModel.call(new Prompt(List.of(userMessage), functionOptions));
|
||||
@@ -267,8 +266,8 @@ class FunctionCallbackWithPlainFunctionBeanIT {
|
||||
// Test weatherFunction
|
||||
UserMessage userMessage = new UserMessage("What's the weather like in San Francisco, Tokyo, and Paris?");
|
||||
|
||||
PortableFunctionCallingOptions functionOptions = FunctionCallingOptions.builder()
|
||||
.withFunction("weatherFunction")
|
||||
FunctionCallingOptions functionOptions = FunctionCallingOptions.builder()
|
||||
.function("weatherFunction")
|
||||
.build();
|
||||
|
||||
ChatResponse response = chatModel.call(new Prompt(List.of(userMessage), functionOptions));
|
||||
|
||||
@@ -28,7 +28,7 @@ import org.springframework.ai.autoconfigure.vertexai.gemini.VertexAiGeminiAutoCo
|
||||
import org.springframework.ai.chat.messages.UserMessage;
|
||||
import org.springframework.ai.chat.model.ChatResponse;
|
||||
import org.springframework.ai.chat.prompt.Prompt;
|
||||
import org.springframework.ai.model.function.FunctionCallingOptionsBuilder.PortableFunctionCallingOptions;
|
||||
import org.springframework.ai.model.function.FunctionCallingOptions;
|
||||
import org.springframework.ai.vertexai.gemini.VertexAiGeminiChatModel;
|
||||
import org.springframework.ai.vertexai.gemini.VertexAiGeminiChatOptions;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
@@ -109,7 +109,7 @@ class FunctionCallWithFunctionBeanIT {
|
||||
""");
|
||||
|
||||
ChatResponse response = chatModel.call(new Prompt(List.of(userMessage),
|
||||
PortableFunctionCallingOptions.builder().withFunction("weatherFunction").build()));
|
||||
FunctionCallingOptions.builder().function("weatherFunction").build()));
|
||||
|
||||
logger.info("Response: {}", response);
|
||||
|
||||
|
||||
@@ -34,7 +34,6 @@ 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.FunctionCallingOptions;
|
||||
import org.springframework.ai.model.function.FunctionCallingOptionsBuilder.PortableFunctionCallingOptions;
|
||||
import org.springframework.ai.zhipuai.ZhiPuAiChatModel;
|
||||
import org.springframework.ai.zhipuai.ZhiPuAiChatOptions;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
@@ -98,8 +97,8 @@ class FunctionCallbackWithPlainFunctionBeanIT {
|
||||
UserMessage userMessage = new UserMessage(
|
||||
"What's the weather like in San Francisco, Tokyo, and Paris? Return the temperature in Celsius.");
|
||||
|
||||
PortableFunctionCallingOptions functionOptions = FunctionCallingOptions.builder()
|
||||
.withFunction("weatherFunction")
|
||||
FunctionCallingOptions functionOptions = FunctionCallingOptions.builder()
|
||||
.function("weatherFunction")
|
||||
.build();
|
||||
|
||||
ChatResponse response = chatModel.call(new Prompt(List.of(userMessage), functionOptions));
|
||||
|
||||
@@ -89,7 +89,7 @@ class FunctionCallbackResolverKotlinIT : BaseOllamaIT() {
|
||||
"What are the weather conditions in San Francisco, Tokyo, and Paris? Find the temperature in Celsius for each of the three locations.")
|
||||
|
||||
val functionOptions = FunctionCallingOptions.builder()
|
||||
.withFunction("weatherInfo")
|
||||
.function("weatherInfo")
|
||||
.build()
|
||||
|
||||
val response = chatModel.call(Prompt(listOf(userMessage), functionOptions));
|
||||
|
||||
@@ -89,7 +89,7 @@ class FunctionCallbackKotlinIT : BaseOllamaIT() {
|
||||
"What are the weather conditions in San Francisco, Tokyo, and Paris? Find the temperature in Celsius for each of the three locations.")
|
||||
|
||||
val functionOptions = FunctionCallingOptions.builder()
|
||||
.withFunction("WeatherInfo")
|
||||
.function("WeatherInfo")
|
||||
.build()
|
||||
|
||||
val response = chatModel.call(Prompt(listOf(userMessage), functionOptions));
|
||||
|
||||
Reference in New Issue
Block a user