Rename request call() to prompt() and the response collect() to call(). Adjust tests
This commit is contained in:
@@ -62,13 +62,12 @@ class OpenAiChatClientIT extends AbstractIT {
|
||||
@Test
|
||||
void roleTest() {
|
||||
|
||||
ChatResponse response = ChatClient.builder(modelCaller)
|
||||
.build()
|
||||
.call()
|
||||
.system(s -> s.text(systemTextResource).param("name", "Bob").param("voice", "pirate"))
|
||||
.user(u -> u.text("Tell me about 3 famous pirates from the Golden Age of Piracy and what they did"))
|
||||
.collect()
|
||||
.chatResponse();
|
||||
ChatResponse response = ChatClient.builder(modelCaller).build().prompt()
|
||||
.system(s -> s.text(systemTextResource)
|
||||
.param("name", "Bob")
|
||||
.param("voice", "pirate"))
|
||||
.user("Tell me about 3 famous pirates from the Golden Age of Piracy and what they did")
|
||||
.call().chatResponse();
|
||||
|
||||
System.out.println(response);
|
||||
// UserMessage userMessage = new UserMessage(
|
||||
@@ -89,12 +88,10 @@ class OpenAiChatClientIT extends AbstractIT {
|
||||
void listOutputConverter() {
|
||||
|
||||
// TODO: there is a problem here.
|
||||
Collection<String> list = ChatClient.builder(modelCaller)
|
||||
.build()
|
||||
.call()
|
||||
.user(u -> u.text("List five {subject}").param("subject", "ice cream flavors"))
|
||||
.collect()
|
||||
.list(String.class);
|
||||
Collection<String> list = ChatClient.builder(modelCaller).build().prompt()
|
||||
.user(u -> u.text("List five {subject}")
|
||||
.param("subject", "ice cream flavors"))
|
||||
.call().list(String.class);
|
||||
|
||||
// DefaultConversionService conversionService = new DefaultConversionService();
|
||||
// ListOutputConverter outputConverter = new
|
||||
@@ -119,14 +116,11 @@ class OpenAiChatClientIT extends AbstractIT {
|
||||
@Test
|
||||
void mapOutputConverter() {
|
||||
|
||||
Map<String, Object> result = ChatClient.builder(modelCaller)
|
||||
.build()
|
||||
.call()
|
||||
.user(u -> u.text("Provide me a List of {subject}")
|
||||
.param("subject", "an array of numbers from 1 to 9 under they key name 'numbers'"))
|
||||
.collect()
|
||||
.single(new ParameterizedTypeReference<Map<String, Object>>() {
|
||||
});
|
||||
Map<String, Object> result = ChatClient.builder(modelCaller).build().prompt()
|
||||
.user(u -> u.text("Provide me a List of {subject}")
|
||||
.param("subject", "an array of numbers from 1 to 9 under they key name 'numbers'"))
|
||||
.call().single(new ParameterizedTypeReference<Map<String, Object>>() {
|
||||
});
|
||||
|
||||
// MapOutputConverter outputConverter = new MapOutputConverter();
|
||||
|
||||
@@ -149,12 +143,10 @@ class OpenAiChatClientIT extends AbstractIT {
|
||||
@Test
|
||||
void beanOutputConverter() {
|
||||
|
||||
ActorsFilms actorsFilms = ChatClient.builder(modelCaller)
|
||||
.build()
|
||||
.call()
|
||||
.user(u -> u.text("Generate the filmography for a random actor."))
|
||||
.collect()
|
||||
.single(ActorsFilms.class);
|
||||
ActorsFilms actorsFilms = ChatClient.builder(modelCaller).build().prompt()
|
||||
.user("Generate the filmography for a random actor.")
|
||||
.call()
|
||||
.single(ActorsFilms.class);
|
||||
|
||||
// BeanOutputConverter<ActorsFilms> outputConverter = new
|
||||
// BeanOutputConverter<>(ActorsFilms.class);
|
||||
@@ -181,12 +173,10 @@ class OpenAiChatClientIT extends AbstractIT {
|
||||
@Test
|
||||
void beanOutputConverterRecords() {
|
||||
|
||||
ActorsFilmsRecord actorsFilms = ChatClient.builder(modelCaller)
|
||||
.build()
|
||||
.call()
|
||||
.user(u -> u.text("Generate the filmography of 5 movies for Tom Hanks."))
|
||||
.collect()
|
||||
.single(ActorsFilmsRecord.class);
|
||||
ActorsFilmsRecord actorsFilms = ChatClient.builder(modelCaller).build().prompt()
|
||||
.user("Generate the filmography of 5 movies for Tom Hanks.")
|
||||
.call()
|
||||
.single(ActorsFilmsRecord.class);
|
||||
|
||||
// BeanOutputConverter<ActorsFilmsRecord> outputConverter = new
|
||||
// BeanOutputConverter<>(ActorsFilmsRecord.class);
|
||||
@@ -213,22 +203,20 @@ class OpenAiChatClientIT extends AbstractIT {
|
||||
|
||||
BeanOutputConverter<ActorsFilmsRecord> outputConverter = new BeanOutputConverter<>(ActorsFilmsRecord.class);
|
||||
|
||||
Flux<ChatResponse> chatResponse = ChatClient.builder(modelCaller)
|
||||
.build()
|
||||
.call()
|
||||
.user(u -> u
|
||||
.text("Generate the filmography of 5 movies for Tom Hanks. " + System.lineSeparator() + "{format}")
|
||||
.param("format", outputConverter.getFormat()))
|
||||
.stream()
|
||||
.chatResponse();
|
||||
Flux<String> chatResponse = ChatClient.builder(modelCaller)
|
||||
.build()
|
||||
.prompt()
|
||||
.user(u -> u
|
||||
.text("Generate the filmography of 5 movies for Tom Hanks. " + System.lineSeparator()
|
||||
+ "{format}")
|
||||
.param("format", outputConverter.getFormat()))
|
||||
.stream()
|
||||
.content();
|
||||
|
||||
String generationTextFromStream = chatResponse.collectList()
|
||||
.block()
|
||||
.stream()
|
||||
.map(ChatResponse::getResult)
|
||||
.map(Generation::getOutput)
|
||||
.map(AssistantMessage::getContent)
|
||||
.collect(Collectors.joining());
|
||||
.block()
|
||||
.stream()
|
||||
.collect(Collectors.joining());
|
||||
|
||||
// String generationTextFromStream = chatResponse.collectList()
|
||||
// .block()
|
||||
@@ -266,13 +254,11 @@ class OpenAiChatClientIT extends AbstractIT {
|
||||
@Test
|
||||
void functionCallTest() {
|
||||
|
||||
ChatResponse response = ChatClient.builder(modelCaller)
|
||||
.build()
|
||||
.call()
|
||||
.user(u -> u.text("What's the weather like in San Francisco, Tokyo, and Paris?"))
|
||||
.function("getCurrentWeather", "Get the weather in location", new MockWeatherService())
|
||||
.collect()
|
||||
.chatResponse();
|
||||
String response = ChatClient.builder(modelCaller).build().prompt()
|
||||
.user(u -> u.text("What's the weather like in San Francisco, Tokyo, and Paris?"))
|
||||
.function("getCurrentWeather", "Get the weather in location", new MockWeatherService())
|
||||
.call()
|
||||
.content();
|
||||
|
||||
// UserMessage userMessage = new UserMessage("What's the weather like in San
|
||||
// Francisco, Tokyo, and Paris?");
|
||||
@@ -293,21 +279,19 @@ class OpenAiChatClientIT extends AbstractIT {
|
||||
|
||||
logger.info("Response: {}", response);
|
||||
|
||||
assertThat(response.getResult().getOutput().getContent()).containsAnyOf("30.0", "30");
|
||||
assertThat(response.getResult().getOutput().getContent()).containsAnyOf("10.0", "10");
|
||||
assertThat(response.getResult().getOutput().getContent()).containsAnyOf("15.0", "15");
|
||||
assertThat(response).containsAnyOf("30.0", "30");
|
||||
assertThat(response).containsAnyOf("10.0", "10");
|
||||
assertThat(response).containsAnyOf("15.0", "15");
|
||||
}
|
||||
|
||||
@Test
|
||||
void streamFunctionCallTest() {
|
||||
|
||||
Flux<ChatResponse> response = ChatClient.builder(modelCaller)
|
||||
.build()
|
||||
.call()
|
||||
.user(u -> u.text("What's the weather like in San Francisco, Tokyo, and Paris?"))
|
||||
.function("getCurrentWeather", "Get the weather in location", new MockWeatherService())
|
||||
.stream()
|
||||
.chatResponse();
|
||||
Flux<String> response = ChatClient.builder(modelCaller).build().prompt()
|
||||
.user("What's the weather like in San Francisco, Tokyo, and Paris?")
|
||||
.function("getCurrentWeather", "Get the weather in location", new MockWeatherService())
|
||||
.stream()
|
||||
.content();
|
||||
|
||||
// UserMessage userMessage = new UserMessage("What's the weather like in San
|
||||
// Francisco, Tokyo, and Paris?");
|
||||
@@ -328,13 +312,9 @@ class OpenAiChatClientIT extends AbstractIT {
|
||||
// promptOptions));
|
||||
|
||||
String content = response.collectList()
|
||||
.block()
|
||||
.stream()
|
||||
.map(ChatResponse::getResults)
|
||||
.flatMap(List::stream)
|
||||
.map(Generation::getOutput)
|
||||
.map(AssistantMessage::getContent)
|
||||
.collect(Collectors.joining());
|
||||
.block()
|
||||
.stream()
|
||||
.collect(Collectors.joining());
|
||||
logger.info("Response: {}", content);
|
||||
|
||||
assertThat(content).containsAnyOf("30.0", "30");
|
||||
@@ -346,16 +326,14 @@ class OpenAiChatClientIT extends AbstractIT {
|
||||
@ValueSource(strings = { "gpt-4-vision-preview", "gpt-4o" })
|
||||
void multiModalityEmbeddedImage(String modelName) throws IOException {
|
||||
|
||||
ChatResponse response = ChatClient.builder(modelCaller)
|
||||
.build()
|
||||
.call()
|
||||
// TODO consider adding model(...) method to ChatClient as a shortcut to
|
||||
// OpenAiChatOptions.builder().withModel(modelName).build()
|
||||
.options(OpenAiChatOptions.builder().withModel(modelName).build())
|
||||
.user(u -> u.text("Explain what do you see on this picture?")
|
||||
.media(MimeTypeUtils.IMAGE_PNG, new ClassPathResource("/test.png")))
|
||||
.collect()
|
||||
.chatResponse();
|
||||
String response = ChatClient.builder(modelCaller).build().prompt()
|
||||
// TODO consider adding model(...) method to ChatClient as a shortcut to
|
||||
// OpenAiChatOptions.builder().withModel(modelName).build()
|
||||
.options(OpenAiChatOptions.builder().withModel(modelName).build())
|
||||
.user(u -> u.text("Explain what do you see on this picture?")
|
||||
.media(MimeTypeUtils.IMAGE_PNG, new ClassPathResource("/test.png")))
|
||||
.call()
|
||||
.content();
|
||||
|
||||
// var imageData = new ClassPathResource("/test.png");
|
||||
|
||||
@@ -366,9 +344,9 @@ class OpenAiChatClientIT extends AbstractIT {
|
||||
// .call(new Prompt(List.of(userMessage),
|
||||
// OpenAiChatOptions.builder().withModel(modelName).build()));
|
||||
|
||||
logger.info(response.getResult().getOutput().getContent());
|
||||
assertThat(response.getResult().getOutput().getContent()).contains("bananas", "apple");
|
||||
assertThat(response.getResult().getOutput().getContent()).containsAnyOf("bowl", "basket");
|
||||
logger.info(response);
|
||||
assertThat(response).contains("bananas", "apple");
|
||||
assertThat(response).containsAnyOf("bowl", "basket");
|
||||
}
|
||||
|
||||
@ParameterizedTest(name = "{0} : {displayName} ")
|
||||
@@ -378,15 +356,15 @@ class OpenAiChatClientIT extends AbstractIT {
|
||||
// TODO: add url method that wrapps the checked exception.
|
||||
URL url = new URL("https://docs.spring.io/spring-ai/reference/1.0-SNAPSHOT/_images/multimodal.test.png");
|
||||
|
||||
ChatResponse response = ChatClient.builder(modelCaller)
|
||||
.build()
|
||||
.call()
|
||||
// TODO consider adding model(...) method to ChatClient as a shortcut to
|
||||
// OpenAiChatOptions.builder().withModel(modelName).build()
|
||||
.options(OpenAiChatOptions.builder().withModel(modelName).build())
|
||||
.user(u -> u.text("Explain what do you see on this picture?").media(MimeTypeUtils.IMAGE_PNG, url))
|
||||
.collect()
|
||||
.chatResponse();
|
||||
String response = ChatClient.builder(modelCaller)
|
||||
.build()
|
||||
.prompt()
|
||||
// TODO consider adding model(...) method to ChatClient as a shortcut to
|
||||
// OpenAiChatOptions.builder().withModel(modelName).build()
|
||||
.options(OpenAiChatOptions.builder().withModel(modelName).build())
|
||||
.user(u -> u.text("Explain what do you see on this picture?").media(MimeTypeUtils.IMAGE_PNG, url))
|
||||
.call()
|
||||
.content();
|
||||
|
||||
// var userMessage = new UserMessage("Explain what do you see on this picture?",
|
||||
// List
|
||||
@@ -398,9 +376,9 @@ class OpenAiChatClientIT extends AbstractIT {
|
||||
// .call(new Prompt(List.of(userMessage),
|
||||
// OpenAiChatOptions.builder().withModel(modelName).build()));
|
||||
|
||||
logger.info(response.getResult().getOutput().getContent());
|
||||
assertThat(response.getResult().getOutput().getContent()).contains("bananas", "apple");
|
||||
assertThat(response.getResult().getOutput().getContent()).containsAnyOf("bowl", "basket");
|
||||
logger.info(response);
|
||||
assertThat(response).contains("bananas", "apple");
|
||||
assertThat(response).containsAnyOf("bowl", "basket");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -409,19 +387,16 @@ class OpenAiChatClientIT extends AbstractIT {
|
||||
// TODO: add url method that wrapps the checked exception.
|
||||
URL url = new URL("https://docs.spring.io/spring-ai/reference/1.0-SNAPSHOT/_images/multimodal.test.png");
|
||||
|
||||
Flux<ChatResponse> response = ChatClient.builder(modelCaller)
|
||||
.build()
|
||||
.call()
|
||||
// TODO consider adding model(...) method to ChatClient as a shortcut to
|
||||
// OpenAiChatOptions.builder().withModel(modelName).build()
|
||||
.options(OpenAiChatOptions.builder().withModel(OpenAiApi.ChatModel.GPT_4_VISION_PREVIEW.getValue()).build())
|
||||
.user(u -> u.text("Explain what do you see on this picture?").media(MimeTypeUtils.IMAGE_PNG, url))
|
||||
.stream()
|
||||
.chatResponse();
|
||||
Flux<String> response = ChatClient.builder(modelCaller).build().prompt()
|
||||
.options(OpenAiChatOptions.builder().withModel(OpenAiApi.ChatModel.GPT_4_VISION_PREVIEW.getValue())
|
||||
.build())
|
||||
.user(u -> u.text("Explain what do you see on this picture?")
|
||||
.media(MimeTypeUtils.IMAGE_PNG, url))
|
||||
.stream()
|
||||
.content();
|
||||
|
||||
// var userMessage = new UserMessage("Explain what do you see on this picture?",
|
||||
// List
|
||||
// .of(new Media(MimeTypeUtils.IMAGE_PNG,
|
||||
// List.of(new Media(MimeTypeUtils.IMAGE_PNG,
|
||||
// new
|
||||
// URL("https://docs.spring.io/spring-ai/reference/1.0-SNAPSHOT/_images/multimodal.test.png"))));
|
||||
|
||||
@@ -429,14 +404,8 @@ class OpenAiChatClientIT extends AbstractIT {
|
||||
// Prompt(List.of(userMessage),
|
||||
// OpenAiChatOptions.builder().withModel(OpenAiApi.ChatModel.GPT_4_VISION_PREVIEW.getValue()).build()));
|
||||
|
||||
String content = response.collectList()
|
||||
.block()
|
||||
.stream()
|
||||
.map(ChatResponse::getResults)
|
||||
.flatMap(List::stream)
|
||||
.map(Generation::getOutput)
|
||||
.map(AssistantMessage::getContent)
|
||||
.collect(Collectors.joining());
|
||||
String content = response.collectList().block().stream().collect(Collectors.joining());
|
||||
|
||||
logger.info("Response: {}", content);
|
||||
assertThat(content).contains("bananas", "apple");
|
||||
assertThat(content).containsAnyOf("bowl", "basket");
|
||||
|
||||
@@ -64,7 +64,7 @@ public interface ChatClient {
|
||||
|
||||
ChatResponse call(Prompt prompt);
|
||||
|
||||
ChatClientRequest call();
|
||||
ChatClientRequest prompt();
|
||||
|
||||
interface PromptSpec<T> {
|
||||
|
||||
@@ -268,18 +268,18 @@ public interface ChatClient {
|
||||
return this;
|
||||
}
|
||||
|
||||
public static class CollectResponseSpec {
|
||||
public static class CallResponseSpec {
|
||||
|
||||
private final ChatClientRequest request;
|
||||
|
||||
private final ChatCaller modelCaller;
|
||||
|
||||
public CollectResponseSpec(ChatCaller modelCaller, ChatClientRequest request) {
|
||||
public CallResponseSpec(ChatCaller modelCaller, ChatClientRequest request) {
|
||||
this.modelCaller = modelCaller;
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
public <T> T single(ParameterizedTypeReference<T> t) {
|
||||
public <T> T single(ParameterizedTypeReference<T> type) {
|
||||
return doSingleWithBeanOutputConverter(new BeanOutputConverter<T>(new ParameterizedTypeReference<>() {
|
||||
}));
|
||||
}
|
||||
@@ -292,9 +292,9 @@ public interface ChatClient {
|
||||
return boc.convert(stringResponse);
|
||||
}
|
||||
|
||||
public <T> T single(Class<T> clzz) {
|
||||
Assert.notNull(clzz, "the class must be non-null");
|
||||
var boc = new BeanOutputConverter<T>(clzz);
|
||||
public <T> T single(Class<T> type) {
|
||||
Assert.notNull(type, "the class must be non-null");
|
||||
var boc = new BeanOutputConverter<T>(type);
|
||||
return doSingleWithBeanOutputConverter(boc);
|
||||
}
|
||||
|
||||
@@ -462,9 +462,6 @@ public interface ChatClient {
|
||||
|
||||
public Flux<String> content() {
|
||||
return doGetFluxChatResponse(this.request.userText)
|
||||
// .map(ChatResponse::getResult)
|
||||
// .map(Generation::getOutput)
|
||||
// .map(AssistantMessage::getContent);
|
||||
.map(r -> {
|
||||
if (r.getResult() == null || r.getResult().getOutput() == null
|
||||
|| r.getResult().getOutput().getContent() == null) {
|
||||
@@ -487,8 +484,8 @@ public interface ChatClient {
|
||||
|
||||
}
|
||||
|
||||
public CollectResponseSpec collect() {
|
||||
return new CollectResponseSpec(this.caller, this);
|
||||
public CallResponseSpec call() {
|
||||
return new CallResponseSpec(this.caller, this);
|
||||
}
|
||||
|
||||
public StreamResponseSpec stream() {
|
||||
|
||||
@@ -20,12 +20,12 @@ class DefaultChatClient implements ChatClient {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChatClientRequest call() {
|
||||
public ChatClientRequest prompt() {
|
||||
return new ChatClientRequest(this.defaultChatClientRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* use the new fluid DSL starting in {@link #call()}
|
||||
* use the new fluid DSL starting in {@link #prompt()}
|
||||
* @param prompt the {@link Prompt prompt} object
|
||||
* @return a {@link ChatResponse chat response}
|
||||
*/
|
||||
|
||||
@@ -46,9 +46,9 @@ public class Main {
|
||||
.defaultFunctions("function1")
|
||||
.build();
|
||||
|
||||
String response = client.call()
|
||||
String response = client.prompt()
|
||||
.user(u -> u.text("User text {music}").param("music", "Rock").media(MimeTypeUtils.IMAGE_PNG, url))
|
||||
.collect()
|
||||
.call()
|
||||
.single(String.class);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright 2023 - 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.autoconfigure.openai.tool;
|
||||
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.springframework.ai.autoconfigure.openai.OpenAiAutoConfiguration;
|
||||
import org.springframework.ai.autoconfigure.retry.SpringAiRetryAutoConfiguration;
|
||||
import org.springframework.ai.chat.ChatClient;
|
||||
import org.springframework.ai.openai.OpenAiModelCaller;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@EnabledIfEnvironmentVariable(named = "OPENAI_API_KEY", matches = ".*")
|
||||
public class FunctionCallbackInPrompt2IT {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(FunctionCallbackInPromptIT.class);
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withPropertyValues("spring.ai.openai.apiKey=" + System.getenv("OPENAI_API_KEY"))
|
||||
.withConfiguration(AutoConfigurations.of(SpringAiRetryAutoConfiguration.class,
|
||||
RestClientAutoConfiguration.class, OpenAiAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void functionCallTest() {
|
||||
contextRunner.withPropertyValues("spring.ai.openai.chat.options.model=gpt-4-turbo-preview").run(context -> {
|
||||
|
||||
OpenAiModelCaller caller = context.getBean(OpenAiModelCaller.class);
|
||||
|
||||
ChatClient chatClient = ChatClient.builder(caller).build();
|
||||
|
||||
chatClient.prompt()
|
||||
.user("Tell me a joke?")
|
||||
.call().content();
|
||||
|
||||
String content = ChatClient.builder(caller).build().prompt()
|
||||
.user("What's the weather like in San Francisco, Tokyo, and Paris?")
|
||||
.function("CurrentWeatherService", "Get the weather in location", new MockWeatherService())
|
||||
.call().content();
|
||||
|
||||
logger.info("Response: {}", content);
|
||||
|
||||
assertThat(content).containsAnyOf("30.0", "30");
|
||||
assertThat(content).containsAnyOf("10.0", "10");
|
||||
assertThat(content).containsAnyOf("15.0", "15");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void functionCallTest2() {
|
||||
contextRunner.withPropertyValues("spring.ai.openai.chat.options.model=gpt-4-turbo-preview").run(context -> {
|
||||
|
||||
OpenAiModelCaller caller = context.getBean(OpenAiModelCaller.class);
|
||||
|
||||
String content = ChatClient.builder(caller).build().prompt()
|
||||
.user("What's the weather like in Amsterdam?")
|
||||
.function("CurrentWeatherService", "Get the weather in location",
|
||||
new Function<MockWeatherService.Request, String>() {
|
||||
@Override
|
||||
public String apply(MockWeatherService.Request request) {
|
||||
return "18 degrees Celsius";
|
||||
}
|
||||
})
|
||||
.call().content();
|
||||
|
||||
logger.info("Response: {}", content);
|
||||
|
||||
assertThat(content).contains("18");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void streamingFunctionCallTest() {
|
||||
|
||||
contextRunner.withPropertyValues("spring.ai.openai.chat.options.model=gpt-4-turbo-preview").run(context -> {
|
||||
|
||||
OpenAiModelCaller caller = context.getBean(OpenAiModelCaller.class);
|
||||
|
||||
String content = ChatClient.builder(caller).build().prompt()
|
||||
.user("What's the weather like in San Francisco, Tokyo, and Paris?")
|
||||
.function("CurrentWeatherService", "Get the weather in location", new MockWeatherService())
|
||||
.stream().content()
|
||||
.collectList().block().stream().collect(Collectors.joining());
|
||||
|
||||
logger.info("Response: {}", content);
|
||||
|
||||
assertThat(content).containsAnyOf("30.0", "30");
|
||||
assertThat(content).containsAnyOf("10.0", "10");
|
||||
assertThat(content).containsAnyOf("15.0", "15");
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -58,10 +58,9 @@ public class FunctionCallbackWrapper2IT {
|
||||
.defaultUser(u -> u.text("What's the weather like in {cities}?"))
|
||||
.build();
|
||||
|
||||
String content = chatClient.call()
|
||||
String content = chatClient.prompt()
|
||||
.user(u -> u.param("cities", "San Francisco, Tokyo, Paris"))
|
||||
.collect()
|
||||
.content();
|
||||
.call().content();
|
||||
|
||||
logger.info("Response: {}", content);
|
||||
|
||||
@@ -77,17 +76,11 @@ public class FunctionCallbackWrapper2IT {
|
||||
|
||||
OpenAiModelCaller caller = context.getBean(OpenAiModelCaller.class);
|
||||
|
||||
String content = ChatClient.builder(caller)
|
||||
.build()
|
||||
.call()
|
||||
String content = ChatClient.builder(caller).build().prompt()
|
||||
.functions("WeatherInfo")
|
||||
.user(u -> u.text("What's the weather like in San Francisco, Tokyo, and Paris?"))
|
||||
.stream()
|
||||
.content()
|
||||
.collectList()
|
||||
.block()
|
||||
.stream()
|
||||
.collect(Collectors.joining());
|
||||
.stream().content()
|
||||
.collectList().block().stream().collect(Collectors.joining());
|
||||
|
||||
logger.info("Response: {}", content);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user