Add web search capability to MiniMax model

Implement web search functionality for the MiniMax model.
Includes unit tests
This enhancement expands the model's ability to access and utilize current information from the internet.

Resolves #1245
This commit is contained in:
GR
2024-08-23 22:30:48 +08:00
committed by Mark Pollack
parent 0927bd197d
commit 4fac212b0d
5 changed files with 54 additions and 4 deletions

View File

@@ -17,6 +17,7 @@ package org.springframework.ai.minimax;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.ai.chat.messages.MessageType;
import org.springframework.ai.chat.messages.ToolResponseMessage;
@@ -302,7 +303,7 @@ public class MiniMaxChatModel extends AbstractToolCallSupport implements ChatMod
if (delta == null) {
delta = new ChatCompletionMessage("", Role.ASSISTANT);
}
return new ChatCompletion.Choice(cc.finishReason(), cc.index(), delta, cc.logprobs());
return new ChatCompletion.Choice(cc.finishReason(), cc.index(), delta, null, cc.logprobs());
}).toList();
return new ChatCompletion(chunk.id(), choices, chunk.created(), chunk.model(), chunk.systemFingerprint(),

View File

@@ -160,6 +160,10 @@ public class MiniMaxApi {
this(Type.FUNCTION, function);
}
public static FunctionTool webSearchFunctionTool() {
return new FunctionTool(Type.WEB_SEARCH, null);
}
/**
* Create a tool of type 'function' and the given function definition.
*/
@@ -167,7 +171,8 @@ public class MiniMaxApi {
/**
* Function tool type.
*/
@JsonProperty("function") FUNCTION
@JsonProperty("function") FUNCTION,
@JsonProperty("web_search") WEB_SEARCH
}
/**
@@ -561,6 +566,7 @@ public class MiniMaxApi {
@JsonProperty("finish_reason") ChatCompletionFinishReason finishReason,
@JsonProperty("index") Integer index,
@JsonProperty("message") ChatCompletionMessage message,
@JsonProperty("messages") List<ChatCompletionMessage> messages,
@JsonProperty("logprobs") LogProbs logprobs) {
}

View File

@@ -170,7 +170,23 @@ public class MiniMaxStreamFunctionCallingHelper {
if (choice == null || choice.delta() == null) {
return false;
}
return choice.finishReason() == ChatCompletionFinishReason.TOOL_CALLS;
return choice.finishReason() == MiniMaxApi.ChatCompletionFinishReason.TOOL_CALLS;
}
/**
* Convert the ChatCompletionChunk into a ChatCompletion. The Usage is set to null.
* @param chunk the ChatCompletionChunk to convert
* @return the ChatCompletion
*/
public MiniMaxApi.ChatCompletion chunkToChatCompletion(MiniMaxApi.ChatCompletionChunk chunk) {
List<MiniMaxApi.ChatCompletion.Choice> choices = chunk.choices()
.stream()
.map(chunkChoice -> new MiniMaxApi.ChatCompletion.Choice(chunkChoice.finishReason(), chunkChoice.index(),
chunkChoice.delta(), null, chunkChoice.logprobs()))
.toList();
return new MiniMaxApi.ChatCompletion(chunk.id(), choices, chunk.created(), chunk.model(),
chunk.systemFingerprint(), "chat.completion", null, null);
}
}

View File

@@ -131,6 +131,33 @@ public class MiniMaxApiToolFunctionCallIT {
.containsAnyOf("°C", "Celsius");
}
@SuppressWarnings("null")
@Test
public void webSearchToolFunctionCall() {
var message = new ChatCompletionMessage(
"How many gold medals has the United States won in total at the 2024 Olympics?", Role.USER);
var functionTool = MiniMaxApi.FunctionTool.webSearchFunctionTool();
List<ChatCompletionMessage> messages = new ArrayList<>(List.of(message));
ChatCompletionRequest chatCompletionRequest = new ChatCompletionRequest(messages,
org.springframework.ai.minimax.api.MiniMaxApi.ChatModel.ABAB_6_5_S_Chat.getValue(),
List.of(functionTool), ToolChoiceBuilder.AUTO);
ResponseEntity<ChatCompletion> chatCompletion = miniMaxApi.chatCompletionEntity(chatCompletionRequest);
assertThat(chatCompletion.getBody()).isNotNull();
assertThat(chatCompletion.getBody().choices()).isNotEmpty();
List<ChatCompletionMessage> responseMessages = chatCompletion.getBody().choices().get(0).messages();
ChatCompletionMessage assistantMessage = responseMessages.get(responseMessages.size() - 1);
assertThat(assistantMessage.role()).isEqualTo(Role.ASSISTANT);
assertThat(assistantMessage.content()).contains("40");
}
private static <T> T fromJson(String json, Class<T> targetClass) {
try {
return new ObjectMapper().readValue(json, targetClass);

View File

@@ -102,7 +102,7 @@ public class MiniMaxRetryTests {
public void miniMaxChatTransientError() {
var choice = new ChatCompletion.Choice(ChatCompletionFinishReason.STOP, 0,
new ChatCompletionMessage("Response", Role.ASSISTANT), null);
new ChatCompletionMessage("Response", Role.ASSISTANT), null, null);
ChatCompletion expectedChatCompletion = new ChatCompletion("id", List.of(choice), 666l, "model", null, null,
null, new MiniMaxApi.Usage(10, 10, 10));