Skip to content

Commit 085446c

Browse files
committed
feat(google-genai): add Google GenAI embedding module and unified SDK support
This PR introduces comprehensive support for Google's latest Unified SDK with text embedding capabilities and enhances the existing chat model functionality. Key Changes: 1. New Google Gen AI Text Embedding Support (#3824) - Added a new **spring-ai-google-genai-embedding** module with full text embedding model implementation - Supports Google's text embedding models (text-embedding-005, text-embedding-004, gemini-embedding-001) with configurable options - Includes comprehensive test coverage with retry logic and observability support 2. Spring Boot Starter for Google Gen AI (#3824) - Created **spring-ai-autoconfigure-model-google-genai** module with auto-configuration for both chat and embedding models - Provides property-based configuration for easy integration - Includes migration guide and extensive integration tests 3. Thinking Configuration Support (#3849) - Enhanced Google Gen AI chat model with thinking/reasoning configuration in the **spring-ai-google-genai** module - Added support for configurable thinking parameters in chat options - Enables advanced reasoning capabilities in the chat model Closes #3824 Closes #3849 Authored-by: Dan Dobrin <[email protected]>
1 parent 2778ec6 commit 085446c

File tree

39 files changed

+3477
-11
lines changed

39 files changed

+3477
-11
lines changed

auto-configurations/mcp/spring-ai-autoconfigure-mcp-server/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpServerAutoConfiguration.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -248,8 +248,9 @@ public McpSyncServer mcpSyncServer(McpServerTransportProvider transportProvider,
248248
}
249249

250250
rootsChangeConsumers.ifAvailable(consumer -> {
251-
serverBuilder.rootsChangeHandler((exchange, roots) -> consumer.accept((McpSyncServerExchange) exchange,
252-
(List<McpSchema.Root>) roots));
251+
BiConsumer<McpSyncServerExchange, List<McpSchema.Root>> syncConsumer = (exchange, roots) -> consumer
252+
.accept(exchange, roots);
253+
serverBuilder.rootsChangeHandler(syncConsumer);
253254
logger.info("Registered roots change consumer");
254255
});
255256

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# Migration Guide: Spring AI Google GenAI Autoconfiguration
2+
3+
## Overview
4+
5+
This guide helps you migrate from the old Vertex AI-based autoconfiguration to the new Google GenAI SDK-based autoconfiguration.
6+
7+
## Key Changes
8+
9+
### 1. Property Namespace Changes
10+
11+
Old properties:
12+
```properties
13+
spring.ai.vertex.ai.gemini.project-id=my-project
14+
spring.ai.vertex.ai.gemini.location=us-central1
15+
spring.ai.vertex.ai.gemini.chat.options.model=gemini-pro
16+
spring.ai.vertex.ai.embedding.text.options.model=textembedding-gecko
17+
```
18+
19+
New properties:
20+
```properties
21+
# For Vertex AI mode
22+
spring.ai.google.genai.project-id=my-project
23+
spring.ai.google.genai.location=us-central1
24+
spring.ai.google.genai.chat.options.model=gemini-2.0-flash
25+
26+
# For Gemini Developer API mode (new!)
27+
spring.ai.google.genai.api-key=your-api-key
28+
spring.ai.google.genai.chat.options.model=gemini-2.0-flash
29+
30+
# Embedding properties
31+
spring.ai.google.genai.embedding.project-id=my-project
32+
spring.ai.google.genai.embedding.location=us-central1
33+
spring.ai.google.genai.embedding.text.options.model=text-embedding-004
34+
```
35+
36+
### 2. New Authentication Options
37+
38+
The new SDK supports both:
39+
- **Vertex AI mode**: Using Google Cloud credentials (same as before)
40+
- **Gemini Developer API mode**: Using API keys (new!)
41+
42+
### 3. Removed Features
43+
44+
- `transport` property is no longer needed
45+
- Multimodal embedding autoconfiguration has been removed (pending support in new SDK)
46+
47+
### 4. Bean Name Changes
48+
49+
If you were autowiring beans by name:
50+
- `vertexAi``googleGenAiClient`
51+
- `vertexAiGeminiChat``googleGenAiChatModel`
52+
- `textEmbedding``googleGenAiTextEmbedding`
53+
54+
### 5. Class Changes
55+
56+
If you were importing classes directly:
57+
- `com.google.cloud.vertexai.VertexAI``com.google.genai.Client`
58+
- `org.springframework.ai.vertexai.gemini.*``org.springframework.ai.google.genai.*`
59+
60+
## Migration Steps
61+
62+
1. Update your application properties:
63+
- Replace `spring.ai.vertex.ai.*` with `spring.ai.google.genai.*`
64+
- Remove any `transport` configuration
65+
66+
2. If using API key authentication:
67+
- Set `spring.ai.google.genai.api-key` property
68+
- Remove project-id and location for chat (not needed with API key)
69+
70+
3. Update any custom configurations or bean references
71+
72+
4. Test your application thoroughly
73+
74+
## Environment Variables
75+
```bash
76+
export GOOGLE_CLOUD_PROJECT=my-project
77+
export GOOGLE_CLOUD_LOCATION=us-central1
78+
```
79+
80+
New (additional option):
81+
```bash
82+
export GOOGLE_API_KEY=your-api-key
83+
```
84+
85+
## Backward Compatibility
86+
87+
The old autoconfiguration module is still available but deprecated. We recommend migrating to the new module as soon as possible.
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xmlns="http://maven.apache.org/POM/4.0.0"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
<parent>
7+
<groupId>org.springframework.ai</groupId>
8+
<artifactId>spring-ai-parent</artifactId>
9+
<version>1.1.0-SNAPSHOT</version>
10+
<relativePath>../../../pom.xml</relativePath>
11+
</parent>
12+
<artifactId>spring-ai-autoconfigure-model-google-genai</artifactId>
13+
<packaging>jar</packaging>
14+
<name>Spring AI Google GenAI Auto Configuration</name>
15+
<description>Spring AI Google GenAI Auto Configuration</description>
16+
<url>https://github.com/spring-projects/spring-ai</url>
17+
18+
<scm>
19+
<url>https://github.com/spring-projects/spring-ai</url>
20+
<connection>git://github.com/spring-projects/spring-ai.git</connection>
21+
<developerConnection>[email protected]:spring-projects/spring-ai.git</developerConnection>
22+
</scm>
23+
24+
25+
<dependencies>
26+
27+
<!-- Spring AI dependencies -->
28+
29+
<!-- Google GenAI Embedding -->
30+
<dependency>
31+
<groupId>org.springframework.ai</groupId>
32+
<artifactId>spring-ai-google-genai-embedding</artifactId>
33+
<version>${project.parent.version}</version>
34+
<optional>true</optional>
35+
</dependency>
36+
37+
<!-- Google GenAI -->
38+
<dependency>
39+
<groupId>org.springframework.ai</groupId>
40+
<artifactId>spring-ai-google-genai</artifactId>
41+
<version>${project.parent.version}</version>
42+
<optional>true</optional>
43+
</dependency>
44+
45+
<!-- Spring AI auto configurations -->
46+
47+
<dependency>
48+
<groupId>org.springframework.ai</groupId>
49+
<artifactId>spring-ai-autoconfigure-model-tool</artifactId>
50+
<version>${project.parent.version}</version>
51+
</dependency>
52+
53+
<dependency>
54+
<groupId>org.springframework.ai</groupId>
55+
<artifactId>spring-ai-autoconfigure-retry</artifactId>
56+
<version>${project.parent.version}</version>
57+
</dependency>
58+
59+
<dependency>
60+
<groupId>org.springframework.ai</groupId>
61+
<artifactId>spring-ai-autoconfigure-model-chat-observation</artifactId>
62+
<version>${project.parent.version}</version>
63+
</dependency>
64+
65+
<dependency>
66+
<groupId>org.springframework.ai</groupId>
67+
<artifactId>spring-ai-autoconfigure-model-embedding-observation</artifactId>
68+
<version>${project.parent.version}</version>
69+
</dependency>
70+
71+
<!-- Boot dependencies -->
72+
<dependency>
73+
<groupId>org.springframework.boot</groupId>
74+
<artifactId>spring-boot-starter</artifactId>
75+
<optional>true</optional>
76+
</dependency>
77+
78+
<dependency>
79+
<groupId>org.springframework.boot</groupId>
80+
<artifactId>spring-boot-configuration-processor</artifactId>
81+
<optional>true</optional>
82+
</dependency>
83+
84+
<dependency>
85+
<groupId>org.springframework.boot</groupId>
86+
<artifactId>spring-boot-autoconfigure-processor</artifactId>
87+
<optional>true</optional>
88+
</dependency>
89+
90+
<!-- Test dependencies -->
91+
<dependency>
92+
<groupId>org.springframework.ai</groupId>
93+
<artifactId>spring-ai-test</artifactId>
94+
<version>${project.parent.version}</version>
95+
<scope>test</scope>
96+
</dependency>
97+
98+
<dependency>
99+
<groupId>org.springframework.boot</groupId>
100+
<artifactId>spring-boot-starter-test</artifactId>
101+
<scope>test</scope>
102+
</dependency>
103+
104+
<dependency>
105+
<groupId>org.mockito</groupId>
106+
<artifactId>mockito-core</artifactId>
107+
<scope>test</scope>
108+
</dependency>
109+
110+
<dependency>
111+
<groupId>org.testcontainers</groupId>
112+
<artifactId>junit-jupiter</artifactId>
113+
<scope>test</scope>
114+
</dependency>
115+
116+
<dependency>
117+
<groupId>org.testcontainers</groupId>
118+
<artifactId>ollama</artifactId>
119+
<scope>test</scope>
120+
</dependency>
121+
</dependencies>
122+
123+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/*
2+
* Copyright 2023-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.ai.model.google.genai.autoconfigure.chat;
18+
19+
import java.io.IOException;
20+
21+
import com.google.auth.oauth2.GoogleCredentials;
22+
import com.google.genai.Client;
23+
import io.micrometer.observation.ObservationRegistry;
24+
25+
import org.springframework.ai.chat.observation.ChatModelObservationConvention;
26+
import org.springframework.ai.google.genai.GoogleGenAiChatModel;
27+
import org.springframework.ai.model.SpringAIModelProperties;
28+
import org.springframework.ai.model.SpringAIModels;
29+
import org.springframework.ai.model.tool.DefaultToolExecutionEligibilityPredicate;
30+
import org.springframework.ai.model.tool.ToolCallingManager;
31+
import org.springframework.ai.model.tool.ToolExecutionEligibilityPredicate;
32+
import org.springframework.ai.model.tool.autoconfigure.ToolCallingAutoConfiguration;
33+
import org.springframework.ai.retry.autoconfigure.SpringAiRetryAutoConfiguration;
34+
import org.springframework.beans.factory.ObjectProvider;
35+
import org.springframework.boot.autoconfigure.AutoConfiguration;
36+
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
37+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
38+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
39+
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
40+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
41+
import org.springframework.context.ApplicationContext;
42+
import org.springframework.context.annotation.Bean;
43+
import org.springframework.retry.support.RetryTemplate;
44+
import org.springframework.util.Assert;
45+
import org.springframework.util.StringUtils;
46+
47+
/**
48+
* Auto-configuration for Google GenAI Chat.
49+
*
50+
* @author Christian Tzolov
51+
* @author Soby Chacko
52+
* @author Mark Pollack
53+
* @author Ilayaperumal Gopinathan
54+
* @since 1.1.0
55+
*/
56+
@AutoConfiguration(after = { SpringAiRetryAutoConfiguration.class, ToolCallingAutoConfiguration.class })
57+
@ConditionalOnClass({ Client.class, GoogleGenAiChatModel.class })
58+
@ConditionalOnProperty(name = SpringAIModelProperties.CHAT_MODEL, havingValue = SpringAIModels.GOOGLE_GEN_AI,
59+
matchIfMissing = true)
60+
@EnableConfigurationProperties({ GoogleGenAiChatProperties.class, GoogleGenAiConnectionProperties.class })
61+
@ImportAutoConfiguration(classes = { SpringAiRetryAutoConfiguration.class, ToolCallingAutoConfiguration.class })
62+
public class GoogleGenAiChatAutoConfiguration {
63+
64+
@Bean
65+
@ConditionalOnMissingBean
66+
public Client googleGenAiClient(GoogleGenAiConnectionProperties connectionProperties) throws IOException {
67+
68+
Client.Builder clientBuilder = Client.builder();
69+
70+
if (StringUtils.hasText(connectionProperties.getApiKey())) {
71+
// Gemini Developer API mode
72+
clientBuilder.apiKey(connectionProperties.getApiKey());
73+
}
74+
else {
75+
// Vertex AI mode
76+
Assert.hasText(connectionProperties.getProjectId(), "Google GenAI project-id must be set!");
77+
Assert.hasText(connectionProperties.getLocation(), "Google GenAI location must be set!");
78+
79+
clientBuilder.project(connectionProperties.getProjectId())
80+
.location(connectionProperties.getLocation())
81+
.vertexAI(true);
82+
83+
if (connectionProperties.getCredentialsUri() != null) {
84+
GoogleCredentials credentials = GoogleCredentials
85+
.fromStream(connectionProperties.getCredentialsUri().getInputStream());
86+
// Note: The new SDK doesn't have a direct setCredentials method,
87+
// credentials are handled automatically when vertexAI is true
88+
}
89+
}
90+
91+
return clientBuilder.build();
92+
}
93+
94+
@Bean
95+
@ConditionalOnMissingBean
96+
public GoogleGenAiChatModel googleGenAiChatModel(Client googleGenAiClient, GoogleGenAiChatProperties chatProperties,
97+
ToolCallingManager toolCallingManager, ApplicationContext context, RetryTemplate retryTemplate,
98+
ObjectProvider<ObservationRegistry> observationRegistry,
99+
ObjectProvider<ChatModelObservationConvention> observationConvention,
100+
ObjectProvider<ToolExecutionEligibilityPredicate> toolExecutionEligibilityPredicate) {
101+
102+
GoogleGenAiChatModel chatModel = GoogleGenAiChatModel.builder()
103+
.genAiClient(googleGenAiClient)
104+
.defaultOptions(chatProperties.getOptions())
105+
.toolCallingManager(toolCallingManager)
106+
.toolExecutionEligibilityPredicate(
107+
toolExecutionEligibilityPredicate.getIfUnique(() -> new DefaultToolExecutionEligibilityPredicate()))
108+
.retryTemplate(retryTemplate)
109+
.observationRegistry(observationRegistry.getIfUnique(() -> ObservationRegistry.NOOP))
110+
.build();
111+
112+
observationConvention.ifAvailable(chatModel::setObservationConvention);
113+
114+
return chatModel;
115+
}
116+
117+
}

0 commit comments

Comments
 (0)