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)
相关推荐
NE_STOP19 小时前
MyBatis-配置文件解读及MyBatis为何不用编写Mapper接口的实现类
java
机器之心21 小时前
让AI自我进化?斯坦福华人博士答辩视频火了,庞若鸣参与评审
人工智能·openai
狗胜1 天前
二等兵·甘: 当 Agent 开始替你做决定,系统治理就不是可选项
openai
后端AI实验室1 天前
用AI写代码,我差点把漏洞发上线:血泪总结的10个教训
java·ai
王小酱1 天前
Everything Claude Code 新手教学指南(中文版)
openai·ai编程·claude
程序员清风1 天前
小红书二面:Spring Boot的单例模式是如何实现的?
java·后端·面试
belhomme1 天前
(面试题)Redis实现 IP 维度滑动窗口限流实践
java·面试
树獭叔叔1 天前
19-为什么AI工程这么喜欢"创造名词":从Prompt到Skill的造词运动
后端·aigc·openai
Be_Better1 天前
学会与虚拟机对话---ASM
java