Restructure OpenAI and AzureOpenAI ChatClientITs

- Use List<ChatResponse> to better examine the full response
This commit is contained in:
Mark Pollack
2024-10-07 17:29:11 +02:00
parent 22a61548ac
commit 64b147e699
4 changed files with 96 additions and 8 deletions

View File

@@ -20,13 +20,18 @@ import static com.azure.core.http.policy.HttpLogDetailLevel.BODY_AND_HEADERS;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.converter.BeanOutputConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Bean;
@@ -35,18 +40,77 @@ import com.azure.ai.openai.OpenAIClientBuilder;
import com.azure.ai.openai.OpenAIServiceVersion;
import com.azure.core.credential.AzureKeyCredential;
import com.azure.core.http.policy.HttpLogOptions;
import org.springframework.core.io.Resource;
import reactor.core.publisher.Flux;
/**
* @author Soby Chacko
*/
@SpringBootTest(classes = AzureOpenAiChatClientTest.TestConfiguration.class)
@SpringBootTest(classes = AzureOpenAiChatClientIT.TestConfiguration.class)
@EnabledIfEnvironmentVariable(named = "AZURE_OPENAI_API_KEY", matches = ".+")
@EnabledIfEnvironmentVariable(named = "AZURE_OPENAI_ENDPOINT", matches = ".+")
public class AzureOpenAiChatClientTest {
public class AzureOpenAiChatClientIT {
@Autowired
private ChatClient chatClient;
@Value("classpath:/prompts/system-message.st")
private Resource systemTextResource;
record ActorsFilms(String actor, List<String> movies) {
}
@Test
void call() {
// @formatter:off
ChatResponse response = chatClient.prompt()
.advisors(new SimpleLoggerAdvisor())
.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();
// @formatter:on
assertThat(response.getResults()).hasSize(1);
assertThat(response.getResults().get(0).getOutput().getContent()).contains("Blackbeard");
}
@Test
void beanStreamOutputConverterRecords() {
BeanOutputConverter<ActorsFilms> outputConverter = new BeanOutputConverter<>(ActorsFilms.class);
// @formatter:off
Flux<ChatResponse> chatResponse = chatClient
.prompt()
.advisors(new SimpleLoggerAdvisor())
.user(u -> u
.text("Generate the filmography of 5 movies for Tom Hanks. " + System.lineSeparator()
+ "{format}")
.param("format", outputConverter.getFormat()))
.stream()
.chatResponse();
List<ChatResponse> chatResponses = chatResponse.collectList()
.block()
.stream()
.toList();
String generationTextFromStream = chatResponses
.stream()
.map(cr -> cr.getResult().getOutput().getContent())
.collect(Collectors.joining());
// @formatter:on
ActorsFilms actorsFilms = outputConverter.convert(generationTextFromStream);
assertThat(actorsFilms.actor()).isEqualTo("Tom Hanks");
assertThat(actorsFilms.movies()).hasSize(5);
}
@Test
void streamingAndImperativeResponsesContainIdenticalRelevantResults() {
String prompt = "Name all states in the USA and their capitals, add a space followed by a hyphen, then another space between the two. "

View File

@@ -0,0 +1,4 @@
"You are a helpful AI assistant. Your name is {name}.
You are an AI assistant that helps people find information.
Your name is {name}
You should reply to the user's request with your name and also in the style of a {voice}.

View File

@@ -212,19 +212,25 @@ class OpenAiChatClientIT extends AbstractIT {
BeanOutputConverter<ActorsFilms> outputConverter = new BeanOutputConverter<>(ActorsFilms.class);
// @formatter:off
Flux<String> chatResponse = ChatClient.create(chatModel)
Flux<ChatResponse> chatResponse = ChatClient.create(chatModel)
.prompt()
.options(OpenAiChatOptions.builder().withStreamUsage(true).build())
.advisors(new SimpleLoggerAdvisor())
.user(u -> u
.text("Generate the filmography of 5 movies for Tom Hanks. " + System.lineSeparator()
+ "{format}")
.param("format", outputConverter.getFormat()))
.stream()
.content();
.chatResponse();
String generationTextFromStream = chatResponse.collectList()
List<ChatResponse> chatResponses = chatResponse.collectList()
.block()
.stream()
.toList();
String generationTextFromStream = chatResponses
.stream()
.map(cr -> cr.getResult().getOutput().getContent())
.collect(Collectors.joining());
// @formatter:on

View File

@@ -34,9 +34,12 @@ import org.springframework.ai.chat.memory.InMemoryChatMemory;
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.MessageType;
import org.springframework.ai.chat.metadata.ChatResponseMetadata;
import org.springframework.ai.chat.metadata.EmptyUsage;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.model.Generation;
import org.springframework.ai.chat.model.MessageAggregator;
import org.springframework.ai.chat.prompt.Prompt;
import reactor.core.publisher.Flux;
@@ -60,9 +63,19 @@ public class ChatClientAdvisorTests {
@Test
public void promptChatMemory() {
var builder = ChatResponseMetadata.builder()
.withId("124")
.withUsage(new MessageAggregator.DefaultUsage(1, 2, 3))
.withModel("gpt4o")
.withKeyValue("created", 0L)
.withKeyValue("system-fingerprint", "john doe");
ChatResponseMetadata chatResponseMetadata = builder.build();
when(chatModel.call(promptCaptor.capture()))
.thenReturn(new ChatResponse(List.of(new Generation(new AssistantMessage("Hello John")))))
.thenReturn(new ChatResponse(List.of(new Generation(new AssistantMessage("Your name is John")))));
.thenReturn(
new ChatResponse(List.of(new Generation(new AssistantMessage("Hello John"))), chatResponseMetadata))
.thenReturn(new ChatResponse(List.of(new Generation(new AssistantMessage("Your name is John"))),
chatResponseMetadata));
ChatMemory chatMemory = new InMemoryChatMemory();
@@ -71,8 +84,9 @@ public class ChatClientAdvisorTests {
.defaultAdvisors(new PromptChatMemoryAdvisor(chatMemory))
.build();
var content = chatClient.prompt().user("my name is John").call().content();
ChatResponse chatResponse = chatClient.prompt().user("my name is John").call().chatResponse();
String content = chatResponse.getResult().getOutput().getContent();
assertThat(content).isEqualTo("Hello John");
Message systemMessage = promptCaptor.getValue().getInstructions().get(0);