OpenAI Function Call Java Example

From the project: https://github.com/HamaWhiteGG/langchain-java

Please refer to the ChatFunctionTest for the complete test code.

1. Core main process

  • Generates a ChatParameter instance that represents the given class.
  • Invoke the OpenAI API and return the function name and parameters.
  • Execute functions through the FunctionExecutor.

2. Step-by-step introduction

2.1 Declare function parameters and response

java 复制代码
public record Weather(
        @JsonProperty(required = true)
        @JsonPropertyDescription("The city and state, e.g. San Francisco, CA")
        String location,

        @JsonPropertyDescription("The temperature unit")
        WeatherUnit unit
) {}


public enum WeatherUnit {

    CELSIUS,
    FAHRENHEIT
}


@Data
@Builder
public class WeatherResponse {

    public String location;

    public WeatherUnit unit;

    public int temperature;

    public String description;
}


WeatherResponse getCurrentWeather(Weather weather) {
    // mock function
    return WeatherResponse.builder()
            .location(weather.location())
            .unit(weather.unit())
            .temperature(new Random().nextInt(50))
            .description("sunny")
            .build();
}

2.2 Generates a ChatParameter instance that represents the given class

Automatically convert Weather.class to ChatParameter using the ChatParameterUtils.generate method.

java 复制代码
ChatFunction.ChatParameter chatParameter = ChatParameterUtils.generate(Weather.class);

The output of converting chatParameter to JSON String is as follows:

json 复制代码
{
    "type" : "object",
    "properties" : {
        "location" : {
            "type" : "string",
            "description" : "The city and state, e.g. San Francisco, CA"
        },
        "unit" : {
            "type" : "string",
            "description" : "The temperature unit",
            "enum" : [
                "celsius",
                "fahrenheit"
            ]
        }
    },
    "required" : [
        "location"
    ]
}

2.3 Invoke the OpenAI API and return the function name and parameters.

java 复制代码
ChatFunction chatFunction = ChatFunction.builder()
        .name(functionName)
        .description("Get the current weather in a given location")
        .parameters(ChatParameterUtils.generate(Weather.class))
        .build();

Message message = Message.of("What is the weather like in Boston?");

ChatCompletion chatCompletion = ChatCompletion.builder()
        .model("gpt-4")
        .temperature(0)
        .messages(List.of(message))
        .tools(List.of(new Tool(chatFunction)))
        .toolChoice("auto")
        .build();

ChatCompletionResp response = client.createChatCompletion(chatCompletion);
ChatChoice chatChoice = response.getChoices().get(0);

The output of converting chatChoice to JSON String is as follows:

json 复制代码
{
    "index":0,
    "message":{
        "role":"assistant",
        "content":null,
        "tool_calls":[
            {
                "id":"call_aS4LspVVBkE8uIiBSLZWXe6O",
                "type":"function",
                "function":{
                    "name":"get_current_weather",
                    "arguments":"{\n  \"location\": \"Boston, MA\"\n}"
                }
            }
        ]
    },
    "finish_reason":"tool_calls"
}

2.4 Execute functions through the FunctionExecutor.

The code for FunctionExecutor is as follows, allowing the caller to avoid explicit type casting through generics, making the code more concise and elegant.

java 复制代码
public class FunctionExecutor {

    private static final Map<String, Function<?, ?>> FUNCTION_MAP = new HashMap<>(16);

    public static <T> void register(String functionName, Function<T, ?> function) {
        FUNCTION_MAP.put(functionName, function);
    }

    @SuppressWarnings("unchecked")
    public static <T, R> R execute(String functionName, Class<T> clazz, String arguments) throws ClassCastException {
        Function<T, R> function = (Function<T, R>) FUNCTION_MAP.get(functionName);
        if (function == null) {
            throw new IllegalArgumentException("No function registered with name: " + functionName);
        }
        T input = convertFromJsonStr(arguments, clazz);
        return function.apply(input);
    }
}

The caller's code is as follows:

java 复制代码
Function function = chatChoice.getMessage().getToolCalls().get(0).getFunction();

// execute function
WeatherResponse weatherResponse = FunctionExecutor.execute(function.getName(), Weather.class, function.getArguments());
System.out.println(weatherResponse)

The final result is:

shell 复制代码
WeatherResponse(location=Boston, MA, unit=null, temperature=2, description=sunny)
相关推荐
都叫我大帅哥14 分钟前
@EnableTransactionManagement 详解:Spring 声明式事务的基石
java·spring
2602_959960921 小时前
大厂Java面试:Spring Boot、JVM、Redis、Kafka与Elasticsearch在内容社区UGC场景下的实战拷问
java·jvm·spring boot·redis·面试题
怕浪猫8 小时前
DeepSeek Harness 源码实战第3章:Profile / Bundle / Patch——dsh 的装配系统
openai·agent·ai编程
St_rive8 小时前
Page Object设计模式
java·开发语言·设计模式
风流 少年9 小时前
Spring AI 2.0:SSE
java·人工智能·spring
凤山老林9 小时前
精细化流量治理:Spring Boot 动态特性开关与灰度发布体系
java·spring boot·后端
Aphelios38011 小时前
一次锁内网络IO引发的Tomcat线程池“饿死”事故
java·开发语言·spring boot·elasticsearch·tomcat·网络io阻塞·线程池耗尽
不可求~12 小时前
C++ std::string_view 不是字符串:从悬空引用到安全用法
java·开发语言·c++
Lam Tang12 小时前
APS 系列文章10
java·代理模式