Core model interfaces and abstractions for Spring AI framework providing portable API for chat, embeddings, images, audio, and tool calling across multiple AI providers
Advanced chat options for configuring tool/function calling behavior, including tool registration, execution control, and context management.
Extended chat options interface specifically for tool calling functionality.
public interface ToolCallingChatOptions extends ChatOptions {
/**
* Default value for tool execution enabled flag.
*/
boolean DEFAULT_TOOL_EXECUTION_ENABLED = true;
/**
* Get the tool callbacks registered with the chat model.
*
* @return list of tool callbacks
*/
List<ToolCallback> getToolCallbacks();
/**
* Set the tool callbacks to be registered with the chat model.
*
* @param toolCallbacks the list of tool callbacks
*/
void setToolCallbacks(List<ToolCallback> toolCallbacks);
/**
* Get the names of the tools to register with the chat model.
*
* @return set of tool names
*/
Set<String> getToolNames();
/**
* Set the names of the tools to register with the chat model.
*
* @param toolNames the set of tool names
*/
void setToolNames(Set<String> toolNames);
/**
* Whether the ChatModel is responsible for executing tools requested by the model,
* or if tools should be executed directly by the caller.
*
* @return true if internal tool execution is enabled, false if manual execution, null for default
*/
@Nullable
Boolean getInternalToolExecutionEnabled();
/**
* Set whether the ChatModel is responsible for executing the tools.
*
* @param internalToolExecutionEnabled true for internal execution, false for manual
*/
void setInternalToolExecutionEnabled(@Nullable Boolean internalToolExecutionEnabled);
/**
* Get the configured tool context.
*
* @return the tool context map
*/
Map<String, Object> getToolContext();
/**
* Set the tool context values as map.
*
* @param toolContext the tool context map
*/
void setToolContext(Map<String, Object> toolContext);
/**
* Create a new builder for ToolCallingChatOptions.
*
* @return a new builder
*/
static Builder builder();
/**
* Check if internal tool execution is enabled for the given chat options.
*
* @param chatOptions the chat options to check
* @return true if internal execution is enabled
*/
static boolean isInternalToolExecutionEnabled(ChatOptions chatOptions);
/**
* Merge runtime and default tool names.
*
* @param runtimeToolNames the runtime tool names
* @param defaultToolNames the default tool names
* @return merged set of tool names
*/
static Set<String> mergeToolNames(Set<String> runtimeToolNames, Set<String> defaultToolNames);
/**
* Merge runtime and default tool callbacks.
*
* @param runtimeToolCallbacks the runtime tool callbacks
* @param defaultToolCallbacks the default tool callbacks
* @return merged list of tool callbacks
*/
static List<ToolCallback> mergeToolCallbacks(
List<ToolCallback> runtimeToolCallbacks,
List<ToolCallback> defaultToolCallbacks
);
/**
* Merge runtime and default tool context.
*
* @param runtimeToolContext the runtime tool context
* @param defaultToolContext the default tool context
* @return merged tool context map
*/
static Map<String, Object> mergeToolContext(
Map<String, Object> runtimeToolContext,
Map<String, Object> defaultToolContext
);
/**
* Validate that tool callbacks don't have duplicate names.
*
* @param toolCallbacks the tool callbacks to validate
* @throws IllegalStateException if duplicate tool names found
*/
static void validateToolCallbacks(List<ToolCallback> toolCallbacks);
}Builder interface for constructing ToolCallingChatOptions instances.
interface Builder extends ChatOptions.Builder {
/**
* Set tool callbacks to be registered with the ChatModel.
*
* @param toolCallbacks the list of tool callbacks
* @return this builder
*/
Builder toolCallbacks(List<ToolCallback> toolCallbacks);
/**
* Set tool callbacks to be registered with the ChatModel.
*
* @param toolCallbacks varargs of tool callbacks
* @return this builder
*/
Builder toolCallbacks(ToolCallback... toolCallbacks);
/**
* Set names of the tools to register with the ChatModel.
*
* @param toolNames the set of tool names
* @return this builder
*/
Builder toolNames(Set<String> toolNames);
/**
* Set names of the tools to register with the ChatModel.
*
* @param toolNames varargs of tool names
* @return this builder
*/
Builder toolNames(String... toolNames);
/**
* Set whether the ChatModel is responsible for executing the tools.
*
* @param internalToolExecutionEnabled true for internal execution
* @return this builder
*/
Builder internalToolExecutionEnabled(@Nullable Boolean internalToolExecutionEnabled);
/**
* Add a Map of context values into tool context.
*
* @param context the map representing the tool context
* @return this builder
*/
Builder 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 this builder
*/
Builder toolContext(String key, Object value);
// ChatOptions.Builder methods
@Override
Builder model(@Nullable String model);
@Override
Builder frequencyPenalty(@Nullable Double frequencyPenalty);
@Override
Builder maxTokens(@Nullable Integer maxTokens);
@Override
Builder presencePenalty(@Nullable Double presencePenalty);
@Override
Builder stopSequences(@Nullable List<String> stopSequences);
@Override
Builder temperature(@Nullable Double temperature);
@Override
Builder topK(@Nullable Integer topK);
@Override
Builder topP(@Nullable Double topP);
@Override
ToolCallingChatOptions build();
}Mixin interface for ChatModels that support structured output with JSON schema.
public interface StructuredOutputChatOptions extends ChatOptions {
/**
* Get the output JSON schema.
*
* @return the JSON schema string
*/
String getOutputSchema();
/**
* Set the output JSON schema for structured responses.
*
* @param outputSchema the JSON schema string
*/
void setOutputSchema(String outputSchema);
}Default implementation of ToolCallingChatOptions.
public class DefaultToolCallingChatOptions implements ToolCallingChatOptions {
// Implementation of all ToolCallingChatOptions and ChatOptions methods
// with getters and setters for tool callbacks, tool names, tool context,
// internal tool execution flag, and all standard chat options
}Represents the context for tool execution in function calling scenarios.
public final class ToolContext {
/**
* Key for the tool call history stored in the context map.
*/
public static final String TOOL_CALL_HISTORY = "TOOL_CALL_HISTORY";
/**
* Constructs a new ToolContext with the given context map.
*
* @param context A map containing the tool context information (made unmodifiable)
*/
public ToolContext(Map<String, Object> context);
/**
* Returns the immutable context map.
*
* @return An unmodifiable view of the context map
*/
public Map<String, Object> getContext();
/**
* Returns the tool call history from the context map.
*
* @return The tool call history
*/
public List<Message> getToolCallHistory();
}Service responsible for managing the tool calling process for a chat model.
public interface ToolCallingManager {
/**
* Resolve the tool definitions from the model's tool calling options.
*
* @param chatOptions the tool calling chat options
* @return list of resolved tool definitions
*/
List<ToolDefinition> resolveToolDefinitions(ToolCallingChatOptions chatOptions);
/**
* Execute the tool calls requested by the model.
*
* @param prompt the original prompt
* @param chatResponse the chat response containing tool calls
* @return the tool execution result
*/
ToolExecutionResult executeToolCalls(Prompt prompt, ChatResponse chatResponse);
/**
* Create a default ToolCallingManager builder.
*
* @return a new builder
*/
static DefaultToolCallingManager.Builder builder();
}Default implementation of ToolCallingManager.
public final class DefaultToolCallingManager implements ToolCallingManager {
/**
* Construct a DefaultToolCallingManager with required dependencies.
*
* @param observationRegistry the observation registry for metrics
* @param toolCallbackResolver the resolver for tool callbacks
* @param toolExecutionExceptionProcessor the processor for tool exceptions
*/
public DefaultToolCallingManager(
ObservationRegistry observationRegistry,
ToolCallbackResolver toolCallbackResolver,
ToolExecutionExceptionProcessor toolExecutionExceptionProcessor
);
@Override
public List<ToolDefinition> resolveToolDefinitions(ToolCallingChatOptions chatOptions);
@Override
public ToolExecutionResult executeToolCalls(Prompt prompt, ChatResponse chatResponse);
/**
* Create a new builder.
*
* @return a new builder
*/
public static Builder builder();
/**
* Builder for DefaultToolCallingManager.
*/
public static final class Builder {
/**
* Set the observation registry.
*
* @param observationRegistry the observation registry
* @return this builder
*/
public Builder observationRegistry(ObservationRegistry observationRegistry);
/**
* Set the tool callback resolver.
*
* @param toolCallbackResolver the resolver
* @return this builder
*/
public Builder toolCallbackResolver(ToolCallbackResolver toolCallbackResolver);
/**
* Set the tool execution exception processor.
*
* @param processor the processor
* @return this builder
*/
public Builder toolExecutionExceptionProcessor(ToolExecutionExceptionProcessor processor);
/**
* Build the DefaultToolCallingManager.
*
* @return the manager
*/
public DefaultToolCallingManager build();
}
}The result of a tool execution, containing conversation history and execution metadata.
public interface ToolExecutionResult {
/**
* Finish reason constant for direct return tools.
* When a tool is marked with returnDirect=true, this finish reason is used.
*/
String FINISH_REASON = "returnDirect";
/**
* Metadata key for tool ID.
* Used to store the unique identifier of the executed tool in message metadata.
*/
String METADATA_TOOL_ID = "toolId";
/**
* Metadata key for tool name.
* Used to store the name of the executed tool in message metadata.
*/
String METADATA_TOOL_NAME = "toolName";
/**
* Get the history of messages exchanged during the conversation,
* including the tool execution result.
* This includes the original assistant message with tool calls and the tool response messages.
*
* @return the conversation history with tool calls and responses
*/
List<Message> conversationHistory();
/**
* Check whether the tool execution result should be returned directly
* or passed back to the model for further processing.
* Returns true when any executed tool has returnDirect=true.
*
* @return true if result should be returned directly to the user
*/
default boolean returnDirect() {
return false;
}
/**
* Check if the execution result contains any tool calls that need processing.
* This is useful for determining if another model call is needed.
*
* @return true if there are tool calls in the conversation history
*/
default boolean hasToolCalls() {
return conversationHistory().stream()
.filter(msg -> msg instanceof AssistantMessage)
.map(msg -> (AssistantMessage) msg)
.anyMatch(AssistantMessage::hasToolCalls);
}
/**
* Create a default ToolExecutionResult builder.
*
* @return a new builder for constructing ToolExecutionResult instances
*/
static DefaultToolExecutionResult.Builder builder() {
return DefaultToolExecutionResult.builder();
}
/**
* Build a list of Generation from the tool execution result,
* useful for sending the tool execution result to the client directly.
* This is typically used when returnDirect is true.
*
* @param toolExecutionResult the tool execution result to convert
* @return list of generations representing the tool execution results
*/
static List<Generation> buildGenerations(ToolExecutionResult toolExecutionResult) {
return toolExecutionResult.conversationHistory().stream()
.filter(msg -> msg instanceof ToolResponseMessage)
.map(msg -> (ToolResponseMessage) msg)
.flatMap(msg -> msg.getResponses().stream())
.map(response -> new Generation(
new AssistantMessage(response.responseData()),
ChatGenerationMetadata.builder()
.finishReason(FINISH_REASON)
.metadata(METADATA_TOOL_ID, response.id())
.metadata(METADATA_TOOL_NAME, response.name())
.build()
))
.toList();
}
}Predicate for determining whether a tool call is eligible for execution.
public interface ToolExecutionEligibilityPredicate {
/**
* Test whether a tool call should be executed.
* This allows filtering of tool calls based on custom criteria such as
* security policies, rate limiting, or conditional execution logic.
*
* @param toolCall the tool call to test
* @param toolContext the execution context
* @return true if the tool call should be executed
*/
boolean test(AssistantMessage.ToolCall toolCall, ToolContext toolContext);
}Default implementation that allows all tool calls to execute.
public class DefaultToolExecutionEligibilityPredicate implements ToolExecutionEligibilityPredicate {
/**
* Default implementation that returns true for all tool calls.
*
* @param toolCall the tool call to test
* @param toolContext the execution context
* @return always returns true
*/
@Override
public boolean test(AssistantMessage.ToolCall toolCall, ToolContext toolContext) {
return true;
}
}Record implementation of ToolExecutionResult.
public record DefaultToolExecutionResult(
List<Message> conversationHistory,
boolean returnDirect
) implements ToolExecutionResult {
/**
* Create a new builder.
*
* @return a new builder
*/
public static Builder builder();
/**
* Builder for DefaultToolExecutionResult.
*/
public static final class Builder {
/**
* Set the conversation history.
*
* @param conversationHistory the conversation history
* @return this builder
*/
public Builder conversationHistory(List<Message> conversationHistory);
/**
* Set whether to return directly.
*
* @param returnDirect true to return directly
* @return this builder
*/
public Builder returnDirect(boolean returnDirect);
/**
* Build the DefaultToolExecutionResult.
*
* @return the result
*/
public DefaultToolExecutionResult build();
}
}import org.springframework.ai.model.tool.ToolCallingChatOptions;
import org.springframework.ai.tool.ToolCallback;
// Build tool calling options
ToolCallingChatOptions options = ToolCallingChatOptions.builder()
.toolCallbacks(weatherTool, calculatorTool)
.internalToolExecutionEnabled(true) // ChatModel executes tools automatically
.temperature(0.7)
.maxTokens(1000)
.build();
// Use with prompt
Prompt prompt = new Prompt("What's the weather in London?", options);
ChatResponse response = chatModel.call(prompt);// Internal execution (default) - ChatModel handles tool calls automatically
ToolCallingChatOptions autoExecute = ToolCallingChatOptions.builder()
.toolCallbacks(tools)
.internalToolExecutionEnabled(true) // or null for default
.build();
// Manual execution - you handle tool calls yourself
ToolCallingChatOptions manualExecute = ToolCallingChatOptions.builder()
.toolCallbacks(tools)
.internalToolExecutionEnabled(false) // Disable automatic execution
.build();
Prompt prompt = new Prompt("Execute calculation", manualExecute);
ChatResponse response = chatModel.call(prompt);
// With manual execution, you need to check for tool calls and execute them
if (response.getResult().getOutput().hasToolCalls()) {
// Handle tool calls manually
for (AssistantMessage.ToolCall toolCall : response.getResult().getOutput().getToolCalls()) {
// Resolve and execute tool
ToolCallback tool = resolver.resolve(toolCall.name());
String result = tool.call(toolCall.arguments());
// Send result back to model...
}
}// Register specific tools by name
ToolCallingChatOptions options = ToolCallingChatOptions.builder()
.toolNames("getCurrentWeather", "searchDatabase", "sendEmail")
.internalToolExecutionEnabled(true)
.build();
// Or as a set
Set<String> toolNames = Set.of("tool1", "tool2", "tool3");
options = ToolCallingChatOptions.builder()
.toolNames(toolNames)
.build();// Add context information for tools to access
ToolCallingChatOptions options = ToolCallingChatOptions.builder()
.toolCallbacks(databaseTool, userTool)
.toolContext("userId", "user_123")
.toolContext("sessionId", "session_abc")
.toolContext("permissions", List.of("read", "write"))
.build();
// Or as a map
Map<String, Object> context = Map.of(
"userId", "user_123",
"sessionId", "session_abc",
"tenant", "acme_corp"
);
options = ToolCallingChatOptions.builder()
.toolCallbacks(tools)
.toolContext(context)
.build();
// Tools can access context during execution
public class DatabaseTool {
@Tool(description = "Query database")
public String queryDatabase(@ToolParam(description = "Query") String query) {
// Context is available via ToolContext parameter in ToolCallback.call()
return executeQuery(query);
}
}// Define default options
ToolCallingChatOptions defaults = ToolCallingChatOptions.builder()
.toolCallbacks(defaultTools)
.toolNames("defaultTool1", "defaultTool2")
.toolContext("env", "production")
.temperature(0.7)
.build();
// Runtime options
ToolCallingChatOptions runtime = ToolCallingChatOptions.builder()
.toolCallbacks(additionalTools) // Will replace defaults
.toolContext("requestId", "req_123") // Will be merged with defaults
.temperature(0.9) // Will override default
.build();
// Use merge utilities
Set<String> mergedNames = ToolCallingChatOptions.mergeToolNames(
runtime.getToolNames(),
defaults.getToolNames()
);
List<ToolCallback> mergedCallbacks = ToolCallingChatOptions.mergeToolCallbacks(
runtime.getToolCallbacks(),
defaults.getToolCallbacks()
);
Map<String, Object> mergedContext = ToolCallingChatOptions.mergeToolContext(
runtime.getToolContext(),
defaults.getToolContext()
);List<ToolCallback> tools = List.of(
weatherTool,
calculatorTool,
databaseTool
);
// Validate no duplicate names
try {
ToolCallingChatOptions.validateToolCallbacks(tools);
// Safe to use
} catch (IllegalStateException e) {
System.err.println("Duplicate tool names found: " + e.getMessage());
}ChatOptions options = getOptionsFromSomewhere();
// Check if internal execution is enabled
boolean internalExec = ToolCallingChatOptions.isInternalToolExecutionEnabled(options);
if (internalExec) {
System.out.println("ChatModel will execute tools automatically");
} else {
System.out.println("You need to handle tool execution manually");
}@Service
public class ToolCallingService {
private final ChatModel chatModel;
private final List<ToolCallback> tools;
public String processWithContext(String userMessage, String userId, String sessionId) {
// Build options with context
ToolCallingChatOptions options = ToolCallingChatOptions.builder()
.toolCallbacks(tools)
.toolContext("userId", userId)
.toolContext("sessionId", sessionId)
.toolContext("timestamp", System.currentTimeMillis())
.internalToolExecutionEnabled(true)
.temperature(0.7)
.maxTokens(2000)
.build();
// Create prompt
Prompt prompt = new Prompt(userMessage, options);
// Call model - tools will have access to context
ChatResponse response = chatModel.call(prompt);
return response.getResult().getOutput().getText();
}
}@Configuration
public class ToolCallingConfig {
@Bean
public ToolCallingChatOptions defaultToolOptions(List<ToolCallback> tools) {
return ToolCallingChatOptions.builder()
.toolCallbacks(tools)
.internalToolExecutionEnabled(true)
.temperature(0.7)
.maxTokens(1500)
.build();
}
@Bean
public List<ToolCallback> availableTools(
WeatherTool weatherTool,
DatabaseTool databaseTool,
EmailTool emailTool
) {
return List.of(
new MethodToolCallbackProvider(weatherTool).getToolCallbacks(),
new MethodToolCallbackProvider(databaseTool).getToolCallbacks(),
new MethodToolCallbackProvider(emailTool).getToolCallbacks()
).stream().flatMap(List::stream).toList();
}
}import org.springframework.ai.chat.model.ToolContext;
import org.springframework.ai.chat.messages.Message;
// Create context with tool call history
Map<String, Object> contextMap = new HashMap<>();
contextMap.put("userId", "user_123");
contextMap.put(ToolContext.TOOL_CALL_HISTORY, previousMessages);
ToolContext toolContext = new ToolContext(contextMap);
// Access context in tool execution
Map<String, Object> context = toolContext.getContext();
List<Message> history = toolContext.getToolCallHistory();
// Use in options
ToolCallingChatOptions options = ToolCallingChatOptions.builder()
.toolCallbacks(tools)
.toolContext(contextMap)
.build();@Service
public class AdvancedToolService {
private final ChatModel chatModel;
public ChatResponse executeWithAdvancedConfig(String message, boolean autoExecute) {
// Scan beans for tools
MethodToolCallbackProvider provider = new MethodToolCallbackProvider(this);
List<ToolCallback> tools = provider.getToolCallbacks();
// Validate tools
ToolCallingChatOptions.validateToolCallbacks(tools);
// Build options
ToolCallingChatOptions options = ToolCallingChatOptions.builder()
.toolCallbacks(tools)
.internalToolExecutionEnabled(autoExecute)
.toolContext("service", "advanced")
.toolContext("timestamp", System.currentTimeMillis())
.model("gpt-4")
.temperature(0.8)
.maxTokens(2000)
.build();
return chatModel.call(new Prompt(message, options));
}
@Tool(description = "Process user data")
public String processData(@ToolParam(description = "Data to process") String data) {
// Tool implementation with context access
return "Processed: " + data;
}
}