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)
相关推荐
rururunu几秒前
Windows 下切换 Java 环境太复杂了,我做了个 cli 工具,可以快速安装,切换 Java 版本
java
qq_452396232 分钟前
第十一篇:《性能压测基础:JMeter线程模型与压测策略设计》
java·开发语言·jmeter
澈20711 分钟前
二叉搜索树:高效增删查的秘诀
java·开发语言·算法
青云计划16 分钟前
Spring
java·后端·spring
yychen_java19 分钟前
深度解析电力交易系统的“硬核”战场
java·能源
爱吃的小肥羊22 分钟前
Codex 手机端连接教程:三分钟搞定,附完整步骤
aigc·openai·ai编程
无尽冬.1 小时前
个人八股之string字符串
java·开发语言·经验分享·后端·异世界
伯远医学1 小时前
Nat. Methods | 邻近标记技术:活细胞中捕捉分子互作的新利器
java·开发语言·前端·javascript·人工智能·算法·eclipse
RainCity1 小时前
Java Swing 自定义组件库分享(五)
java·笔记·后端