ChatClient register functions with explicit input type
The Lambda functions do not retain the type information, so we need to provide the input type explicitly. Resolves #1052 Co-authored-by: liuzhifei <2679431923@qq.com>
This commit is contained in:
@@ -17,7 +17,9 @@ package org.springframework.ai.openai.chat.client;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -25,6 +27,7 @@ import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ai.chat.client.ChatClient;
|
||||
import org.springframework.ai.chat.client.DefaultChatClient;
|
||||
import org.springframework.ai.openai.OpenAiTestConfiguration;
|
||||
import org.springframework.ai.openai.api.tool.MockWeatherService;
|
||||
import org.springframework.ai.openai.testutils.AbstractIT;
|
||||
@@ -123,4 +126,47 @@ class OpenAiChatClientMultipleFunctionCallsIT extends AbstractIT {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void functionCallWithExplicitInputType() throws NoSuchMethodException {
|
||||
|
||||
var chatClient = ChatClient.create(chatModel);
|
||||
|
||||
Method currentTemp = MyFunction.class.getMethod("getCurrentTemp", MyFunction.Req.class);
|
||||
|
||||
// NOTE: Lambda functions do not retain the type information, so we need to
|
||||
// provide the input type explicitly.
|
||||
MyFunction myFunction = new MyFunction();
|
||||
Function<MyFunction.Req, Object> function = createFunction(myFunction, currentTemp);
|
||||
|
||||
ChatClient.ChatClientRequestSpec chatClientRequestSpec = chatClient.prompt()
|
||||
.user("What's the weather like in Shanghai?")
|
||||
.function("currentTemp", "get current temp", MyFunction.Req.class, function);
|
||||
|
||||
String content = chatClientRequestSpec.call().content();
|
||||
|
||||
assertThat(content).contains("23");
|
||||
}
|
||||
|
||||
public static <T, R> Function<T, R> createFunction(Object obj, Method method) {
|
||||
return (T t) -> {
|
||||
try {
|
||||
return (R) method.invoke(obj, t);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static class MyFunction {
|
||||
|
||||
public record Req(String city) {
|
||||
}
|
||||
|
||||
public String getCurrentTemp(Req req) {
|
||||
return "23";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -189,6 +189,9 @@ public interface ChatClient {
|
||||
<I, O> ChatClientRequestSpec function(String name, String description,
|
||||
java.util.function.Function<I, O> function);
|
||||
|
||||
<I, O> ChatClientRequestSpec function(String name, String description, Class<I> inputType,
|
||||
java.util.function.Function<I, O> function);
|
||||
|
||||
ChatClientRequestSpec functions(String... functionBeanNames);
|
||||
|
||||
ChatClientRequestSpec system(String text);
|
||||
|
||||
@@ -610,6 +610,11 @@ public class DefaultChatClient implements ChatClient {
|
||||
|
||||
public <I, O> ChatClientRequestSpec function(String name, String description,
|
||||
java.util.function.Function<I, O> function) {
|
||||
return this.function(name, description, null, function);
|
||||
}
|
||||
|
||||
public <I, O> ChatClientRequestSpec function(String name, String description, Class<I> inputType,
|
||||
java.util.function.Function<I, O> function) {
|
||||
|
||||
Assert.hasText(name, "the name must be non-null and non-empty");
|
||||
Assert.hasText(description, "the description must be non-null and non-empty");
|
||||
@@ -618,6 +623,7 @@ public class DefaultChatClient implements ChatClient {
|
||||
var fcw = FunctionCallbackWrapper.builder(function)
|
||||
.withDescription(description)
|
||||
.withName(name)
|
||||
.withInputType(inputType)
|
||||
.withResponseConverter(Object::toString)
|
||||
.build();
|
||||
this.functionCallbacks.add(fcw);
|
||||
|
||||
Reference in New Issue
Block a user