Reflection Agent Example

This commit is contained in:
Mark Pollack
2024-11-01 15:45:50 -04:00
parent 9ea4523878
commit 6880ad100f
14 changed files with 1596 additions and 0 deletions

View File

@@ -0,0 +1,32 @@
package org.springframework.ai.openai.samples.helloworld;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import java.util.Scanner;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Bean
CommandLineRunner cli(ReflectionAgent reflectionAgent) {
return args -> {
var scanner = new Scanner(System.in);
System.out.println("\nLet's chat!");
// Generate a Java implementation of the Merge Sort algorithm
while (true) {
System.out.print("\nUSER: ");
System.out.println("AGENT: " +
reflectionAgent.run(scanner.nextLine(), 2));
}
};
}
}

View File

@@ -0,0 +1,72 @@
/*
* Copyright 2024 - 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.openai.samples.helloworld;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.memory.InMemoryChatMemory;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.stereotype.Component;
@Component
public class ReflectionAgent {
private final ChatClient generateChatClient;
private final ChatClient critiqueChatClient;
public ReflectionAgent(ChatModel chatModel) {
this.generateChatClient = ChatClient.builder(chatModel)
.defaultSystem("""
You are a Java programmer tasked with generating high quality Java code.
Your task is to Generate the best content possible for the user's request. If the user provides critique,
respond with a revised version of your previous attempt.
""")
.defaultAdvisors(new MessageChatMemoryAdvisor(new InMemoryChatMemory()))
.build();
this.critiqueChatClient = ChatClient.builder(chatModel)
.defaultSystem("""
You are tasked with generating critique and recommendations to the user's generated content.
If the user content has something wrong or something to be improved, output a list of recommendations
and critiques. If the user content is ok and there's nothing to change, output this: <OK>
""")
.defaultAdvisors(new MessageChatMemoryAdvisor(new InMemoryChatMemory()))
.build();
}
public String run(String userQuestion, int maxIterations) {
String generation = generateChatClient.prompt(userQuestion).call().content();
System.out.println("##generation\n\n" + generation);
String critique;
for (int i = 0; i < maxIterations; i++) {
critique = critiqueChatClient.prompt(generation).call().content();
System.out.println("##Critique\n\n" + critique);
if (critique.contains("<OK>")) {
System.out.println("\n\nStop sequence found\n\n");
break;
}
generation = generateChatClient.prompt(critique).call().content();
}
return generation;
}
}

View File

@@ -0,0 +1,29 @@
spring:
ai:
azure:
openai:
chat:
options:
function-callbacks:
- name: "functionName1"
description: "Description of what function1 does"
input-type-schema: |
{
"type": "object",
"properties": {
"param1": {
"type": "string"
}
}
}
- name: "functionName2"
description: "Description of what function2 does"
input-type-schema: |
{
"type": "object",
"properties": {
"param2": {
"type": "integer"
}
}
}

View File

@@ -0,0 +1,100 @@
/*
* Copyright 2024 - 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.openai.samples.helloworld;
public class MergeSort {
public static void mergeSort(int[] array) {
if (array == null || array.length < 2) {
return;
}
int[] tempArray = new int[array.length];
mergeSort(array, tempArray, 0, array.length - 1);
}
private static void mergeSort(int[] array, int[] tempArray, int start, int end) {
if (start < end) {
int mid = (start + end) / 2;
// Recursively sort the two halves
mergeSort(array, tempArray, start, mid);
mergeSort(array, tempArray, mid + 1, end);
// Merge the sorted halves
merge(array, tempArray, start, mid, end);
}
}
private static void merge(int[] array, int[] tempArray, int start, int mid, int end) {
// Copy data to temporary array for merging
System.arraycopy(array, start, tempArray, start, end - start + 1);
int leftIndex = start;
int rightIndex = mid + 1;
int currentIndex = start;
// Merge the temp arrays back into the original array
while (leftIndex <= mid && rightIndex <= end) {
if (tempArray[leftIndex] <= tempArray[rightIndex]) {
array[currentIndex] = tempArray[leftIndex];
leftIndex++;
} else {
array[currentIndex] = tempArray[rightIndex];
rightIndex++;
}
currentIndex++;
}
// Copy remaining elements of left half, if any
while (leftIndex <= mid) {
array[currentIndex] = tempArray[leftIndex];
leftIndex++;
currentIndex++;
}
// No need to copy the right half because it's already in place
}
public static void main(String[] args) {
int[][] testCases = {
{12, 11, 13, 5, 6, 7},
{5, 5, 5, 5, 5, 5},
{},
{-1, -3, -2, -5, -4},
{1, 2, 3, 4, 5, 6},
{9, 7, 5, 3, 1, 0}
};
for (int i = 0; i < testCases.length; i++) {
System.out.println("Test Case " + (i + 1) + ":");
System.out.println("Original Array:");
printArray(testCases[i]);
mergeSort(testCases[i]);
System.out.println("Sorted Array:");
printArray(testCases[i]);
System.out.println();
}
}
private static void printArray(int[] array) {
for (int value : array) {
System.out.print(value + " ");
}
System.out.println();
}
}

View File

@@ -0,0 +1,79 @@
package org.springframework.ai.openai.samples.helloworld;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class ResultFromAgentTest {
@Test
void testMergeSortWithRandomArray() {
int[] array = {12, 11, 13, 5, 6, 7};
int[] expected = {5, 6, 7, 11, 12, 13};
MergeSort.mergeSort(array);
assertArrayEquals(expected, array);
}
@Test
void testMergeSortWithAllSameElements() {
int[] array = {5, 5, 5, 5, 5};
int[] expected = {5, 5, 5, 5, 5};
MergeSort.mergeSort(array);
assertArrayEquals(expected, array);
}
@Test
void testMergeSortWithEmptyArray() {
int[] array = {};
int[] expected = {};
MergeSort.mergeSort(array);
assertArrayEquals(expected, array);
}
@Test
void testMergeSortWithNegativeNumbers() {
int[] array = {-1, -3, -2, -5, -4};
int[] expected = {-5, -4, -3, -2, -1};
MergeSort.mergeSort(array);
assertArrayEquals(expected, array);
}
@Test
void testMergeSortWithAlreadySortedArray() {
int[] array = {1, 2, 3, 4, 5, 6};
int[] expected = {1, 2, 3, 4, 5, 6};
MergeSort.mergeSort(array);
assertArrayEquals(expected, array);
}
@Test
void testMergeSortWithReverseSortedArray() {
int[] array = {9, 7, 5, 3, 1, 0};
int[] expected = {0, 1, 3, 5, 7, 9};
MergeSort.mergeSort(array);
assertArrayEquals(expected, array);
}
@Test
void testMergeSortWithNullArray() {
int[] array = null;
// Should not throw an exception
assertDoesNotThrow(() -> MergeSort.mergeSort(array));
}
@Test
void testMergeSortWithSingleElement() {
int[] array = {1};
int[] expected = {1};
MergeSort.mergeSort(array);
assertArrayEquals(expected, array);
}
}