refactor: introduce FunctionCallbackResolver interface

- Introduces a new FunctionCallbackResolver interface to define the strategy for
  resolving FunctionCallback instances.
- Renames FunctionCallbackContext to DefaultFunctionCallbackResolver to better reflect its
  implementation role. Updates all related components to use the new interface.
- Update the affected AI model implementations
  - Replaces FunctionCallbackContext parameter with FunctionCallbackResolver in all
    model constructors
  - Updates builder patterns to use functionCallbackResolver() method instead of
    withFunctionCallbackContext()
  - Deprecates old withFunctionCallbackContext() methods in builders to guide
    migration
- Updates integration tests to use DefaultFunctionCallbackResolver
- Improves documentation to clarify the resolver's role in function callbacks
- Moves SchemaType enum from FunctionCallbackContext to FunctionCallback

Resolves #758
This commit is contained in:
Christian Tzolov
2024-11-23 11:22:36 +01:00
committed by Ilayaperumal Gopinathan
parent 308d8d4cc2
commit 479a095976
43 changed files with 291 additions and 206 deletions

View File

@@ -62,7 +62,7 @@ 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.FunctionCallback;
import org.springframework.ai.model.function.FunctionCallbackContext;
import org.springframework.ai.model.function.FunctionCallbackResolver;
import org.springframework.ai.model.function.FunctionCallingOptions;
import org.springframework.ai.retry.RetryUtils;
import org.springframework.http.ResponseEntity;
@@ -156,13 +156,13 @@ public class AnthropicChatModel extends AbstractToolCallSupport implements ChatM
* @param anthropicApi the lower-level API for the Anthropic service.
* @param defaultOptions the default options used for the chat completion requests.
* @param retryTemplate the retry template used to retry the Anthropic API calls.
* @param functionCallbackContext the function callback context used to store the
* state of the function calls.
* @param functionCallbackResolver the function callback resolver used to resolve the
* function by its name.
*/
public AnthropicChatModel(AnthropicApi anthropicApi, AnthropicChatOptions defaultOptions,
RetryTemplate retryTemplate, FunctionCallbackContext functionCallbackContext) {
RetryTemplate retryTemplate, FunctionCallbackResolver functionCallbackResolver) {
this(anthropicApi, defaultOptions, retryTemplate, functionCallbackContext, List.of());
this(anthropicApi, defaultOptions, retryTemplate, functionCallbackResolver, List.of());
}
/**
@@ -170,15 +170,15 @@ public class AnthropicChatModel extends AbstractToolCallSupport implements ChatM
* @param anthropicApi the lower-level API for the Anthropic service.
* @param defaultOptions the default options used for the chat completion requests.
* @param retryTemplate the retry template used to retry the Anthropic API calls.
* @param functionCallbackContext the function callback context used to store the
* state of the function calls.
* @param functionCallbackResolver the function callback resolver used to resolve the
* function by its name.
* @param toolFunctionCallbacks the tool function callbacks used to handle the tool
* calls.
*/
public AnthropicChatModel(AnthropicApi anthropicApi, AnthropicChatOptions defaultOptions,
RetryTemplate retryTemplate, FunctionCallbackContext functionCallbackContext,
RetryTemplate retryTemplate, FunctionCallbackResolver functionCallbackResolver,
List<FunctionCallback> toolFunctionCallbacks) {
this(anthropicApi, defaultOptions, retryTemplate, functionCallbackContext, toolFunctionCallbacks,
this(anthropicApi, defaultOptions, retryTemplate, functionCallbackResolver, toolFunctionCallbacks,
ObservationRegistry.NOOP);
}
@@ -187,16 +187,16 @@ public class AnthropicChatModel extends AbstractToolCallSupport implements ChatM
* @param anthropicApi the lower-level API for the Anthropic service.
* @param defaultOptions the default options used for the chat completion requests.
* @param retryTemplate the retry template used to retry the Anthropic API calls.
* @param functionCallbackContext the function callback context used to store the
* state of the function calls.
* @param functionCallbackResolver the function callback resolver used to resolve the
* function by its name.
* @param toolFunctionCallbacks the tool function callbacks used to handle the tool
* calls.
*/
public AnthropicChatModel(AnthropicApi anthropicApi, AnthropicChatOptions defaultOptions,
RetryTemplate retryTemplate, FunctionCallbackContext functionCallbackContext,
RetryTemplate retryTemplate, FunctionCallbackResolver functionCallbackResolver,
List<FunctionCallback> toolFunctionCallbacks, ObservationRegistry observationRegistry) {
super(functionCallbackContext, defaultOptions, toolFunctionCallbacks);
super(functionCallbackResolver, defaultOptions, toolFunctionCallbacks);
Assert.notNull(anthropicApi, "AnthropicApi must not be null");
Assert.notNull(defaultOptions, "DefaultOptions must not be null");

View File

@@ -33,7 +33,7 @@ import org.springframework.ai.chat.observation.ChatModelObservationDocumentation
import org.springframework.ai.chat.observation.ChatModelObservationDocumentation.LowCardinalityKeyNames;
import org.springframework.ai.chat.observation.DefaultChatModelObservationConvention;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.model.function.FunctionCallbackContext;
import org.springframework.ai.model.function.DefaultFunctionCallbackResolver;
import org.springframework.ai.observation.conventions.AiOperationType;
import org.springframework.ai.observation.conventions.AiProvider;
import org.springframework.beans.factory.annotation.Autowired;
@@ -170,7 +170,8 @@ public class AnthropicChatModelObservationIT {
public AnthropicChatModel anthropicChatModel(AnthropicApi anthropicApi,
TestObservationRegistry observationRegistry) {
return new AnthropicChatModel(anthropicApi, AnthropicChatOptions.builder().build(),
RetryTemplate.defaultInstance(), new FunctionCallbackContext(), List.of(), observationRegistry);
RetryTemplate.defaultInstance(), new DefaultFunctionCallbackResolver(), List.of(),
observationRegistry);
}
}

View File

@@ -83,7 +83,7 @@ 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.FunctionCallback;
import org.springframework.ai.model.function.FunctionCallbackContext;
import org.springframework.ai.model.function.FunctionCallbackResolver;
import org.springframework.ai.model.function.FunctionCallingOptions;
import org.springframework.ai.observation.conventions.AiProvider;
import org.springframework.util.Assert;
@@ -154,19 +154,19 @@ public class AzureOpenAiChatModel extends AbstractToolCallSupport implements Cha
}
public AzureOpenAiChatModel(OpenAIClientBuilder openAIClientBuilder, AzureOpenAiChatOptions options,
FunctionCallbackContext functionCallbackContext) {
this(openAIClientBuilder, options, functionCallbackContext, List.of());
FunctionCallbackResolver functionCallbackResolver) {
this(openAIClientBuilder, options, functionCallbackResolver, List.of());
}
public AzureOpenAiChatModel(OpenAIClientBuilder openAIClientBuilder, AzureOpenAiChatOptions options,
FunctionCallbackContext functionCallbackContext, List<FunctionCallback> toolFunctionCallbacks) {
this(openAIClientBuilder, options, functionCallbackContext, toolFunctionCallbacks, ObservationRegistry.NOOP);
FunctionCallbackResolver functionCallbackResolver, List<FunctionCallback> toolFunctionCallbacks) {
this(openAIClientBuilder, options, functionCallbackResolver, toolFunctionCallbacks, ObservationRegistry.NOOP);
}
public AzureOpenAiChatModel(OpenAIClientBuilder openAIClientBuilder, AzureOpenAiChatOptions options,
FunctionCallbackContext functionCallbackContext, List<FunctionCallback> toolFunctionCallbacks,
FunctionCallbackResolver functionCallbackResolver, List<FunctionCallback> toolFunctionCallbacks,
ObservationRegistry observationRegistry) {
super(functionCallbackContext, options, toolFunctionCallbacks);
super(functionCallbackResolver, options, toolFunctionCallbacks);
Assert.notNull(openAIClientBuilder, "com.azure.ai.openai.OpenAIClient must not be null");
Assert.notNull(options, "AzureOpenAiChatOptions must not be null");
this.openAIClient = openAIClientBuilder.buildClient();

View File

@@ -25,7 +25,7 @@ import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.ai.model.function.FunctionCallback;
import org.springframework.ai.model.function.FunctionCallbackContext;
import org.springframework.ai.model.function.FunctionCallbackResolver;
/**
* @author Jihoon Kim
@@ -37,7 +37,7 @@ public class AzureOpenAiChatModelTests {
OpenAIClientBuilder mockClient;
@Mock
FunctionCallbackContext functionCallbackContext;
FunctionCallbackResolver functionCallbackResolver;
@Test
public void createAzureOpenAiChatModelTest() {
@@ -51,7 +51,7 @@ public class AzureOpenAiChatModelTests {
List<FunctionCallback> functionCallbacks = List.of(new TestFunctionCallback(callbackFromConstructorParam));
AzureOpenAiChatModel openAiChatModel = new AzureOpenAiChatModel(this.mockClient, chatOptions,
this.functionCallbackContext, functionCallbacks);
this.functionCallbackResolver, functionCallbacks);
assert 2 == openAiChatModel.getFunctionCallbackRegister().size();

View File

@@ -88,7 +88,7 @@ import org.springframework.ai.chat.prompt.ChatOptionsBuilder;
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.FunctionCallbackContext;
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;
@@ -146,10 +146,10 @@ public class BedrockProxyChatModel extends AbstractToolCallSupport implements Ch
public BedrockProxyChatModel(BedrockRuntimeClient bedrockRuntimeClient,
BedrockRuntimeAsyncClient bedrockRuntimeAsyncClient, FunctionCallingOptions defaultOptions,
FunctionCallbackContext functionCallbackContext, List<FunctionCallback> toolFunctionCallbacks,
FunctionCallbackResolver functionCallbackResolver, List<FunctionCallback> toolFunctionCallbacks,
ObservationRegistry observationRegistry) {
super(functionCallbackContext, defaultOptions, toolFunctionCallbacks);
super(functionCallbackResolver, defaultOptions, toolFunctionCallbacks);
Assert.notNull(bedrockRuntimeClient, "bedrockRuntimeClient must not be null");
Assert.notNull(bedrockRuntimeAsyncClient, "bedrockRuntimeAsyncClient must not be null");
@@ -608,7 +608,7 @@ public class BedrockProxyChatModel extends AbstractToolCallSupport implements Ch
private FunctionCallingOptions defaultOptions = new FunctionCallingOptionsBuilder().build();
private FunctionCallbackContext functionCallbackContext;
private FunctionCallbackResolver functionCallbackResolver;
private List<FunctionCallback> toolFunctionCallbacks;
@@ -647,8 +647,18 @@ public class BedrockProxyChatModel extends AbstractToolCallSupport implements Ch
return this;
}
public Builder withFunctionCallbackContext(FunctionCallbackContext functionCallbackContext) {
this.functionCallbackContext = functionCallbackContext;
/**
* @deprecated Use {@link #functionCallbackResolver(FunctionCallbackResolver)}
* instead.
*/
@Deprecated
public Builder withFunctionCallbackContext(FunctionCallbackResolver functionCallbackResolver) {
this.functionCallbackResolver = functionCallbackResolver;
return this;
}
public Builder functionCallbackResolver(FunctionCallbackResolver functionCallbackResolver) {
this.functionCallbackResolver = functionCallbackResolver;
return this;
}
@@ -707,7 +717,7 @@ public class BedrockProxyChatModel extends AbstractToolCallSupport implements Ch
}
var bedrockProxyChatModel = new BedrockProxyChatModel(this.bedrockRuntimeClient,
this.bedrockRuntimeAsyncClient, this.defaultOptions, this.functionCallbackContext,
this.bedrockRuntimeAsyncClient, this.defaultOptions, this.functionCallbackResolver,
this.toolFunctionCallbacks, this.observationRegistry);
if (this.customObservationConvention != null) {

View File

@@ -64,7 +64,7 @@ import org.springframework.ai.minimax.api.MiniMaxApiConstants;
import org.springframework.ai.minimax.metadata.MiniMaxUsage;
import org.springframework.ai.model.ModelOptionsUtils;
import org.springframework.ai.model.function.FunctionCallback;
import org.springframework.ai.model.function.FunctionCallbackContext;
import org.springframework.ai.model.function.FunctionCallbackResolver;
import org.springframework.ai.model.function.FunctionCallingOptions;
import org.springframework.ai.retry.RetryUtils;
import org.springframework.http.ResponseEntity;
@@ -139,12 +139,13 @@ public class MiniMaxChatModel extends AbstractToolCallSupport implements ChatMod
* @param miniMaxApi The MiniMaxApi instance to be used for interacting with the
* MiniMax Chat API.
* @param options The MiniMaxChatOptions to configure the chat model.
* @param functionCallbackContext The function callback context.
* @param functionCallbackResolver The function callback resolver to resolve the
* function by its name.
* @param retryTemplate The retry template.
*/
public MiniMaxChatModel(MiniMaxApi miniMaxApi, MiniMaxChatOptions options,
FunctionCallbackContext functionCallbackContext, RetryTemplate retryTemplate) {
this(miniMaxApi, options, functionCallbackContext, List.of(), retryTemplate, ObservationRegistry.NOOP);
FunctionCallbackResolver functionCallbackResolver, RetryTemplate retryTemplate) {
this(miniMaxApi, options, functionCallbackResolver, List.of(), retryTemplate, ObservationRegistry.NOOP);
}
/**
@@ -152,15 +153,16 @@ public class MiniMaxChatModel extends AbstractToolCallSupport implements ChatMod
* @param miniMaxApi The MiniMaxApi instance to be used for interacting with the
* MiniMax Chat API.
* @param options The MiniMaxChatOptions to configure the chat model.
* @param functionCallbackContext The function callback context.
* @param functionCallbackResolver The function callback resolver to resolve the
* function by its name.
* @param toolFunctionCallbacks The tool function callbacks.
* @param retryTemplate The retry template.
* @param observationRegistry The ObservationRegistry used for instrumentation.
*/
public MiniMaxChatModel(MiniMaxApi miniMaxApi, MiniMaxChatOptions options,
FunctionCallbackContext functionCallbackContext, List<FunctionCallback> toolFunctionCallbacks,
FunctionCallbackResolver functionCallbackResolver, List<FunctionCallback> toolFunctionCallbacks,
RetryTemplate retryTemplate, ObservationRegistry observationRegistry) {
super(functionCallbackContext, options, toolFunctionCallbacks);
super(functionCallbackResolver, options, toolFunctionCallbacks);
Assert.notNull(miniMaxApi, "MiniMaxApi must not be null");
Assert.notNull(options, "Options must not be null");
Assert.notNull(retryTemplate, "RetryTemplate must not be null");

View File

@@ -33,7 +33,7 @@ import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.minimax.MiniMaxChatModel;
import org.springframework.ai.minimax.MiniMaxChatOptions;
import org.springframework.ai.minimax.api.MiniMaxApi;
import org.springframework.ai.model.function.FunctionCallbackContext;
import org.springframework.ai.model.function.DefaultFunctionCallbackResolver;
import org.springframework.ai.observation.conventions.AiOperationType;
import org.springframework.ai.observation.conventions.AiProvider;
import org.springframework.beans.factory.annotation.Autowired;
@@ -170,8 +170,9 @@ public class MiniMaxChatModelObservationIT {
@Bean
public MiniMaxChatModel minimaxChatModel(MiniMaxApi minimaxApi, TestObservationRegistry observationRegistry) {
return new MiniMaxChatModel(minimaxApi, MiniMaxChatOptions.builder().build(), new FunctionCallbackContext(),
List.of(), RetryTemplate.defaultInstance(), observationRegistry);
return new MiniMaxChatModel(minimaxApi, MiniMaxChatOptions.builder().build(),
new DefaultFunctionCallbackResolver(), List.of(), RetryTemplate.defaultInstance(),
observationRegistry);
}
}

View File

@@ -59,7 +59,7 @@ import org.springframework.ai.mistralai.api.MistralAiApi.ChatCompletionRequest;
import org.springframework.ai.mistralai.metadata.MistralAiUsage;
import org.springframework.ai.model.ModelOptionsUtils;
import org.springframework.ai.model.function.FunctionCallback;
import org.springframework.ai.model.function.FunctionCallbackContext;
import org.springframework.ai.model.function.FunctionCallbackResolver;
import org.springframework.ai.model.function.FunctionCallingOptions;
import org.springframework.ai.retry.RetryUtils;
import org.springframework.http.ResponseEntity;
@@ -120,21 +120,21 @@ public class MistralAiChatModel extends AbstractToolCallSupport implements ChatM
}
public MistralAiChatModel(MistralAiApi mistralAiApi, MistralAiChatOptions options,
FunctionCallbackContext functionCallbackContext, RetryTemplate retryTemplate) {
this(mistralAiApi, options, functionCallbackContext, List.of(), retryTemplate);
FunctionCallbackResolver functionCallbackResolver, RetryTemplate retryTemplate) {
this(mistralAiApi, options, functionCallbackResolver, List.of(), retryTemplate);
}
public MistralAiChatModel(MistralAiApi mistralAiApi, MistralAiChatOptions options,
FunctionCallbackContext functionCallbackContext, List<FunctionCallback> toolFunctionCallbacks,
FunctionCallbackResolver functionCallbackResolver, List<FunctionCallback> toolFunctionCallbacks,
RetryTemplate retryTemplate) {
this(mistralAiApi, options, functionCallbackContext, toolFunctionCallbacks, retryTemplate,
this(mistralAiApi, options, functionCallbackResolver, toolFunctionCallbacks, retryTemplate,
ObservationRegistry.NOOP);
}
public MistralAiChatModel(MistralAiApi mistralAiApi, MistralAiChatOptions options,
FunctionCallbackContext functionCallbackContext, List<FunctionCallback> toolFunctionCallbacks,
FunctionCallbackResolver functionCallbackResolver, List<FunctionCallback> toolFunctionCallbacks,
RetryTemplate retryTemplate, ObservationRegistry observationRegistry) {
super(functionCallbackContext, options, toolFunctionCallbacks);
super(functionCallbackResolver, options, toolFunctionCallbacks);
Assert.notNull(mistralAiApi, "mistralAiApi must not be null");
Assert.notNull(options, "options must not be null");
Assert.notNull(retryTemplate, "retryTemplate must not be null");

View File

@@ -32,7 +32,7 @@ import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.observation.DefaultChatModelObservationConvention;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.mistralai.api.MistralAiApi;
import org.springframework.ai.model.function.FunctionCallbackContext;
import org.springframework.ai.model.function.DefaultFunctionCallbackResolver;
import org.springframework.ai.observation.conventions.AiOperationType;
import org.springframework.ai.observation.conventions.AiProvider;
import org.springframework.beans.factory.annotation.Autowired;
@@ -181,7 +181,8 @@ public class MistralAiChatModelObservationIT {
public MistralAiChatModel openAiChatModel(MistralAiApi mistralAiApi,
TestObservationRegistry observationRegistry) {
return new MistralAiChatModel(mistralAiApi, MistralAiChatOptions.builder().build(),
new FunctionCallbackContext(), List.of(), RetryTemplate.defaultInstance(), observationRegistry);
new DefaultFunctionCallbackResolver(), List.of(), RetryTemplate.defaultInstance(),
observationRegistry);
}
}

View File

@@ -51,7 +51,7 @@ import org.springframework.ai.chat.prompt.ChatOptionsBuilder;
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.FunctionCallbackContext;
import org.springframework.ai.model.function.FunctionCallbackResolver;
import org.springframework.ai.model.function.FunctionCallingOptions;
import org.springframework.ai.moonshot.api.MoonshotApi;
import org.springframework.ai.moonshot.api.MoonshotApi.ChatCompletion;
@@ -128,12 +128,13 @@ public class MoonshotChatModel extends AbstractToolCallSupport implements ChatMo
* @param moonshotApi The Moonshot instance to be used for interacting with the
* Moonshot Chat API.
* @param options The MoonshotChatOptions to configure the chat client.
* @param functionCallbackContext The function callback context.
* @param functionCallbackResolver The function callback resolver to resolve the
* function by its name.
* @param retryTemplate The retry template.
*/
public MoonshotChatModel(MoonshotApi moonshotApi, MoonshotChatOptions options,
FunctionCallbackContext functionCallbackContext, RetryTemplate retryTemplate) {
this(moonshotApi, options, functionCallbackContext, List.of(), retryTemplate, ObservationRegistry.NOOP);
FunctionCallbackResolver functionCallbackResolver, RetryTemplate retryTemplate) {
this(moonshotApi, options, functionCallbackResolver, List.of(), retryTemplate, ObservationRegistry.NOOP);
}
/**
@@ -141,15 +142,15 @@ public class MoonshotChatModel extends AbstractToolCallSupport implements ChatMo
* @param moonshotApi The Moonshot instance to be used for interacting with the
* Moonshot Chat API.
* @param options The MoonshotChatOptions to configure the chat client.
* @param functionCallbackContext The function callback context.
* @param functionCallbackResolver resolves the function by its name.
* @param toolFunctionCallbacks The tool function callbacks.
* @param retryTemplate The retry template.
* @param observationRegistry The ObservationRegistry used for instrumentation.
*/
public MoonshotChatModel(MoonshotApi moonshotApi, MoonshotChatOptions options,
FunctionCallbackContext functionCallbackContext, List<FunctionCallback> toolFunctionCallbacks,
FunctionCallbackResolver functionCallbackResolver, List<FunctionCallback> toolFunctionCallbacks,
RetryTemplate retryTemplate, ObservationRegistry observationRegistry) {
super(functionCallbackContext, options, toolFunctionCallbacks);
super(functionCallbackResolver, options, toolFunctionCallbacks);
Assert.notNull(moonshotApi, "MoonshotApi must not be null");
Assert.notNull(options, "Options must not be null");
Assert.notNull(retryTemplate, "RetryTemplate must not be null");

View File

@@ -30,7 +30,7 @@ import org.springframework.ai.chat.metadata.ChatResponseMetadata;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.observation.DefaultChatModelObservationConvention;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.model.function.FunctionCallbackContext;
import org.springframework.ai.model.function.DefaultFunctionCallbackResolver;
import org.springframework.ai.moonshot.MoonshotChatModel;
import org.springframework.ai.moonshot.MoonshotChatOptions;
import org.springframework.ai.moonshot.api.MoonshotApi;
@@ -173,7 +173,8 @@ public class MoonshotChatModelObservationIT {
public MoonshotChatModel moonshotChatModel(MoonshotApi moonshotApi,
TestObservationRegistry observationRegistry) {
return new MoonshotChatModel(moonshotApi, MoonshotChatOptions.builder().build(),
new FunctionCallbackContext(), List.of(), RetryTemplate.defaultInstance(), observationRegistry);
new DefaultFunctionCallbackResolver(), List.of(), RetryTemplate.defaultInstance(),
observationRegistry);
}
}

View File

@@ -47,7 +47,7 @@ import org.springframework.ai.chat.prompt.ChatOptionsBuilder;
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.FunctionCallbackContext;
import org.springframework.ai.model.function.FunctionCallbackResolver;
import org.springframework.ai.model.function.FunctionCallingOptions;
import org.springframework.ai.ollama.api.OllamaApi;
import org.springframework.ai.ollama.api.OllamaApi.ChatRequest;
@@ -92,9 +92,9 @@ public class OllamaChatModel extends AbstractToolCallSupport implements ChatMode
private ChatModelObservationConvention observationConvention = DEFAULT_OBSERVATION_CONVENTION;
public OllamaChatModel(OllamaApi ollamaApi, OllamaOptions defaultOptions,
FunctionCallbackContext functionCallbackContext, List<FunctionCallback> toolFunctionCallbacks,
FunctionCallbackResolver functionCallbackResolver, List<FunctionCallback> toolFunctionCallbacks,
ObservationRegistry observationRegistry, ModelManagementOptions modelManagementOptions) {
super(functionCallbackContext, defaultOptions, toolFunctionCallbacks);
super(functionCallbackResolver, defaultOptions, toolFunctionCallbacks);
Assert.notNull(ollamaApi, "ollamaApi must not be null");
Assert.notNull(defaultOptions, "defaultOptions must not be null");
Assert.notNull(observationRegistry, "observationRegistry must not be null");
@@ -401,7 +401,7 @@ public class OllamaChatModel extends AbstractToolCallSupport implements ChatMode
private OllamaOptions defaultOptions = OllamaOptions.create().withModel(OllamaModel.MISTRAL.id());
private FunctionCallbackContext functionCallbackContext;
private FunctionCallbackResolver functionCallbackResolver;
private List<FunctionCallback> toolFunctionCallbacks = List.of();
@@ -422,8 +422,18 @@ public class OllamaChatModel extends AbstractToolCallSupport implements ChatMode
return this;
}
public Builder withFunctionCallbackContext(FunctionCallbackContext functionCallbackContext) {
this.functionCallbackContext = functionCallbackContext;
/**
* @deprecated use the {@link functionCallbackResolver(FunctionCallbackResolver)}
* instead
*/
@Deprecated
public Builder withFunctionCallbackContext(FunctionCallbackResolver functionCallbackContext) {
this.functionCallbackResolver = functionCallbackContext;
return this;
}
public Builder functionCallbackResolver(FunctionCallbackResolver functionCallbackResolver) {
this.functionCallbackResolver = functionCallbackResolver;
return this;
}
@@ -443,7 +453,7 @@ public class OllamaChatModel extends AbstractToolCallSupport implements ChatMode
}
public OllamaChatModel build() {
return new OllamaChatModel(this.ollamaApi, this.defaultOptions, this.functionCallbackContext,
return new OllamaChatModel(this.ollamaApi, this.defaultOptions, this.functionCallbackResolver,
this.toolFunctionCallbacks, this.observationRegistry, this.modelManagementOptions);
}

View File

@@ -57,7 +57,7 @@ import org.springframework.ai.chat.prompt.ChatOptionsBuilder;
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.FunctionCallbackContext;
import org.springframework.ai.model.function.FunctionCallbackResolver;
import org.springframework.ai.model.function.FunctionCallingOptions;
import org.springframework.ai.openai.api.OpenAiApi;
import org.springframework.ai.openai.api.OpenAiApi.ChatCompletion;
@@ -155,12 +155,12 @@ public class OpenAiChatModel extends AbstractToolCallSupport implements ChatMode
* @param openAiApi The OpenAiApi instance to be used for interacting with the OpenAI
* Chat API.
* @param options The OpenAiChatOptions to configure the chat model.
* @param functionCallbackContext The function callback context.
* @param functionCallbackResolver The function callback resolver.
* @param retryTemplate The retry template.
*/
public OpenAiChatModel(OpenAiApi openAiApi, OpenAiChatOptions options,
FunctionCallbackContext functionCallbackContext, RetryTemplate retryTemplate) {
this(openAiApi, options, functionCallbackContext, List.of(), retryTemplate);
FunctionCallbackResolver functionCallbackResolver, RetryTemplate retryTemplate) {
this(openAiApi, options, functionCallbackResolver, List.of(), retryTemplate);
}
/**
@@ -168,14 +168,14 @@ public class OpenAiChatModel extends AbstractToolCallSupport implements ChatMode
* @param openAiApi The OpenAiApi instance to be used for interacting with the OpenAI
* Chat API.
* @param options The OpenAiChatOptions to configure the chat model.
* @param functionCallbackContext The function callback context.
* @param functionCallbackResolver The function callback resolver.
* @param toolFunctionCallbacks The tool function callbacks.
* @param retryTemplate The retry template.
*/
public OpenAiChatModel(OpenAiApi openAiApi, OpenAiChatOptions options,
FunctionCallbackContext functionCallbackContext, List<FunctionCallback> toolFunctionCallbacks,
FunctionCallbackResolver functionCallbackResolver, List<FunctionCallback> toolFunctionCallbacks,
RetryTemplate retryTemplate) {
this(openAiApi, options, functionCallbackContext, toolFunctionCallbacks, retryTemplate,
this(openAiApi, options, functionCallbackResolver, toolFunctionCallbacks, retryTemplate,
ObservationRegistry.NOOP);
}
@@ -184,16 +184,16 @@ public class OpenAiChatModel extends AbstractToolCallSupport implements ChatMode
* @param openAiApi The OpenAiApi instance to be used for interacting with the OpenAI
* Chat API.
* @param options The OpenAiChatOptions to configure the chat model.
* @param functionCallbackContext The function callback context.
* @param functionCallbackResolver The function callback resolver.
* @param toolFunctionCallbacks The tool function callbacks.
* @param retryTemplate The retry template.
* @param observationRegistry The ObservationRegistry used for instrumentation.
*/
public OpenAiChatModel(OpenAiApi openAiApi, OpenAiChatOptions options,
FunctionCallbackContext functionCallbackContext, List<FunctionCallback> toolFunctionCallbacks,
FunctionCallbackResolver functionCallbackResolver, List<FunctionCallback> toolFunctionCallbacks,
RetryTemplate retryTemplate, ObservationRegistry observationRegistry) {
super(functionCallbackContext, options, toolFunctionCallbacks);
super(functionCallbackResolver, options, toolFunctionCallbacks);
Assert.notNull(openAiApi, "OpenAiApi must not be null");
Assert.notNull(options, "Options must not be null");

View File

@@ -30,7 +30,7 @@ import org.springframework.ai.chat.metadata.ChatResponseMetadata;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.observation.DefaultChatModelObservationConvention;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.model.function.FunctionCallbackContext;
import org.springframework.ai.model.function.DefaultFunctionCallbackResolver;
import org.springframework.ai.observation.conventions.AiOperationType;
import org.springframework.ai.observation.conventions.AiProvider;
import org.springframework.ai.openai.OpenAiChatModel;
@@ -174,8 +174,9 @@ public class OpenAiChatModelObservationIT {
@Bean
public OpenAiChatModel openAiChatModel(OpenAiApi openAiApi, TestObservationRegistry observationRegistry) {
return new OpenAiChatModel(openAiApi, OpenAiChatOptions.builder().build(), new FunctionCallbackContext(),
List.of(), RetryTemplate.defaultInstance(), observationRegistry);
return new OpenAiChatModel(openAiApi, OpenAiChatOptions.builder().build(),
new DefaultFunctionCallbackResolver(), List.of(), RetryTemplate.defaultInstance(),
observationRegistry);
}
}

View File

@@ -34,7 +34,8 @@ import org.springframework.ai.chat.client.advisor.api.AdvisedResponse;
import org.springframework.ai.chat.client.advisor.api.CallAroundAdvisor;
import org.springframework.ai.chat.client.advisor.api.CallAroundAdvisorChain;
import org.springframework.ai.converter.BeanOutputConverter;
import org.springframework.ai.model.function.FunctionCallbackContext;
import org.springframework.ai.model.function.DefaultFunctionCallbackResolver;
import org.springframework.ai.model.function.FunctionCallbackResolver;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.ai.openai.api.OpenAiApi;
@@ -220,22 +221,22 @@ public class OpenAiPaymentTransactionIT {
}
@Bean
public OpenAiChatModel openAiClient(OpenAiApi openAiApi, FunctionCallbackContext functionCallbackContext) {
public OpenAiChatModel openAiClient(OpenAiApi openAiApi, FunctionCallbackResolver functionCallbackResolver) {
return new OpenAiChatModel(openAiApi,
OpenAiChatOptions.builder()
.withModel(ChatModel.GPT_4_O_MINI.getName())
.withTemperature(0.1)
.build(),
functionCallbackContext, RetryUtils.DEFAULT_RETRY_TEMPLATE);
functionCallbackResolver, RetryUtils.DEFAULT_RETRY_TEMPLATE);
}
/**
* Because of the OPEN_API_SCHEMA type, the FunctionCallbackContext instance must
* Because of the OPEN_API_SCHEMA type, the FunctionCallbackResolver instance must
* different from the other JSON schema types.
*/
@Bean
public FunctionCallbackContext springAiFunctionManager(ApplicationContext context) {
FunctionCallbackContext manager = new FunctionCallbackContext();
public FunctionCallbackResolver springAiFunctionManager(ApplicationContext context) {
DefaultFunctionCallbackResolver manager = new DefaultFunctionCallbackResolver();
manager.setApplicationContext(context);
return manager;
}

View File

@@ -71,7 +71,7 @@ import org.springframework.ai.model.ChatModelDescription;
import org.springframework.ai.model.Media;
import org.springframework.ai.model.ModelOptionsUtils;
import org.springframework.ai.model.function.FunctionCallback;
import org.springframework.ai.model.function.FunctionCallbackContext;
import org.springframework.ai.model.function.FunctionCallbackResolver;
import org.springframework.ai.model.function.FunctionCallingOptions;
import org.springframework.ai.retry.RetryUtils;
import org.springframework.ai.vertexai.gemini.common.VertexAiGeminiConstants;
@@ -130,27 +130,27 @@ public class VertexAiGeminiChatModel extends AbstractToolCallSupport implements
}
public VertexAiGeminiChatModel(VertexAI vertexAI, VertexAiGeminiChatOptions options,
FunctionCallbackContext functionCallbackContext) {
this(vertexAI, options, functionCallbackContext, List.of());
FunctionCallbackResolver functionCallbackResolver) {
this(vertexAI, options, functionCallbackResolver, List.of());
}
public VertexAiGeminiChatModel(VertexAI vertexAI, VertexAiGeminiChatOptions options,
FunctionCallbackContext functionCallbackContext, List<FunctionCallback> toolFunctionCallbacks) {
this(vertexAI, options, functionCallbackContext, toolFunctionCallbacks, RetryUtils.DEFAULT_RETRY_TEMPLATE);
FunctionCallbackResolver functionCallbackResolver, List<FunctionCallback> toolFunctionCallbacks) {
this(vertexAI, options, functionCallbackResolver, toolFunctionCallbacks, RetryUtils.DEFAULT_RETRY_TEMPLATE);
}
public VertexAiGeminiChatModel(VertexAI vertexAI, VertexAiGeminiChatOptions options,
FunctionCallbackContext functionCallbackContext, List<FunctionCallback> toolFunctionCallbacks,
FunctionCallbackResolver functionCallbackResolver, List<FunctionCallback> toolFunctionCallbacks,
RetryTemplate retryTemplate) {
this(vertexAI, options, functionCallbackContext, toolFunctionCallbacks, retryTemplate,
this(vertexAI, options, functionCallbackResolver, toolFunctionCallbacks, retryTemplate,
ObservationRegistry.NOOP);
}
public VertexAiGeminiChatModel(VertexAI vertexAI, VertexAiGeminiChatOptions options,
FunctionCallbackContext functionCallbackContext, List<FunctionCallback> toolFunctionCallbacks,
FunctionCallbackResolver functionCallbackResolver, List<FunctionCallback> toolFunctionCallbacks,
RetryTemplate retryTemplate, ObservationRegistry observationRegistry) {
super(functionCallbackContext, options, toolFunctionCallbacks);
super(functionCallbackResolver, options, toolFunctionCallbacks);
Assert.notNull(vertexAI, "VertexAI must not be null");
Assert.notNull(options, "VertexAiGeminiChatOptions must not be null");

View File

@@ -24,7 +24,7 @@ import com.google.cloud.vertexai.api.GenerateContentResponse;
import com.google.cloud.vertexai.generativeai.GenerativeModel;
import org.springframework.ai.model.function.FunctionCallback;
import org.springframework.ai.model.function.FunctionCallbackContext;
import org.springframework.ai.model.function.FunctionCallbackResolver;
import org.springframework.retry.support.RetryTemplate;
/**
@@ -35,9 +35,9 @@ public class TestVertexAiGeminiChatModel extends VertexAiGeminiChatModel {
private GenerativeModel mockGenerativeModel;
public TestVertexAiGeminiChatModel(VertexAI vertexAI, VertexAiGeminiChatOptions options,
FunctionCallbackContext functionCallbackContext, List<FunctionCallback> toolFunctionCallbacks,
FunctionCallbackResolver functionCallbackResolver, List<FunctionCallback> toolFunctionCallbacks,
RetryTemplate retryTemplate) {
super(vertexAI, options, functionCallbackContext, toolFunctionCallbacks, retryTemplate);
super(vertexAI, options, functionCallbackResolver, toolFunctionCallbacks, retryTemplate);
}
@Override

View File

@@ -36,7 +36,7 @@ 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.FunctionCallback.SchemaType;
import org.springframework.ai.vertexai.gemini.VertexAiGeminiChatModel;
import org.springframework.ai.vertexai.gemini.VertexAiGeminiChatOptions;
import org.springframework.beans.factory.annotation.Autowired;

View File

@@ -35,8 +35,9 @@ import org.springframework.ai.chat.client.advisor.api.AdvisedRequest;
import org.springframework.ai.chat.client.advisor.api.AdvisedResponse;
import org.springframework.ai.chat.client.advisor.api.CallAroundAdvisor;
import org.springframework.ai.chat.client.advisor.api.CallAroundAdvisorChain;
import org.springframework.ai.model.function.FunctionCallbackContext;
import org.springframework.ai.model.function.FunctionCallbackContext.SchemaType;
import org.springframework.ai.model.function.DefaultFunctionCallbackResolver;
import org.springframework.ai.model.function.FunctionCallbackResolver;
import org.springframework.ai.model.function.FunctionCallback.SchemaType;
import org.springframework.ai.vertexai.gemini.VertexAiGeminiChatModel;
import org.springframework.ai.vertexai.gemini.VertexAiGeminiChatOptions;
import org.springframework.beans.factory.annotation.Autowired;
@@ -207,23 +208,23 @@ public class VertexAiGeminiPaymentTransactionIT {
@Bean
public VertexAiGeminiChatModel vertexAiChatModel(VertexAI vertexAi, ApplicationContext context) {
FunctionCallbackContext functionCallbackContext = springAiFunctionManager(context);
FunctionCallbackResolver functionCallbackResolver = springAiFunctionManager(context);
return new VertexAiGeminiChatModel(vertexAi,
VertexAiGeminiChatOptions.builder()
.withModel(VertexAiGeminiChatModel.ChatModel.GEMINI_1_5_FLASH)
.withTemperature(0.1)
.build(),
functionCallbackContext);
functionCallbackResolver);
}
/**
* Because of the OPEN_API_SCHEMA type, the FunctionCallbackContext instance
* Because of the OPEN_API_SCHEMA type, the FunctionCallbackResolver instance
* must
* different from the other JSON schema types.
*/
private FunctionCallbackContext springAiFunctionManager(ApplicationContext context) {
FunctionCallbackContext manager = new FunctionCallbackContext();
private FunctionCallbackResolver springAiFunctionManager(ApplicationContext context) {
DefaultFunctionCallbackResolver manager = new DefaultFunctionCallbackResolver();
manager.setSchemaType(SchemaType.OPEN_API_SCHEMA);
manager.setApplicationContext(context);
return manager;

View File

@@ -54,7 +54,7 @@ import org.springframework.ai.chat.prompt.ChatOptionsBuilder;
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.FunctionCallbackContext;
import org.springframework.ai.model.function.FunctionCallbackResolver;
import org.springframework.ai.model.function.FunctionCallingOptions;
import org.springframework.ai.retry.RetryUtils;
import org.springframework.ai.zhipuai.api.ZhiPuAiApi;
@@ -143,12 +143,12 @@ public class ZhiPuAiChatModel extends AbstractToolCallSupport implements ChatMod
* @param zhiPuAiApi The ZhiPuAiApi instance to be used for interacting with the
* ZhiPuAI Chat API.
* @param options The ZhiPuAiChatOptions to configure the chat model.
* @param functionCallbackContext The function callback context.
* @param functionCallbackResolver The function callback resolver.
* @param retryTemplate The retry template.
*/
public ZhiPuAiChatModel(ZhiPuAiApi zhiPuAiApi, ZhiPuAiChatOptions options,
FunctionCallbackContext functionCallbackContext, RetryTemplate retryTemplate) {
this(zhiPuAiApi, options, functionCallbackContext, List.of(), retryTemplate, ObservationRegistry.NOOP);
FunctionCallbackResolver functionCallbackResolver, RetryTemplate retryTemplate) {
this(zhiPuAiApi, options, functionCallbackResolver, List.of(), retryTemplate, ObservationRegistry.NOOP);
}
/**
@@ -156,15 +156,15 @@ public class ZhiPuAiChatModel extends AbstractToolCallSupport implements ChatMod
* @param zhiPuAiApi The ZhiPuAiApi instance to be used for interacting with the
* ZhiPuAI Chat API.
* @param options The ZhiPuAiChatOptions to configure the chat model.
* @param functionCallbackContext The function callback context.
* @param functionCallbackResolver The function callback resolver.
* @param toolFunctionCallbacks The tool function callbacks.
* @param retryTemplate The retry template.
* @param observationRegistry The ObservationRegistry used for instrumentation.
*/
public ZhiPuAiChatModel(ZhiPuAiApi zhiPuAiApi, ZhiPuAiChatOptions options,
FunctionCallbackContext functionCallbackContext, List<FunctionCallback> toolFunctionCallbacks,
FunctionCallbackResolver functionCallbackResolver, List<FunctionCallback> toolFunctionCallbacks,
RetryTemplate retryTemplate, ObservationRegistry observationRegistry) {
super(functionCallbackContext, options, toolFunctionCallbacks);
super(functionCallbackResolver, options, toolFunctionCallbacks);
Assert.notNull(zhiPuAiApi, "ZhiPuAiApi must not be null");
Assert.notNull(options, "Options must not be null");
Assert.notNull(retryTemplate, "RetryTemplate must not be null");

View File

@@ -30,7 +30,7 @@ import org.springframework.ai.chat.metadata.ChatResponseMetadata;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.observation.DefaultChatModelObservationConvention;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.model.function.FunctionCallbackContext;
import org.springframework.ai.model.function.DefaultFunctionCallbackResolver;
import org.springframework.ai.observation.conventions.AiOperationType;
import org.springframework.ai.observation.conventions.AiProvider;
import org.springframework.ai.zhipuai.ZhiPuAiChatModel;
@@ -165,8 +165,9 @@ public class ZhiPuAiChatModelObservationIT {
@Bean
public ZhiPuAiChatModel zhiPuAiChatModel(ZhiPuAiApi zhiPuAiApi, TestObservationRegistry observationRegistry) {
return new ZhiPuAiChatModel(zhiPuAiApi, ZhiPuAiChatOptions.builder().build(), new FunctionCallbackContext(),
List.of(), RetryTemplate.defaultInstance(), observationRegistry);
return new ZhiPuAiChatModel(zhiPuAiApi, ZhiPuAiChatOptions.builder().build(),
new DefaultFunctionCallbackResolver(), List.of(), RetryTemplate.defaultInstance(),
observationRegistry);
}
}

View File

@@ -27,7 +27,7 @@ import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.ToolResponseMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.model.function.FunctionCallback;
import org.springframework.ai.model.function.FunctionCallbackContext;
import org.springframework.ai.model.function.DefaultFunctionCallbackResolver;
import org.springframework.ai.model.function.FunctionCallbackWrapper;
import org.springframework.aot.hint.ExecutableMode;
import org.springframework.aot.hint.RuntimeHints;
@@ -43,7 +43,7 @@ public class SpringAiCoreRuntimeHints implements RuntimeHintsRegistrar {
public void registerHints(@NonNull RuntimeHints hints, @Nullable ClassLoader classLoader) {
var chatTypes = Set.of(AbstractMessage.class, AssistantMessage.class, ToolResponseMessage.class, Message.class,
MessageType.class, UserMessage.class, SystemMessage.class, FunctionCallbackContext.class,
MessageType.class, UserMessage.class, SystemMessage.class, DefaultFunctionCallbackResolver.class,
FunctionCallback.class, FunctionCallbackWrapper.class);
for (var c : chatTypes) {
hints.reflection().registerType(c);

View File

@@ -30,7 +30,7 @@ import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.ToolResponseMessage;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.model.function.FunctionCallback;
import org.springframework.ai.model.function.FunctionCallbackContext;
import org.springframework.ai.model.function.FunctionCallbackResolver;
import org.springframework.ai.model.function.FunctionCallingOptions;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
@@ -55,20 +55,20 @@ public abstract class AbstractToolCallSupport {
protected final Map<String, FunctionCallback> functionCallbackRegister = new ConcurrentHashMap<>();
/**
* The function callback context is used to resolve the function callbacks by name
* The function callback resolver is used to resolve the function callbacks by name
* from the Spring context. It is optional and usually used with Spring
* auto-configuration.
*/
protected final FunctionCallbackContext functionCallbackContext;
protected final FunctionCallbackResolver functionCallbackResolver;
protected AbstractToolCallSupport(FunctionCallbackContext functionCallbackContext) {
this(functionCallbackContext, FunctionCallingOptions.builder().build(), List.of());
protected AbstractToolCallSupport(FunctionCallbackResolver functionCallbackResolver) {
this(functionCallbackResolver, FunctionCallingOptions.builder().build(), List.of());
}
protected AbstractToolCallSupport(FunctionCallbackContext functionCallbackContext,
protected AbstractToolCallSupport(FunctionCallbackResolver functionCallbackResolver,
FunctionCallingOptions functionCallingOptions, List<FunctionCallback> toolFunctionCallbacks) {
this.functionCallbackContext = functionCallbackContext;
this.functionCallbackResolver = functionCallbackResolver;
List<FunctionCallback> defaultFunctionCallbacks = merge(functionCallingOptions, toolFunctionCallbacks);
@@ -183,15 +183,14 @@ public abstract class AbstractToolCallSupport {
for (String functionName : functionNames) {
if (!this.functionCallbackRegister.containsKey(functionName)) {
if (this.functionCallbackContext != null) {
FunctionCallback functionCallback = this.functionCallbackContext.getFunctionCallback(functionName,
null);
if (this.functionCallbackResolver != null) {
FunctionCallback functionCallback = this.functionCallbackResolver.resolve(functionName);
if (functionCallback != null) {
this.functionCallbackRegister.put(functionName, functionCallback);
}
else {
throw new IllegalStateException(
"No function callback [" + functionName + "] fund in tht FunctionCallbackContext");
"No function callback [" + functionName + "] found in tht FunctionCallbackRegister");
}
}
else {

View File

@@ -36,7 +36,7 @@ import org.springframework.ai.model.ModelOptionsUtils;
import org.springframework.ai.model.function.FunctionCallback.Builder;
import org.springframework.ai.model.function.FunctionCallback.FunctionInvokingSpec;
import org.springframework.ai.model.function.FunctionCallback.MethodInvokingSpec;
import org.springframework.ai.model.function.FunctionCallbackContext.SchemaType;
import org.springframework.ai.model.function.FunctionCallback.SchemaType;
import org.springframework.ai.util.JacksonUtils;
import org.springframework.ai.util.ParsingUtils;
import org.springframework.core.ParameterizedTypeReference;

View File

@@ -27,6 +27,7 @@ import kotlin.jvm.functions.Function1;
import kotlin.jvm.functions.Function2;
import org.springframework.ai.chat.model.ToolContext;
import org.springframework.ai.model.function.FunctionCallback.SchemaType;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
@@ -56,7 +57,7 @@ import org.springframework.util.StringUtils;
* @author Christopher Smith
* @author Sebastien Deleuze
*/
public class FunctionCallbackContext implements ApplicationContextAware {
public class DefaultFunctionCallbackResolver implements ApplicationContextAware, FunctionCallbackResolver {
private GenericApplicationContext applicationContext;
@@ -71,21 +72,20 @@ public class FunctionCallbackContext implements ApplicationContextAware {
this.applicationContext = (GenericApplicationContext) applicationContext;
}
@SuppressWarnings({ "unchecked" })
public FunctionCallback getFunctionCallback(@NonNull String beanName, @Nullable String defaultDescription) {
@Override
public FunctionCallback resolve(@NonNull String beanName) {
ResolvableType functionType = TypeResolverHelper.resolveBeanType(this.applicationContext, beanName);
ResolvableType functionInputType = (ResolvableType.forType(Supplier.class).isAssignableFrom(functionType))
? ResolvableType.forType(Void.class) : TypeResolverHelper.getFunctionArgumentType(functionType, 0);
String functionDescription = resolveFunctionDescription(beanName, defaultDescription,
functionInputType.toClass());
String functionDescription = resolveFunctionDescription(beanName, functionInputType.toClass());
Object bean = this.applicationContext.getBean(beanName);
return buildFunctionCallback(beanName, functionType, functionInputType, functionDescription, bean);
}
private String resolveFunctionDescription(String beanName, String defaultDescription, Class<?> functionInputClass) {
String functionDescription = defaultDescription;
private String resolveFunctionDescription(String beanName, Class<?> functionInputClass) {
String functionDescription = "";
if (!StringUtils.hasText(functionDescription)) {
Description descriptionAnnotation = this.applicationContext.findAnnotationOnBean(beanName,
@@ -178,12 +178,6 @@ public class FunctionCallbackContext implements ApplicationContextAware {
throw new IllegalStateException("Unsupported function type");
}
public enum SchemaType {
JSON_SCHEMA, OPEN_API_SCHEMA
}
private static final class KotlinDelegate {
public static boolean isKotlinSupplier(Class<?> clazz) {

View File

@@ -24,7 +24,6 @@ import java.util.function.Supplier;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.ai.chat.model.ToolContext;
import org.springframework.ai.model.function.FunctionCallbackContext.SchemaType;
import org.springframework.core.ParameterizedTypeReference;
/**
@@ -91,6 +90,23 @@ public interface FunctionCallback {
return new DefaultFunctionCallbackBuilder();
}
/**
* Describes the type of the schema used to describe the input parameters of the
* function.
*/
public enum SchemaType {
/**
* JSON schema
*/
JSON_SCHEMA,
/**
* Open API schema
*/
OPEN_API_SCHEMA
}
/**
* Builder for creating a {@link FunctionCallback} instance. This is a hierarchical
* builder with the following structure:

View File

@@ -0,0 +1,35 @@
/*
* 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 org.springframework.lang.NonNull;
/**
* Strategy interface for resolving {@link FunctionCallback} instances.
*
* @author Christian Tzolov
* @since 1.0.0
*/
public interface FunctionCallbackResolver {
/**
* Resolve the {@link FunctionCallback} instance by its name.
* @param name the name of the function to resolve
* @return the {@link FunctionCallback} instance
*/
FunctionCallback resolve(@NonNull String name);
}

View File

@@ -27,7 +27,6 @@ import com.fasterxml.jackson.databind.json.JsonMapper;
import org.springframework.ai.chat.model.ToolContext;
import org.springframework.ai.model.ModelOptionsUtils;
import org.springframework.ai.model.function.FunctionCallbackContext.SchemaType;
import org.springframework.ai.util.JacksonUtils;
import org.springframework.util.Assert;

View File

@@ -48,9 +48,9 @@ public class FunctionCallingHelper extends AbstractToolCallSupport {
this(null, PortableFunctionCallingOptions.builder().build(), List.of());
}
public FunctionCallingHelper(FunctionCallbackContext functionCallbackContext,
public FunctionCallingHelper(FunctionCallbackResolver functionCallbackResolver,
FunctionCallingOptions functionCallingOptions, List<FunctionCallback> toolFunctionCallbacks) {
super(functionCallbackContext, functionCallingOptions, toolFunctionCallbacks);
super(functionCallbackResolver, functionCallingOptions, toolFunctionCallbacks);
}
@Override

View File

@@ -24,8 +24,9 @@ import org.springframework.ai.anthropic.AnthropicChatModel;
import org.springframework.ai.anthropic.api.AnthropicApi;
import org.springframework.ai.autoconfigure.retry.SpringAiRetryAutoConfiguration;
import org.springframework.ai.chat.observation.ChatModelObservationConvention;
import org.springframework.ai.model.function.DefaultFunctionCallbackResolver;
import org.springframework.ai.model.function.FunctionCallback;
import org.springframework.ai.model.function.FunctionCallbackContext;
import org.springframework.ai.model.function.FunctionCallbackResolver;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
@@ -73,12 +74,12 @@ public class AnthropicAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public AnthropicChatModel anthropicChatModel(AnthropicApi anthropicApi, AnthropicChatProperties chatProperties,
RetryTemplate retryTemplate, FunctionCallbackContext functionCallbackContext,
RetryTemplate retryTemplate, DefaultFunctionCallbackResolver functionCallbackResolver,
List<FunctionCallback> toolFunctionCallbacks, ObjectProvider<ObservationRegistry> observationRegistry,
ObjectProvider<ChatModelObservationConvention> observationConvention) {
var chatModel = new AnthropicChatModel(anthropicApi, chatProperties.getOptions(), retryTemplate,
functionCallbackContext, toolFunctionCallbacks,
functionCallbackResolver, toolFunctionCallbacks,
observationRegistry.getIfUnique(() -> ObservationRegistry.NOOP));
observationConvention.ifAvailable(chatModel::setObservationConvention);
@@ -88,8 +89,8 @@ public class AnthropicAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public FunctionCallbackContext springAiFunctionManager(ApplicationContext context) {
FunctionCallbackContext manager = new FunctionCallbackContext();
public FunctionCallbackResolver springAiFunctionManager(ApplicationContext context) {
DefaultFunctionCallbackResolver manager = new DefaultFunctionCallbackResolver();
manager.setApplicationContext(context);
return manager;
}

View File

@@ -34,8 +34,9 @@ import org.springframework.ai.azure.openai.AzureOpenAiEmbeddingModel;
import org.springframework.ai.azure.openai.AzureOpenAiImageModel;
import org.springframework.ai.chat.observation.ChatModelObservationConvention;
import org.springframework.ai.embedding.observation.EmbeddingModelObservationConvention;
import org.springframework.ai.model.function.DefaultFunctionCallbackResolver;
import org.springframework.ai.model.function.FunctionCallback;
import org.springframework.ai.model.function.FunctionCallbackContext;
import org.springframework.ai.model.function.FunctionCallbackResolver;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
@@ -112,11 +113,11 @@ public class AzureOpenAiAutoConfiguration {
matchIfMissing = true)
public AzureOpenAiChatModel azureOpenAiChatModel(OpenAIClientBuilder openAIClientBuilder,
AzureOpenAiChatProperties chatProperties, List<FunctionCallback> toolFunctionCallbacks,
FunctionCallbackContext functionCallbackContext, ObjectProvider<ObservationRegistry> observationRegistry,
FunctionCallbackResolver functionCallbackResolver, ObjectProvider<ObservationRegistry> observationRegistry,
ObjectProvider<ChatModelObservationConvention> observationConvention) {
var chatModel = new AzureOpenAiChatModel(openAIClientBuilder, chatProperties.getOptions(),
functionCallbackContext, toolFunctionCallbacks,
functionCallbackResolver, toolFunctionCallbacks,
observationRegistry.getIfUnique(() -> ObservationRegistry.NOOP));
observationConvention.ifAvailable(chatModel::setObservationConvention);
@@ -143,8 +144,8 @@ public class AzureOpenAiAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public FunctionCallbackContext springAiFunctionManager(ApplicationContext context) {
FunctionCallbackContext manager = new FunctionCallbackContext();
public FunctionCallbackResolver springAiFunctionManager(ApplicationContext context) {
DefaultFunctionCallbackResolver manager = new DefaultFunctionCallbackResolver();
manager.setApplicationContext(context);
return manager;
}

View File

@@ -28,8 +28,9 @@ import org.springframework.ai.autoconfigure.bedrock.BedrockAwsConnectionConfigur
import org.springframework.ai.autoconfigure.bedrock.BedrockAwsConnectionProperties;
import org.springframework.ai.bedrock.converse.BedrockProxyChatModel;
import org.springframework.ai.chat.observation.ChatModelObservationConvention;
import org.springframework.ai.model.function.DefaultFunctionCallbackResolver;
import org.springframework.ai.model.function.FunctionCallback;
import org.springframework.ai.model.function.FunctionCallbackContext;
import org.springframework.ai.model.function.FunctionCallbackResolver;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
@@ -62,7 +63,7 @@ public class BedrockConverseProxyChatAutoConfiguration {
@ConditionalOnBean({ AwsCredentialsProvider.class, AwsRegionProvider.class })
public BedrockProxyChatModel bedrockProxyChatModel(AwsCredentialsProvider credentialsProvider,
AwsRegionProvider regionProvider, BedrockAwsConnectionProperties connectionProperties,
BedrockConverseProxyChatProperties chatProperties, FunctionCallbackContext functionCallbackContext,
BedrockConverseProxyChatProperties chatProperties, FunctionCallbackResolver functionCallbackResolver,
List<FunctionCallback> toolFunctionCallbacks, ObjectProvider<ObservationRegistry> observationRegistry,
ObjectProvider<ChatModelObservationConvention> observationConvention,
ObjectProvider<BedrockRuntimeClient> bedrockRuntimeClient,
@@ -74,7 +75,7 @@ public class BedrockConverseProxyChatAutoConfiguration {
.withTimeout(connectionProperties.getTimeout())
.withDefaultOptions(chatProperties.getOptions())
.withObservationRegistry(observationRegistry.getIfUnique(() -> ObservationRegistry.NOOP))
.withFunctionCallbackContext(functionCallbackContext)
.functionCallbackResolver(functionCallbackResolver)
.withToolFunctionCallbacks(toolFunctionCallbacks)
.withBedrockRuntimeClient(bedrockRuntimeClient.getIfAvailable())
.withBedrockRuntimeAsyncClient(bedrockRuntimeAsyncClient.getIfAvailable())
@@ -87,8 +88,8 @@ public class BedrockConverseProxyChatAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public FunctionCallbackContext springAiFunctionManager(ApplicationContext context) {
FunctionCallbackContext manager = new FunctionCallbackContext();
public FunctionCallbackResolver springAiFunctionManager(ApplicationContext context) {
DefaultFunctionCallbackResolver manager = new DefaultFunctionCallbackResolver();
manager.setApplicationContext(context);
return manager;
}

View File

@@ -27,7 +27,8 @@ import org.springframework.ai.minimax.MiniMaxChatModel;
import org.springframework.ai.minimax.MiniMaxEmbeddingModel;
import org.springframework.ai.minimax.api.MiniMaxApi;
import org.springframework.ai.model.function.FunctionCallback;
import org.springframework.ai.model.function.FunctionCallbackContext;
import org.springframework.ai.model.function.FunctionCallbackResolver;
import org.springframework.ai.model.function.DefaultFunctionCallbackResolver;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
@@ -60,7 +61,7 @@ public class MiniMaxAutoConfiguration {
matchIfMissing = true)
public MiniMaxChatModel miniMaxChatModel(MiniMaxConnectionProperties commonProperties,
MiniMaxChatProperties chatProperties, ObjectProvider<RestClient.Builder> restClientBuilderProvider,
List<FunctionCallback> toolFunctionCallbacks, FunctionCallbackContext functionCallbackContext,
List<FunctionCallback> toolFunctionCallbacks, FunctionCallbackResolver functionCallbackResolver,
RetryTemplate retryTemplate, ResponseErrorHandler responseErrorHandler,
ObjectProvider<ObservationRegistry> observationRegistry,
ObjectProvider<ChatModelObservationConvention> observationConvention) {
@@ -69,7 +70,7 @@ public class MiniMaxAutoConfiguration {
chatProperties.getApiKey(), commonProperties.getApiKey(),
restClientBuilderProvider.getIfAvailable(RestClient::builder), responseErrorHandler);
var chatModel = new MiniMaxChatModel(miniMaxApi, chatProperties.getOptions(), functionCallbackContext,
var chatModel = new MiniMaxChatModel(miniMaxApi, chatProperties.getOptions(), functionCallbackResolver,
toolFunctionCallbacks, retryTemplate, observationRegistry.getIfUnique(() -> ObservationRegistry.NOOP));
observationConvention.ifAvailable(chatModel::setObservationConvention);
@@ -113,8 +114,8 @@ public class MiniMaxAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public FunctionCallbackContext springAiFunctionManager(ApplicationContext context) {
FunctionCallbackContext manager = new FunctionCallbackContext();
public FunctionCallbackResolver springAiFunctionManager(ApplicationContext context) {
DefaultFunctionCallbackResolver manager = new DefaultFunctionCallbackResolver();
manager.setApplicationContext(context);
return manager;
}

View File

@@ -26,8 +26,9 @@ import org.springframework.ai.embedding.observation.EmbeddingModelObservationCon
import org.springframework.ai.mistralai.MistralAiChatModel;
import org.springframework.ai.mistralai.MistralAiEmbeddingModel;
import org.springframework.ai.mistralai.api.MistralAiApi;
import org.springframework.ai.model.function.DefaultFunctionCallbackResolver;
import org.springframework.ai.model.function.FunctionCallback;
import org.springframework.ai.model.function.FunctionCallbackContext;
import org.springframework.ai.model.function.FunctionCallbackResolver;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
@@ -90,7 +91,7 @@ public class MistralAiAutoConfiguration {
matchIfMissing = true)
public MistralAiChatModel mistralAiChatModel(MistralAiCommonProperties commonProperties,
MistralAiChatProperties chatProperties, ObjectProvider<RestClient.Builder> restClientBuilderProvider,
List<FunctionCallback> toolFunctionCallbacks, FunctionCallbackContext functionCallbackContext,
List<FunctionCallback> toolFunctionCallbacks, FunctionCallbackResolver functionCallbackResolver,
RetryTemplate retryTemplate, ResponseErrorHandler responseErrorHandler,
ObjectProvider<ObservationRegistry> observationRegistry,
ObjectProvider<ChatModelObservationConvention> observationConvention) {
@@ -99,7 +100,7 @@ public class MistralAiAutoConfiguration {
chatProperties.getBaseUrl(), commonProperties.getBaseUrl(),
restClientBuilderProvider.getIfAvailable(RestClient::builder), responseErrorHandler);
var chatModel = new MistralAiChatModel(mistralAiApi, chatProperties.getOptions(), functionCallbackContext,
var chatModel = new MistralAiChatModel(mistralAiApi, chatProperties.getOptions(), functionCallbackResolver,
toolFunctionCallbacks, retryTemplate, observationRegistry.getIfUnique(() -> ObservationRegistry.NOOP));
observationConvention.ifAvailable(chatModel::setObservationConvention);
@@ -121,8 +122,8 @@ public class MistralAiAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public FunctionCallbackContext springAiFunctionManager(ApplicationContext context) {
FunctionCallbackContext manager = new FunctionCallbackContext();
public FunctionCallbackResolver springAiFunctionManager(ApplicationContext context) {
DefaultFunctionCallbackResolver manager = new DefaultFunctionCallbackResolver();
manager.setApplicationContext(context);
return manager;
}

View File

@@ -22,8 +22,9 @@ import io.micrometer.observation.ObservationRegistry;
import org.springframework.ai.autoconfigure.retry.SpringAiRetryAutoConfiguration;
import org.springframework.ai.chat.observation.ChatModelObservationConvention;
import org.springframework.ai.model.function.DefaultFunctionCallbackResolver;
import org.springframework.ai.model.function.FunctionCallback;
import org.springframework.ai.model.function.FunctionCallbackContext;
import org.springframework.ai.model.function.FunctionCallbackResolver;
import org.springframework.ai.moonshot.MoonshotChatModel;
import org.springframework.ai.moonshot.api.MoonshotApi;
import org.springframework.beans.factory.ObjectProvider;
@@ -57,7 +58,7 @@ public class MoonshotAutoConfiguration {
matchIfMissing = true)
public MoonshotChatModel moonshotChatModel(MoonshotCommonProperties commonProperties,
MoonshotChatProperties chatProperties, ObjectProvider<RestClient.Builder> restClientBuilderProvider,
List<FunctionCallback> toolFunctionCallbacks, FunctionCallbackContext functionCallbackContext,
List<FunctionCallback> toolFunctionCallbacks, FunctionCallbackResolver functionCallbackResolver,
RetryTemplate retryTemplate, ResponseErrorHandler responseErrorHandler,
ObjectProvider<ObservationRegistry> observationRegistry,
ObjectProvider<ChatModelObservationConvention> observationConvention) {
@@ -66,7 +67,7 @@ public class MoonshotAutoConfiguration {
chatProperties.getBaseUrl(), commonProperties.getBaseUrl(),
restClientBuilderProvider.getIfAvailable(RestClient::builder), responseErrorHandler);
var chatModel = new MoonshotChatModel(moonshotApi, chatProperties.getOptions(), functionCallbackContext,
var chatModel = new MoonshotChatModel(moonshotApi, chatProperties.getOptions(), functionCallbackResolver,
toolFunctionCallbacks, retryTemplate, observationRegistry.getIfUnique(() -> ObservationRegistry.NOOP));
observationConvention.ifAvailable(chatModel::setObservationConvention);
@@ -75,8 +76,8 @@ public class MoonshotAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public FunctionCallbackContext springAiFunctionManager(ApplicationContext context) {
FunctionCallbackContext manager = new FunctionCallbackContext();
public FunctionCallbackResolver springAiFunctionManager(ApplicationContext context) {
DefaultFunctionCallbackResolver manager = new DefaultFunctionCallbackResolver();
manager.setApplicationContext(context);
return manager;
}

View File

@@ -22,8 +22,9 @@ import io.micrometer.observation.ObservationRegistry;
import org.springframework.ai.chat.observation.ChatModelObservationConvention;
import org.springframework.ai.embedding.observation.EmbeddingModelObservationConvention;
import org.springframework.ai.model.function.DefaultFunctionCallbackResolver;
import org.springframework.ai.model.function.FunctionCallback;
import org.springframework.ai.model.function.FunctionCallbackContext;
import org.springframework.ai.model.function.FunctionCallbackResolver;
import org.springframework.ai.ollama.OllamaChatModel;
import org.springframework.ai.ollama.OllamaEmbeddingModel;
import org.springframework.ai.ollama.api.OllamaApi;
@@ -80,7 +81,7 @@ public class OllamaAutoConfiguration {
matchIfMissing = true)
public OllamaChatModel ollamaChatModel(OllamaApi ollamaApi, OllamaChatProperties properties,
OllamaInitializationProperties initProperties, List<FunctionCallback> toolFunctionCallbacks,
FunctionCallbackContext functionCallbackContext, ObjectProvider<ObservationRegistry> observationRegistry,
FunctionCallbackResolver functionCallbackResolver, ObjectProvider<ObservationRegistry> observationRegistry,
ObjectProvider<ChatModelObservationConvention> observationConvention) {
var chatModelPullStrategy = initProperties.getChat().isInclude() ? initProperties.getPullModelStrategy()
: PullModelStrategy.NEVER;
@@ -88,7 +89,7 @@ public class OllamaAutoConfiguration {
var chatModel = OllamaChatModel.builder()
.withOllamaApi(ollamaApi)
.withDefaultOptions(properties.getOptions())
.withFunctionCallbackContext(functionCallbackContext)
.functionCallbackResolver(functionCallbackResolver)
.withToolFunctionCallbacks(toolFunctionCallbacks)
.withObservationRegistry(observationRegistry.getIfUnique(() -> ObservationRegistry.NOOP))
.withModelManagementOptions(
@@ -127,8 +128,8 @@ public class OllamaAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public FunctionCallbackContext springAiFunctionManager(ApplicationContext context) {
FunctionCallbackContext manager = new FunctionCallbackContext();
public FunctionCallbackResolver springAiFunctionManager(ApplicationContext context) {
DefaultFunctionCallbackResolver manager = new DefaultFunctionCallbackResolver();
manager.setApplicationContext(context);
return manager;
}

View File

@@ -27,8 +27,9 @@ import org.springframework.ai.autoconfigure.retry.SpringAiRetryAutoConfiguration
import org.springframework.ai.chat.observation.ChatModelObservationConvention;
import org.springframework.ai.embedding.observation.EmbeddingModelObservationConvention;
import org.springframework.ai.image.observation.ImageModelObservationConvention;
import org.springframework.ai.model.function.DefaultFunctionCallbackResolver;
import org.springframework.ai.model.function.FunctionCallback;
import org.springframework.ai.model.function.FunctionCallbackContext;
import org.springframework.ai.model.function.FunctionCallbackResolver;
import org.springframework.ai.openai.OpenAiAudioSpeechModel;
import org.springframework.ai.openai.OpenAiAudioTranscriptionModel;
import org.springframework.ai.openai.OpenAiChatModel;
@@ -113,7 +114,7 @@ public class OpenAiAutoConfiguration {
public OpenAiChatModel openAiChatModel(OpenAiConnectionProperties commonProperties,
OpenAiChatProperties chatProperties, ObjectProvider<RestClient.Builder> restClientBuilderProvider,
ObjectProvider<WebClient.Builder> webClientBuilderProvider, List<FunctionCallback> toolFunctionCallbacks,
FunctionCallbackContext functionCallbackContext, RetryTemplate retryTemplate,
FunctionCallbackResolver functionCallbackResolver, RetryTemplate retryTemplate,
ResponseErrorHandler responseErrorHandler, ObjectProvider<ObservationRegistry> observationRegistry,
ObjectProvider<ChatModelObservationConvention> observationConvention) {
@@ -121,7 +122,7 @@ public class OpenAiAutoConfiguration {
restClientBuilderProvider.getIfAvailable(RestClient::builder),
webClientBuilderProvider.getIfAvailable(WebClient::builder), responseErrorHandler, "chat");
var chatModel = new OpenAiChatModel(openAiApi, chatProperties.getOptions(), functionCallbackContext,
var chatModel = new OpenAiChatModel(openAiApi, chatProperties.getOptions(), functionCallbackResolver,
toolFunctionCallbacks, retryTemplate, observationRegistry.getIfUnique(() -> ObservationRegistry.NOOP));
observationConvention.ifAvailable(chatModel::setObservationConvention);
@@ -256,8 +257,8 @@ public class OpenAiAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public FunctionCallbackContext springAiFunctionManager(ApplicationContext context) {
FunctionCallbackContext manager = new FunctionCallbackContext();
public FunctionCallbackResolver springAiFunctionManager(ApplicationContext context) {
DefaultFunctionCallbackResolver manager = new DefaultFunctionCallbackResolver();
manager.setApplicationContext(context);
return manager;
}

View File

@@ -22,7 +22,8 @@ import org.springframework.ai.autoconfigure.retry.SpringAiRetryAutoConfiguration
import org.springframework.ai.chat.observation.ChatModelObservationConvention;
import org.springframework.ai.embedding.observation.EmbeddingModelObservationConvention;
import org.springframework.ai.image.observation.ImageModelObservationConvention;
import org.springframework.ai.model.function.FunctionCallbackContext;
import org.springframework.ai.model.function.DefaultFunctionCallbackResolver;
import org.springframework.ai.model.function.FunctionCallbackResolver;
import org.springframework.ai.qianfan.QianFanChatModel;
import org.springframework.ai.qianfan.QianFanEmbeddingModel;
import org.springframework.ai.qianfan.QianFanImageModel;
@@ -155,8 +156,8 @@ public class QianFanAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public FunctionCallbackContext springAiFunctionManager(ApplicationContext context) {
FunctionCallbackContext manager = new FunctionCallbackContext();
public FunctionCallbackResolver springAiFunctionManager(ApplicationContext context) {
DefaultFunctionCallbackResolver manager = new DefaultFunctionCallbackResolver();
manager.setApplicationContext(context);
return manager;
}

View File

@@ -26,8 +26,9 @@ import io.micrometer.observation.ObservationRegistry;
import org.springframework.ai.autoconfigure.retry.SpringAiRetryAutoConfiguration;
import org.springframework.ai.chat.observation.ChatModelObservationConvention;
import org.springframework.ai.model.function.FunctionCallback;
import org.springframework.ai.model.function.FunctionCallbackContext;
import org.springframework.ai.model.function.FunctionCallbackContext.SchemaType;
import org.springframework.ai.model.function.FunctionCallback.SchemaType;
import org.springframework.ai.model.function.FunctionCallbackResolver;
import org.springframework.ai.model.function.DefaultFunctionCallbackResolver;
import org.springframework.ai.vertexai.gemini.VertexAiGeminiChatModel;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
@@ -94,21 +95,21 @@ public class VertexAiGeminiAutoConfiguration {
ObjectProvider<ObservationRegistry> observationRegistry,
ObjectProvider<ChatModelObservationConvention> observationConvention) {
FunctionCallbackContext functionCallbackContext = springAiFunctionManager(context);
FunctionCallbackResolver functionCallbackResolver = springAiFunctionManager(context);
VertexAiGeminiChatModel chatModel = new VertexAiGeminiChatModel(vertexAi, chatProperties.getOptions(),
functionCallbackContext, toolFunctionCallbacks, retryTemplate,
functionCallbackResolver, toolFunctionCallbacks, retryTemplate,
observationRegistry.getIfUnique(() -> ObservationRegistry.NOOP));
observationConvention.ifAvailable(chatModel::setObservationConvention);
return chatModel;
}
/**
* Because of the OPEN_API_SCHEMA type, the FunctionCallbackContext instance must
* Because of the OPEN_API_SCHEMA type, the FunctionCallbackResolver instance must
* different from the other JSON schema types.
*/
private FunctionCallbackContext springAiFunctionManager(ApplicationContext context) {
FunctionCallbackContext manager = new FunctionCallbackContext();
private FunctionCallbackResolver springAiFunctionManager(ApplicationContext context) {
DefaultFunctionCallbackResolver manager = new DefaultFunctionCallbackResolver();
manager.setSchemaType(SchemaType.OPEN_API_SCHEMA);
manager.setApplicationContext(context);
return manager;

View File

@@ -23,8 +23,9 @@ import io.micrometer.observation.ObservationRegistry;
import org.springframework.ai.autoconfigure.retry.SpringAiRetryAutoConfiguration;
import org.springframework.ai.chat.observation.ChatModelObservationConvention;
import org.springframework.ai.embedding.observation.EmbeddingModelObservationConvention;
import org.springframework.ai.model.function.DefaultFunctionCallbackResolver;
import org.springframework.ai.model.function.FunctionCallback;
import org.springframework.ai.model.function.FunctionCallbackContext;
import org.springframework.ai.model.function.FunctionCallbackResolver;
import org.springframework.ai.zhipuai.ZhiPuAiChatModel;
import org.springframework.ai.zhipuai.ZhiPuAiEmbeddingModel;
import org.springframework.ai.zhipuai.ZhiPuAiImageModel;
@@ -62,7 +63,7 @@ public class ZhiPuAiAutoConfiguration {
matchIfMissing = true)
public ZhiPuAiChatModel zhiPuAiChatModel(ZhiPuAiConnectionProperties commonProperties,
ZhiPuAiChatProperties chatProperties, ObjectProvider<RestClient.Builder> restClientBuilderProvider,
List<FunctionCallback> toolFunctionCallbacks, FunctionCallbackContext functionCallbackContext,
List<FunctionCallback> toolFunctionCallbacks, FunctionCallbackResolver functionCallbackResolver,
RetryTemplate retryTemplate, ResponseErrorHandler responseErrorHandler,
ObjectProvider<ObservationRegistry> observationRegistry,
ObjectProvider<ChatModelObservationConvention> observationConvention) {
@@ -71,7 +72,7 @@ public class ZhiPuAiAutoConfiguration {
chatProperties.getApiKey(), commonProperties.getApiKey(),
restClientBuilderProvider.getIfAvailable(RestClient::builder), responseErrorHandler);
var chatModel = new ZhiPuAiChatModel(zhiPuAiApi, chatProperties.getOptions(), functionCallbackContext,
var chatModel = new ZhiPuAiChatModel(zhiPuAiApi, chatProperties.getOptions(), functionCallbackResolver,
toolFunctionCallbacks, retryTemplate, observationRegistry.getIfUnique(() -> ObservationRegistry.NOOP));
observationConvention.ifAvailable(chatModel::setObservationConvention);
@@ -137,8 +138,8 @@ public class ZhiPuAiAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public FunctionCallbackContext springAiFunctionManager(ApplicationContext context) {
FunctionCallbackContext manager = new FunctionCallbackContext();
public FunctionCallbackResolver springAiFunctionManager(ApplicationContext context) {
DefaultFunctionCallbackResolver manager = new DefaultFunctionCallbackResolver();
manager.setApplicationContext(context);
return manager;
}

View File

@@ -28,7 +28,7 @@ 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.FunctionCallback;
import org.springframework.ai.model.function.FunctionCallbackContext.SchemaType;
import org.springframework.ai.model.function.FunctionCallback.SchemaType;
import org.springframework.ai.vertexai.gemini.VertexAiGeminiChatModel;
import org.springframework.ai.vertexai.gemini.VertexAiGeminiChatOptions;
import org.springframework.boot.autoconfigure.AutoConfigurations;

View File

@@ -28,7 +28,7 @@ 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.FunctionCallback;
import org.springframework.ai.model.function.FunctionCallbackContext.SchemaType;
import org.springframework.ai.model.function.FunctionCallback.SchemaType;
import org.springframework.ai.vertexai.gemini.VertexAiGeminiChatModel;
import org.springframework.ai.vertexai.gemini.VertexAiGeminiChatOptions;
import org.springframework.boot.autoconfigure.AutoConfigurations;

View File

@@ -35,7 +35,7 @@ import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.Description
class FunctionCallbackContextKotlinIT : BaseOllamaIT() {
class FunctionCallbackResolverKotlinIT : BaseOllamaIT() {
companion object {
@@ -48,7 +48,7 @@ class FunctionCallbackContextKotlinIT : BaseOllamaIT() {
}
}
private val logger = LoggerFactory.getLogger(FunctionCallbackContextKotlinIT::class.java)
private val logger = LoggerFactory.getLogger(FunctionCallbackResolverKotlinIT::class.java)
private val contextRunner = ApplicationContextRunner()
.withPropertyValues(