Refactor WatsonxAiChatOptions builder methods

- Refactor the builder methods to remove `with` as the prefix.
- Introduce new methods with updated naming conventions.
- Deprecate the existing `with*` methods to maintain backward compatibility.
- Update WatsonxAi documentation
This commit is contained in:
Alexandros Pappas
2024-12-16 18:50:19 +01:00
committed by Ilayaperumal Gopinathan
parent 1d38fd11fd
commit eccf33a6ec
6 changed files with 208 additions and 107 deletions

View File

@@ -49,6 +49,7 @@ import org.springframework.util.Assert;
* @author Pablo Sanchidrian Herrera
* @author John Jario Moreno Rojas
* @author Christian Tzolov
* @author Alexandros Pappas
* @since 1.0.0
*/
public class WatsonxAiChatModel implements ChatModel, StreamingChatModel {
@@ -60,14 +61,14 @@ public class WatsonxAiChatModel implements ChatModel, StreamingChatModel {
public WatsonxAiChatModel(WatsonxAiApi watsonxAiApi) {
this(watsonxAiApi,
WatsonxAiChatOptions.builder()
.withTemperature(0.7)
.withTopP(1.0)
.withTopK(50)
.withDecodingMethod("greedy")
.withMaxNewTokens(20)
.withMinNewTokens(0)
.withRepetitionPenalty(1.0)
.withStopSequences(List.of())
.temperature(0.7)
.topP(1.0)
.topK(50)
.decodingMethod("greedy")
.maxNewTokens(20)
.minNewTokens(0)
.repetitionPenalty(1.0)
.stopSequences(List.of())
.build());
}

View File

@@ -37,6 +37,7 @@ import org.springframework.ai.chat.prompt.ChatOptions;
* @author Pablo Sanchidrian Herrera
* @author John Jairo Moreno Rojas
* @author Thomas Vitale
* @author Alexandros Pappas
* @since 1.0.0
* @see <a href=
* "https://dataplatform.cloud.ibm.com/docs/content/wsj/analyze-data/fm-model-parameters.html?context=wx&audience=wdp">watsonx.ai
@@ -155,17 +156,17 @@ public class WatsonxAiChatOptions implements ChatOptions {
public static WatsonxAiChatOptions fromOptions(WatsonxAiChatOptions fromOptions) {
return WatsonxAiChatOptions.builder()
.withTemperature(fromOptions.getTemperature())
.withTopP(fromOptions.getTopP())
.withTopK(fromOptions.getTopK())
.withDecodingMethod(fromOptions.getDecodingMethod())
.withMaxNewTokens(fromOptions.getMaxNewTokens())
.withMinNewTokens(fromOptions.getMinNewTokens())
.withStopSequences(fromOptions.getStopSequences())
.withRepetitionPenalty(fromOptions.getRepetitionPenalty())
.withRandomSeed(fromOptions.getRandomSeed())
.withModel(fromOptions.getModel())
.withAdditionalProperties(fromOptions.getAdditionalProperties())
.temperature(fromOptions.getTemperature())
.topP(fromOptions.getTopP())
.topK(fromOptions.getTopK())
.decodingMethod(fromOptions.getDecodingMethod())
.maxNewTokens(fromOptions.getMaxNewTokens())
.minNewTokens(fromOptions.getMinNewTokens())
.stopSequences(fromOptions.getStopSequences())
.repetitionPenalty(fromOptions.getRepetitionPenalty())
.randomSeed(fromOptions.getRandomSeed())
.model(fromOptions.getModel())
.additionalProperties(fromOptions.getAdditionalProperties())
.build();
}
@@ -326,66 +327,162 @@ public class WatsonxAiChatOptions implements ChatOptions {
WatsonxAiChatOptions options = new WatsonxAiChatOptions();
public Builder withTemperature(Double temperature) {
public Builder temperature(Double temperature) {
this.options.temperature = temperature;
return this;
}
public Builder withTopP(Double topP) {
public Builder topP(Double topP) {
this.options.topP = topP;
return this;
}
public Builder withTopK(Integer topK) {
public Builder topK(Integer topK) {
this.options.topK = topK;
return this;
}
public Builder withDecodingMethod(String decodingMethod) {
public Builder decodingMethod(String decodingMethod) {
this.options.decodingMethod = decodingMethod;
return this;
}
public Builder withMaxNewTokens(Integer maxNewTokens) {
public Builder maxNewTokens(Integer maxNewTokens) {
this.options.maxNewTokens = maxNewTokens;
return this;
}
public Builder withMinNewTokens(Integer minNewTokens) {
public Builder minNewTokens(Integer minNewTokens) {
this.options.minNewTokens = minNewTokens;
return this;
}
public Builder withStopSequences(List<String> stopSequences) {
public Builder stopSequences(List<String> stopSequences) {
this.options.stopSequences = stopSequences;
return this;
}
public Builder withRepetitionPenalty(Double repetitionPenalty) {
public Builder repetitionPenalty(Double repetitionPenalty) {
this.options.repetitionPenalty = repetitionPenalty;
return this;
}
public Builder withRandomSeed(Integer randomSeed) {
public Builder randomSeed(Integer randomSeed) {
this.options.randomSeed = randomSeed;
return this;
}
public Builder withModel(String model) {
public Builder model(String model) {
this.options.model = model;
return this;
}
public Builder withAdditionalProperty(String key, Object value) {
public Builder additionalProperty(String key, Object value) {
this.options.additional.put(key, value);
return this;
}
public Builder withAdditionalProperties(Map<String, Object> properties) {
public Builder additionalProperties(Map<String, Object> properties) {
this.options.additional.putAll(properties);
return this;
}
/**
* @deprecated use {@link #temperature(Double)} instead.
*/
@Deprecated(forRemoval = true, since = "1.0.0-M5")
public Builder withTemperature(Double temperature) {
return temperature(temperature);
}
/**
* @deprecated use {@link #topP(Double)} instead.
*/
@Deprecated(forRemoval = true, since = "1.0.0-M5")
public Builder withTopP(Double topP) {
return topP(topP);
}
/**
* @deprecated use {@link #topK(Integer)} instead.
*/
@Deprecated(forRemoval = true, since = "1.0.0-M5")
public Builder withTopK(Integer topK) {
return topK(topK);
}
/**
* @deprecated use {@link #decodingMethod(String)} instead.
*/
@Deprecated(forRemoval = true, since = "1.0.0-M5")
public Builder withDecodingMethod(String decodingMethod) {
return decodingMethod(decodingMethod);
}
/**
* @deprecated use {@link #maxNewTokens(Integer)} instead.
*/
@Deprecated(forRemoval = true, since = "1.0.0-M5")
public Builder withMaxNewTokens(Integer maxNewTokens) {
return maxNewTokens(maxNewTokens);
}
/**
* @deprecated use {@link #minNewTokens(Integer)} instead.
*/
@Deprecated(forRemoval = true, since = "1.0.0-M5")
public Builder withMinNewTokens(Integer minNewTokens) {
return minNewTokens(minNewTokens);
}
/**
* @deprecated use {@link #stopSequences(List)} instead.
*/
@Deprecated(forRemoval = true, since = "1.0.0-M5")
public Builder withStopSequences(List<String> stopSequences) {
return stopSequences(stopSequences);
}
/**
* @deprecated use {@link #repetitionPenalty(Double)} instead.
*/
@Deprecated(forRemoval = true, since = "1.0.0-M5")
public Builder withRepetitionPenalty(Double repetitionPenalty) {
return repetitionPenalty(repetitionPenalty);
}
/**
* @deprecated use {@link #randomSeed(Integer)} instead.
*/
@Deprecated(forRemoval = true, since = "1.0.0-M5")
public Builder withRandomSeed(Integer randomSeed) {
return randomSeed(randomSeed);
}
/**
* @deprecated use {@link #model(String)} instead.
*/
@Deprecated(forRemoval = true, since = "1.0.0-M5")
public Builder withModel(String model) {
return model(model);
}
/**
* @deprecated use {@link #additionalProperty(String, Object)} instead.
*/
@Deprecated(forRemoval = true, since = "1.0.0-M5")
public Builder withAdditionalProperty(String key, Object value) {
return additionalProperty(key, value);
}
/**
* @deprecated use {@link #additionalProperties(Map)} instead.
*/
@Deprecated(forRemoval = true, since = "1.0.0-M5")
public Builder withAdditionalProperties(Map<String, Object> properties) {
return additionalProperties(properties);
}
public WatsonxAiChatOptions build() {
return this.options;
}

View File

@@ -47,6 +47,7 @@ import static org.mockito.Mockito.mock;
/**
* @author Pablo Sanchidrian Herrera
* @author John Jairo Moreno Rojas
* @author Alexandros Pappas
*/
public class WatsonxAiChatModelTest {
@@ -66,9 +67,7 @@ public class WatsonxAiChatModelTest {
String msg = "Test message";
WatsonxAiChatOptions modelOptions = WatsonxAiChatOptions.builder()
.withModel("meta-llama/llama-2-70b-chat")
.build();
WatsonxAiChatOptions modelOptions = WatsonxAiChatOptions.builder().model("meta-llama/llama-2-70b-chat").build();
Prompt prompt = new Prompt(msg, modelOptions);
WatsonxAiChatRequest request = this.chatModel.request(prompt);
@@ -91,16 +90,16 @@ public class WatsonxAiChatModelTest {
String msg = "Test message";
WatsonxAiChatOptions modelOptions = WatsonxAiChatOptions.builder()
.withModel("meta-llama/llama-2-70b-chat")
.withDecodingMethod("sample")
.withTemperature(0.1)
.withTopP(0.2)
.withTopK(10)
.withMaxNewTokens(30)
.withMinNewTokens(10)
.withRepetitionPenalty(1.4)
.withStopSequences(List.of("\n\n\n"))
.withRandomSeed(4)
.model("meta-llama/llama-2-70b-chat")
.decodingMethod("sample")
.temperature(0.1)
.topP(0.2)
.topK(10)
.maxNewTokens(30)
.minNewTokens(10)
.repetitionPenalty(1.4)
.stopSequences(List.of("\n\n\n"))
.randomSeed(4)
.build();
Prompt prompt = new Prompt(msg, modelOptions);
@@ -125,16 +124,16 @@ public class WatsonxAiChatModelTest {
String msg = "Test message";
WatsonxAiChatOptions modelOptions = WatsonxAiChatOptions.builder()
.withModel("meta-llama/llama-2-70b-chat")
.withDecodingMethod("sample")
.withTemperature(0.1)
.withTopP(0.2)
.withTopK(10)
.withMaxNewTokens(30)
.withMinNewTokens(10)
.withRepetitionPenalty(1.4)
.withStopSequences(List.of("\n\n\n"))
.withRandomSeed(4)
.model("meta-llama/llama-2-70b-chat")
.decodingMethod("sample")
.temperature(0.1)
.topP(0.2)
.topK(10)
.maxNewTokens(30)
.minNewTokens(10)
.repetitionPenalty(1.4)
.stopSequences(List.of("\n\n\n"))
.randomSeed(4)
.build();
Prompt prompt = new Prompt(msg, modelOptions);
@@ -160,9 +159,9 @@ public class WatsonxAiChatModelTest {
WatsonxAiChatModel chatModel = new WatsonxAiChatModel(mockChatApi);
Prompt prompt = new Prompt(List.of(new SystemMessage("Your prompt here")),
WatsonxAiChatOptions.builder().withModel("google/flan-ul2").build());
WatsonxAiChatOptions.builder().model("google/flan-ul2").build());
WatsonxAiChatOptions parameters = WatsonxAiChatOptions.builder().withModel("google/flan-ul2").build();
WatsonxAiChatOptions parameters = WatsonxAiChatOptions.builder().model("google/flan-ul2").build();
WatsonxAiChatResults fakeResults = new WatsonxAiChatResults("LLM response", 4, 3, "max_tokens");
@@ -193,9 +192,9 @@ public class WatsonxAiChatModelTest {
WatsonxAiChatModel chatModel = new WatsonxAiChatModel(mockChatApi);
Prompt prompt = new Prompt(List.of(new SystemMessage("Your prompt here")),
WatsonxAiChatOptions.builder().withModel("google/flan-ul2").build());
WatsonxAiChatOptions.builder().model("google/flan-ul2").build());
WatsonxAiChatOptions parameters = WatsonxAiChatOptions.builder().withModel("google/flan-ul2").build();
WatsonxAiChatOptions parameters = WatsonxAiChatOptions.builder().model("google/flan-ul2").build();
WatsonxAiChatResults fakeResultsFirst = new WatsonxAiChatResults("LLM resp", 0, 0, "max_tokens");
WatsonxAiChatResults fakeResultsSecond = new WatsonxAiChatResults("onse", 4, 3, "not_finished");

View File

@@ -28,21 +28,22 @@ import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Pablo Sanchidrian Herrera
* @author John Jairo Moreno Rojas
* @author Alexandros Pappas
*/
public class WatsonxAiChatOptionTest {
@Test
public void testOptions() {
WatsonxAiChatOptions options = WatsonxAiChatOptions.builder()
.withDecodingMethod("sample")
.withTemperature(1.2)
.withTopK(20)
.withTopP(0.5)
.withMaxNewTokens(100)
.withMinNewTokens(20)
.withStopSequences(List.of("\n\n\n"))
.withRepetitionPenalty(1.1)
.withRandomSeed(4)
.decodingMethod("sample")
.temperature(1.2)
.topK(20)
.topP(0.5)
.maxNewTokens(100)
.minNewTokens(20)
.stopSequences(List.of("\n\n\n"))
.repetitionPenalty(1.1)
.randomSeed(4)
.build();
var optionsMap = options.toMap();
@@ -61,17 +62,17 @@ public class WatsonxAiChatOptionTest {
@Test
public void testOptionsWithAdditionalParamsOneByOne() {
WatsonxAiChatOptions options = WatsonxAiChatOptions.builder()
.withDecodingMethod("sample")
.withTemperature(1.2)
.withTopK(20)
.withTopP(0.5)
.withMaxNewTokens(100)
.withMinNewTokens(20)
.withStopSequences(List.of("\n\n\n"))
.withRepetitionPenalty(1.1)
.withRandomSeed(4)
.withAdditionalProperty("HAP", true)
.withAdditionalProperty("typicalP", 0.5f)
.decodingMethod("sample")
.temperature(1.2)
.topK(20)
.topP(0.5)
.maxNewTokens(100)
.minNewTokens(20)
.stopSequences(List.of("\n\n\n"))
.repetitionPenalty(1.1)
.randomSeed(4)
.additionalProperty("HAP", true)
.additionalProperty("typicalP", 0.5f)
.build();
var optionsMap = options.toMap();
@@ -92,16 +93,16 @@ public class WatsonxAiChatOptionTest {
@Test
public void testOptionsWithAdditionalParamsMap() {
WatsonxAiChatOptions options = WatsonxAiChatOptions.builder()
.withDecodingMethod("sample")
.withTemperature(1.2)
.withTopK(20)
.withTopP(0.5)
.withMaxNewTokens(100)
.withMinNewTokens(20)
.withStopSequences(List.of("\n\n\n"))
.withRepetitionPenalty(1.1)
.withRandomSeed(4)
.withAdditionalProperties(Map.of("HAP", true, "typicalP", 0.5f, "test_value", "test"))
.decodingMethod("sample")
.temperature(1.2)
.topK(20)
.topP(0.5)
.maxNewTokens(100)
.minNewTokens(20)
.stopSequences(List.of("\n\n\n"))
.repetitionPenalty(1.1)
.randomSeed(4)
.additionalProperties(Map.of("HAP", true, "typicalP", 0.5f, "test_value", "test"))
.build();
var optionsMap = options.toMap();
@@ -122,7 +123,7 @@ public class WatsonxAiChatOptionTest {
@Test
public void testFilterOut() {
WatsonxAiChatOptions options = WatsonxAiChatOptions.builder().withModel("google/flan-ul2").build();
WatsonxAiChatOptions options = WatsonxAiChatOptions.builder().model("google/flan-ul2").build();
var mappedOptions = WatsonxAiChatOptions.filterNonSupportedFields(options.toMap());
assertThat(mappedOptions).doesNotContainEntry("model", "google/flan-ul2");
}

View File

@@ -87,7 +87,7 @@ ChatResponse response = chatModel.call(
new Prompt(
"Generate the names of 5 famous pirates.",
WatsonxAiChatOptions.builder()
.withTemperature(0.4)
.temperature(0.4)
.build()
));
----
@@ -112,10 +112,11 @@ public class MyClass {
public String generate(String userInput) {
WatsonxAiOptions options = WatsonxAiOptions.create()
.withModel(MODEL)
.withDecodingMethod("sample")
.withRandomSeed(1);
WatsonxAiChatOptions options = WatsonxAiChatOptions.builder()
.model(MODEL)
.decodingMethod("sample")
.randomSeed(1)
.build();
Prompt prompt = new Prompt(new SystemMessage(userInput), options);
@@ -128,10 +129,11 @@ public class MyClass {
public String generateStream(String userInput) {
WatsonxAiOptions options = WatsonxAiOptions.create()
.withModel(MODEL)
.withDecodingMethod("greedy")
.withRandomSeed(2);
WatsonxAiChatOptions options = WatsonxAiChatOptions.builder()
.model(MODEL)
.decodingMethod("greedy")
.randomSeed(2)
.build();
Prompt prompt = new Prompt(new SystemMessage(userInput), options);

View File

@@ -26,6 +26,7 @@ import org.springframework.boot.context.properties.NestedConfigurationProperty;
* Chat properties for Watsonx.AI Chat.
*
* @author Christian Tzolov
* @author Alexandros Pappas
* @since 1.0.0
*/
@ConfigurationProperties(WatsonxAiChatProperties.CONFIG_PREFIX)
@@ -43,15 +44,15 @@ public class WatsonxAiChatProperties {
*/
@NestedConfigurationProperty
private WatsonxAiChatOptions options = WatsonxAiChatOptions.builder()
.withModel("google/flan-ul2")
.withTemperature(0.7)
.withTopP(1.0)
.withTopK(50)
.withDecodingMethod("greedy")
.withMaxNewTokens(20)
.withMinNewTokens(0)
.withRepetitionPenalty(1.0)
.withStopSequences(List.of())
.model("google/flan-ul2")
.temperature(0.7)
.topP(1.0)
.topK(50)
.decodingMethod("greedy")
.maxNewTokens(20)
.minNewTokens(0)
.repetitionPenalty(1.0)
.stopSequences(List.of())
.build();
public boolean isEnabled() {