Skip to content

Commit 9f32a3c

Browse files
committed
Add doc waring about gemini pro model function calling function calling degradation
1 parent 9cd01c5 commit 9f32a3c

File tree

4 files changed

+56
-75
lines changed

4 files changed

+56
-75
lines changed

models/spring-ai-vertex-ai-gemini/src/test/java/org/springframework/ai/vertexai/gemini/function/MockWeatherService.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,7 @@ private Unit(String text) {
7070
/**
7171
* Weather Function response.
7272
*/
73-
public record Response(double temp, double feels_like, double temp_min, double temp_max, int pressure, int humidity,
74-
Unit unit) {
73+
public record Response(double temp, Unit unit) {
7574
}
7675

7776
@Override
@@ -89,7 +88,7 @@ else if (request.location().contains("San Francisco")) {
8988
}
9089

9190
logger.info("Request is {}, response temperature is {}", request, temperature);
92-
return new Response(temperature, 15, 20, 2, 53, 45, Unit.C);
91+
return new Response(temperature, Unit.C);
9392
}
9493

9594
}

models/spring-ai-vertex-ai-gemini/src/test/java/org/springframework/ai/vertexai/gemini/function/VertexAiGeminiChatClientFunctionCallingIT.java

Lines changed: 46 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,21 @@
1515
*/
1616
package org.springframework.ai.vertexai.gemini.function;
1717

18+
import java.util.ArrayList;
19+
import java.util.List;
20+
import java.util.function.Function;
21+
import java.util.stream.Collectors;
22+
1823
import com.google.cloud.vertexai.Transport;
1924
import com.google.cloud.vertexai.VertexAI;
2025
import org.junit.jupiter.api.AfterEach;
26+
import org.junit.jupiter.api.Disabled;
2127
import org.junit.jupiter.api.Test;
2228
import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
2329
import org.slf4j.Logger;
2430
import org.slf4j.LoggerFactory;
31+
import reactor.core.publisher.Flux;
32+
2533
import org.springframework.ai.chat.ChatResponse;
2634
import org.springframework.ai.chat.Generation;
2735
import org.springframework.ai.chat.messages.AssistantMessage;
@@ -36,15 +44,8 @@
3644
import org.springframework.boot.SpringBootConfiguration;
3745
import org.springframework.boot.test.context.SpringBootTest;
3846
import org.springframework.context.annotation.Bean;
39-
import reactor.core.publisher.Flux;
40-
41-
import java.util.ArrayList;
42-
import java.util.List;
43-
import java.util.function.Function;
44-
import java.util.stream.Collectors;
4547

4648
import static org.assertj.core.api.Assertions.assertThat;
47-
import static org.junit.jupiter.api.Assertions.assertNotNull;
4849

4950
@SpringBootTest
5051
@EnabledIfEnvironmentVariable(named = "VERTEX_AI_GEMINI_PROJECT_ID", matches = ".*")
@@ -67,10 +68,14 @@ public void afterEach() {
6768
}
6869

6970
@Test
71+
@Disabled("Google Vertex AI degraded support for parallel function calls")
7072
public void functionCallExplicitOpenApiSchema() {
7173

7274
UserMessage userMessage = new UserMessage(
73-
"What's the weather like in San Francisco, in Paris and in Tokyo, Japan? Use Multi-turn function calling. Provide answer for all requested locations.");
75+
"What's the weather like in San Francisco, in Paris and in Tokyo, Japan?"
76+
+ " Use Celsius units. Answer for all requested locations.");
77+
// " Use Celsius units. Use Multi-turn function calling. Provide answer for all
78+
// requested locations.");
7479

7580
List<Message> messages = new ArrayList<>(List.of(userMessage));
7681

@@ -95,7 +100,7 @@ public void functionCallExplicitOpenApiSchema() {
95100
var promptOptions = VertexAiGeminiChatOptions.builder()
96101
.withModel(VertexAiGeminiChatClient.ChatModel.GEMINI_PRO.getValue())
97102
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
98-
.withName("getCurrentWeather")
103+
.withName("get_current_weather")
99104
.withDescription("Get the current weather in a given location")
100105
.withInputTypeSchema(openApiSchema)
101106
.build()))
@@ -115,39 +120,48 @@ public void functionCallExplicitOpenApiSchema() {
115120
@Test
116121
public void functionCallTestInferredOpenApiSchema() {
117122

118-
// UserMessage userMessage = new UserMessage("What's the weather like in San
119-
// Francisco, Paris and Tokyo?");
120-
UserMessage userMessage = new UserMessage("What's the weather like in Paris?");
123+
UserMessage userMessage = new UserMessage("What's the weather like in Paris? Use Celsius units.");
121124

122125
List<Message> messages = new ArrayList<>(List.of(userMessage));
123126

124127
var promptOptions = VertexAiGeminiChatOptions.builder()
125128
.withModel(VertexAiGeminiChatClient.ChatModel.GEMINI_PRO.getValue())
126-
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
127-
.withSchemaType(SchemaType.OPEN_API_SCHEMA)
128-
.withName("getCurrentWeather")
129-
.withDescription("Get the current weather in a given location")
130-
.build()))
129+
.withFunctionCallbacks(List.of(
130+
FunctionCallbackWrapper.builder(new MockWeatherService())
131+
.withSchemaType(SchemaType.OPEN_API_SCHEMA)
132+
.withName("get_current_weather")
133+
.withDescription("Get the current weather in a given location.")
134+
.build(),
135+
FunctionCallbackWrapper.builder(new PaymentStatus())
136+
.withSchemaType(SchemaType.OPEN_API_SCHEMA)
137+
.withName("get_payment_status")
138+
.withDescription(
139+
"Retrieves the payment status for transaction. For example what is the payment status for transaction 700?")
140+
.build()))
131141
.build();
132142

133143
ChatResponse response = vertexGeminiClient.call(new Prompt(messages, promptOptions));
134144

135145
logger.info("Response: {}", response);
136146

137-
// System.out.println(response.getResult().getOutput().getContent());
138-
// assertThat(response.getResult().getOutput().getContent()).containsAnyOf("30.0",
139-
// "30");
140-
// assertThat(response.getResult().getOutput().getContent()).containsAnyOf("10.0",
141-
// "10");
142147
assertThat(response.getResult().getOutput().getContent()).containsAnyOf("15.0", "15");
143148

149+
ChatResponse response2 = vertexGeminiClient
150+
.call(new Prompt("What is the payment status for transaction 696?", promptOptions));
151+
152+
logger.info("Response: {}", response2);
153+
154+
assertThat(response2.getResult().getOutput().getContent()).containsIgnoringCase("transaction 696 is PAYED");
155+
144156
}
145157

146158
@Test
147159
public void functionCallTestInferredOpenApiSchemaStream() {
148160

149-
UserMessage userMessage = new UserMessage(
150-
"What's the weather like in San Francisco, in Paris and in Tokyo, Japan? Use Multi-turn function calling. Provide answer for all requested locations.");
161+
UserMessage userMessage = new UserMessage("What's the weather like in San Francisco in Celsius units?");
162+
// UserMessage userMessage = new UserMessage(
163+
// "What's the weather like in San Francisco, in Paris and in Tokyo, Japan? Use
164+
// Multi-turn function calling. Provide answer for all requested locations.");
151165

152166
List<Message> messages = new ArrayList<>(List.of(userMessage));
153167

@@ -173,63 +187,23 @@ public void functionCallTestInferredOpenApiSchemaStream() {
173187

174188
logger.info("Response: {}", responseString);
175189

176-
assertThat(responseString).containsAnyOf("15.0", "15");
190+
// assertThat(responseString).containsAnyOf("15.0", "15");
177191
assertThat(responseString).containsAnyOf("30.0", "30");
178-
assertThat(responseString).containsAnyOf("10.0", "10");
192+
// assertThat(responseString).containsAnyOf("10.0", "10");
179193

180194
}
181195

182-
// Gemini wants single tool with multiple function, instead multiple tools with single
183-
// function
184-
@Test
185-
public void canDeclareMultipleFunctions() {
186-
187-
UserMessage userMessage = new UserMessage(
188-
"What's the weather like in San Francisco, in Paris and in Tokyo, Japan? Use Multi-turn function calling. Provide answer for all requested locations.");
189-
190-
List<Message> messages = new ArrayList<>(List.of(userMessage));
191-
192-
final var weatherFunction = FunctionCallbackWrapper.builder(new MockWeatherService())
193-
.withSchemaType(SchemaType.OPEN_API_SCHEMA)
194-
.withName("getCurrentWeather")
195-
.withDescription("Get the current weather in a given location")
196-
.build();
197-
final var theAnswer = FunctionCallbackWrapper.builder(new TheAnswerMock())
198-
.withSchemaType(SchemaType.OPEN_API_SCHEMA)
199-
.withName("theAnswerToTheUniverse")
200-
.withDescription("the answer to the ultimate question of life, the universe, and everything")
201-
.build();
202-
var promptOptions = VertexAiGeminiChatOptions.builder()
203-
.withModel(VertexAiGeminiChatClient.ChatModel.GEMINI_PRO.getValue())
204-
.withFunctionCallbacks(List.of(weatherFunction))
205-
.build();
206-
// var promptOptions = VertexAiGeminiChatOptions.builder()
207-
// .withModel(VertexAiGeminiChatClient.ChatModel.GEMINI_PRO.getValue())
208-
// .withFunctionCallbacks(List.of(weatherFunction, theAnswer))
209-
// .build();
210-
211-
ChatResponse response = vertexGeminiClient.call(new Prompt(messages, promptOptions));
212-
213-
String responseString = response.getResult().getOutput().getContent();
214-
215-
logger.info("Response: {}", responseString);
216-
assertNotNull(responseString);
217-
218-
response = vertexGeminiClient
219-
.call(new Prompt("What is the answer of the ultimate question in life?", promptOptions));
220-
221-
responseString = response.getResult().getOutput().getContent();
222-
223-
logger.info("Response: {}", responseString);
224-
assertNotNull(responseString);
196+
public record PaymentInfoRequest(String id) {
197+
}
225198

199+
public record TransactionStatus(String status) {
226200
}
227201

228-
public static class TheAnswerMock implements Function<String, Integer> {
202+
public static class PaymentStatus implements Function<PaymentInfoRequest, TransactionStatus> {
229203

230204
@Override
231-
public Integer apply(String s) {
232-
return 42;
205+
public TransactionStatus apply(PaymentInfoRequest paymentInfoRequest) {
206+
return new TransactionStatus("Transaction " + paymentInfoRequest.id() + " is PAYED");
233207
}
234208

235209
}

spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/functions/vertexai-gemini-chat-functions.adoc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
= Gemini Function Calling
22

3+
WARNING: As of 30th of April 2023, the Vertex AI `Gemini Pro` model has significantly degraded the support for function calling! While the feature is still available, it is not recommended for production use.
4+
Apparently the Gemini Pro can not handle anymore the function name correctly.
5+
The parallel function calling is gone as well.
6+
37
Function calling lets developers create a description of a function in their code, then pass that description to a language model in a request. The response from the model includes the name of a function that matches the description and the arguments to call it with.
48

59
You can register custom Java functions with the `VertexAiGeminiChatClient` and have the Gemini Pro model intelligently choose to output a JSON object containing arguments to call one or many of the registered functions.

spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/vertexai-gemini-chat.adoc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,10 @@ TIP: In addition to the model specific `VertexAiChatPaLm2Options` you can use a
104104

105105
== Function Calling
106106

107+
WARNING: As of 30th of April 2023, the Vertex AI `Gemini Pro` model has significantly degraded the support for function calling! While the feature is still available, it is not recommended for production use.
108+
Apparently the Gemini Pro can not handle anymore the function name correctly.
109+
The parallel function calling is gone as well.
110+
107111
You can register custom Java functions with the VertexAiGeminiChatClient and have the Gemini Pro model intelligently choose to output a JSON object containing arguments to call one or many of the registered functions.
108112
This is a powerful technique to connect the LLM capabilities with external tools and APIs.
109113
Read more about xref:api/chat/functions/vertexai-gemini-chat-functions.adoc[Vertex AI Gemini Function Calling].

0 commit comments

Comments
 (0)