Core model interfaces and abstractions for Spring AI framework providing portable API for chat, embeddings, images, audio, and tool calling across multiple AI providers
Foundational interfaces that define the contract for all AI model types in Spring AI. These abstractions provide a consistent pattern for interacting with different AI capabilities (chat, embeddings, images, audio, etc.) while maintaining type safety and extensibility.
The base interface for all AI models that support synchronous calls.
public interface Model<TReq extends ModelRequest<?>, TRes extends ModelResponse<?>> {
/**
* Execute a synchronous AI model call.
*
* @param request the model request containing instructions and options
* @return the model response containing results and metadata
*/
TRes call(TReq request);
}Interface for models that support streaming responses via reactive streams.
public interface StreamingModel<TReq extends ModelRequest<?>, TResChunk extends ModelResponse<?>> {
/**
* Execute a streaming AI model call returning a Flux of response chunks.
*
* @param request the model request containing instructions and options
* @return Flux of response chunks streamed as they're generated
*/
Flux<TResChunk> stream(TReq request);
}Base interface for all model requests.
public interface ModelRequest<T> {
/**
* Get the instructions or input for the model.
*
* @return the instructions (e.g., messages, text, image prompts, etc.)
*/
T getInstructions();
/**
* Get the model options for this request.
*
* @return the model options
*/
ModelOptions getOptions();
}Base interface for all model responses.
public interface ModelResponse<T extends ModelResult<?>> {
/**
* Get the first result from the response.
*
* @return the first model result
*/
T getResult();
/**
* Get all results from the response.
* Some models can generate multiple alternative results per request.
*
* @return list of all model results
*/
List<T> getResults();
/**
* Get response metadata including usage, rate limits, model info, etc.
*
* @return the response metadata
*/
ResponseMetadata getMetadata();
}Interface for individual results within a response.
public interface ModelResult<T> {
/**
* Get the output/content of this result.
*
* @return the result output
*/
T getOutput();
/**
* Get result-specific metadata (e.g., finish reason, token counts, etc.).
*
* @return the result metadata
*/
ResultMetadata getMetadata();
}Marker interface for model-specific options. Each model type (chat, embeddings, etc.) extends this with specific options.
public interface ModelOptions {
/**
* Marker interface for model-specific options.
* Each model type (chat, embeddings, images, etc.) extends this
* interface with specific configuration options.
*
* Common implementations include:
* - ChatOptions: for chat model configuration
* - EmbeddingOptions: for embedding model configuration
* - ImageOptions: for image generation configuration
* - AudioTranscriptionOptions: for transcription configuration
* - TextToSpeechOptions: for TTS configuration
*/
}Interface for accessing response-level metadata like usage statistics and rate limits.
public interface ResponseMetadata {
/**
* Get a metadata value by key.
*
* @param key the metadata key
* @return the metadata value, or null if not present
*/
<T> T get(String key);
/**
* Get a required metadata value by key.
* Throws exception if key not present.
*
* @param key the metadata key
* @return the metadata value
* @throws IllegalArgumentException if key not found
*/
<T> T getRequired(Object key);
/**
* Check if metadata contains a key.
*
* @param key the key to check
* @return true if the key exists
*/
boolean containsKey(Object key);
/**
* Get a metadata value with a default if not present.
*
* @param key the metadata key
* @param defaultObject the default value
* @return the metadata value or default
*/
<T> T getOrDefault(Object key, T defaultObject);
/**
* Get all metadata entries.
*
* @return set of metadata entries
*/
Set<Map.Entry<String, Object>> entrySet();
/**
* Get all metadata keys.
*
* @return set of metadata keys
*/
Set<String> keySet();
/**
* Check if metadata is empty.
*
* @return true if empty
*/
boolean isEmpty();
}Marker interface for result-specific metadata. Each model type extends this with specific metadata fields.
public interface ResultMetadata {
/**
* Marker interface for result-specific metadata.
* Each model type extends this interface with specific metadata fields.
*
* Common implementations include:
* - ChatGenerationMetadata: for chat generation metadata (finish reason, filters)
* - EmbeddingResultMetadata: for embedding result metadata
* - ImageGenerationMetadata: for image generation metadata
* - AudioTranscriptionMetadata: for transcription metadata
*/
}Base class for implementing ResponseMetadata with common functionality.
public abstract class AbstractResponseMetadata implements ResponseMetadata {
// Base implementation with common metadata handling
}Mutable implementation of ResponseMetadata allowing metadata to be modified after creation.
public class MutableResponseMetadata extends AbstractResponseMetadata {
/**
* Construct an empty MutableResponseMetadata.
*/
public MutableResponseMetadata();
/**
* Construct a MutableResponseMetadata with initial metadata.
*
* @param metadata the initial metadata map
*/
public MutableResponseMetadata(Map<String, Object> metadata);
/**
* Add or update a metadata entry.
*
* @param key the metadata key
* @param value the metadata value
* @return the previous value associated with the key, or null
*/
public Object put(String key, Object value);
/**
* Add all entries from a map to this metadata.
*
* @param metadata the map of metadata to add
*/
public void putAll(Map<String, Object> metadata);
/**
* Remove a metadata entry.
*
* @param key the metadata key to remove
* @return the previous value associated with the key, or null
*/
public Object remove(String key);
/**
* Clear all metadata entries.
*/
public void clear();
}Interfaces for describing model capabilities and metadata.
Base interface for model metadata.
public interface ModelDescription {
/**
* Get the model name/identifier.
*
* @return the model name
*/
String getName();
/**
* Get a human-readable description of the model.
*
* @return the model description
*/
String getDescription();
/**
* Get the model version.
*
* @return the model version
*/
String getVersion();
}Marker interface for chat model descriptions.
public interface ChatModelDescription extends ModelDescription {
// Marker interface for chat models
}Description interface specific to embedding models.
public interface EmbeddingModelDescription extends ModelDescription {
/**
* Get the dimensionality of embeddings produced by this model.
*
* @return the embedding dimensions
*/
int getDimensions();
}Interfaces and implementations for managing API keys securely.
Interface for accessing API keys.
public interface ApiKey {
/**
* Get the API key value.
*
* @return the API key string
*/
String getValue();
}Record implementation of ApiKey for simple use cases.
public record SimpleApiKey(String value) implements ApiKey {
@Override
public String getValue() {
return value;
}
}No-op implementation for cases where no API key is needed.
public class NoopApiKey implements ApiKey {
@Override
public String getValue() {
return null;
}
}Utility methods for working with model options.
public class ModelOptionsUtils {
/**
* Merge model options, with specific options taking precedence over defaults.
*
* @param options the specific options
* @param defaultOptions the default options
* @return merged options
*/
public static <T extends ModelOptions> T merge(T options, T defaultOptions);
// Additional utility methods
}Utility methods for embedding operations.
public class EmbeddingUtils {
/**
* Calculate cosine similarity between two embedding vectors.
*
* @param a first embedding vector
* @param b second embedding vector
* @return cosine similarity score (-1 to 1)
*/
public static double cosineSimilarity(float[] a, float[] b);
/**
* Normalize an embedding vector.
*
* @param embedding the embedding to normalize
* @return normalized embedding
*/
public static float[] normalize(float[] embedding);
// Additional utility methods
}Constants for common AI model names across providers.
public class SpringAIModels {
// OpenAI models
public static final String OPENAI_GPT_4_O = "gpt-4o";
public static final String OPENAI_GPT_4_TURBO = "gpt-4-turbo";
public static final String OPENAI_GPT_3_5_TURBO = "gpt-3.5-turbo";
// Anthropic models
public static final String ANTHROPIC_CLAUDE_3_5_SONNET = "claude-3-5-sonnet-20241022";
public static final String ANTHROPIC_CLAUDE_3_OPUS = "claude-3-opus-20240229";
// Additional model constants
}Configuration properties for Spring AI models.
public class SpringAIModelProperties {
// Configuration property constants and utilities
}Jackson module for Kotlin-specific features and data classes support in Spring AI.
public class KotlinModule extends com.fasterxml.jackson.databind.Module {
/**
* Construct a KotlinModule for Jackson ObjectMapper.
* Enables proper serialization/deserialization of Kotlin data classes.
*/
public KotlinModule();
/**
* Get the module name.
*
* @return the module name
*/
@Override
public String getModuleName();
/**
* Get the module version.
*
* @return the module version
*/
@Override
public Version version();
/**
* Setup the module with the given context.
* Registers Kotlin-specific serializers and deserializers.
*
* @param context the setup context
*/
@Override
public void setupModule(SetupContext context);
}public class MyCustomChatModel implements ChatModel {
private final MyApiClient apiClient;
private final ChatOptions defaultOptions;
@Override
public ChatResponse call(Prompt prompt) {
// Convert prompt to API request
MyApiRequest request = convertPrompt(prompt);
// Call external API
MyApiResponse apiResponse = apiClient.chat(request);
// Convert to ChatResponse
return convertResponse(apiResponse);
}
@Override
public Flux<ChatResponse> stream(Prompt prompt) {
// Implement streaming
return Flux.create(sink -> {
apiClient.streamChat(convertPrompt(prompt), chunk -> {
sink.next(convertChunk(chunk));
});
});
}
@Override
public ChatOptions getDefaultOptions() {
return defaultOptions;
}
}ChatResponse response = chatModel.call(prompt);
// Access response metadata
ResponseMetadata metadata = response.getMetadata();
// Get usage information
Usage usage = (Usage) metadata.get("usage");
System.out.println("Tokens used: " + usage.getTotalTokens());
// Get rate limit information
RateLimit rateLimit = (RateLimit) metadata.get("rateLimit");
System.out.println("Requests remaining: " + rateLimit.getRequestsRemaining());
// Check for specific metadata
if (metadata.containsKey("model")) {
String model = metadata.get("model");
System.out.println("Model used: " + model);
}// Calculate similarity between two texts
float[] embedding1 = embeddingModel.embed("Hello world");
float[] embedding2 = embeddingModel.embed("Hi there");
double similarity = EmbeddingUtils.cosineSimilarity(embedding1, embedding2);
System.out.println("Similarity: " + similarity);
// Normalize embeddings
float[] normalized = EmbeddingUtils.normalize(embedding1);