Function Call 概念
关于 GPT 中API的function参数,提供了一些能力 这个函数调用是 Open AI 在2023年的6.13号发布的新能力 根据它的官方描述, 函数调用能力可以让模型输出一个请求调用函数的消息 其中包含所需调用函数的信息,以及调用函数时所需携带的参数的信息 这种方式是一种将GPT的能力和外部的工具,外部的API连接起来的新的方式函数调用的机制
那么应该如何去使用函数调用? 首先我们需要去选择函数调用的新模型 用户在构造message参数时候,需要主动的告诉模型有哪些函数 GPT 知道我们有哪些函数之后,根据对于自然语言的理解,根据用户的输入 GPT会自行的判断何时需要调用这些函数,然后会根据目标函数它的描述生成符合要求的请求的参数 然后返回给我们,我们根据GPT的信息再去调用函数函数的作用
第一种,进行自然语言交流时,通过调用外部工具回答问题 通过这种函数调用的能力,我们可以将GPT和第三方的工具去进行一个集成,形成类似于GPT插件的这种模式 第二种,如果我们有特殊的对于自然语言处理的逻辑 我们可以利用GPT, 将自然语言转换成调用API时使用的参数, 或转换成查询数据库时所使用的条件等等 第三种,我们可以利用这种能力从文本当中去提取一些结构化的数据,这是函数的一些基础的作用。函数调用的使用
那么我们如何去使用函数调用呢?如何在它的聊天API的接口上去添加函数相关的这些参数呢? 为了实现函数调用的能力, 在API里面有新的请求的参数就是function, function call等等, 在官方的API文档上可以查询 在使用之前,我们先来了解一下函数调用的步骤 第一步, 当我们去调用函数的时候,首先我们需要在请求参数当中向API也就是向GPT去传递信息, 我们要告诉GPT, 我们有哪些可以调用的函数 第二步, 我们根据GPT的返回, 我们要去进行解析, 判断模型是不是需要调用函数, 如果不需要,我们则不处理 如果需要调用函数,我们这里要根据需要调用的函数,根据GPT输入的参数去进行调用 调用完成之后,得到函数调用的结果 最后, 我们再将函数调用的结果添加到GPT的消息列表来告诉GPT代码实现
参考前文: https://blog.csdn.net/Tyro_java/article/details/1347810211 )新增一些实现类,结构如下
src main java com.xxx.gpt.client entity ChatFunction.java FunctionCallResult.java … test java com.xxx.gpt.client.test FunctionCallTest.java …ChatFunction.java
package com.xxx.gpt.client.entity; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import java.util.List; @Data @AllArgsConstructor @NoArgsConstructor @Builder @JsonInclude(JsonInclude.Include.NON_NULL) public class ChatFunction { String name; String description; ChatParameter parameters; @Data @AllArgsConstructor @NoArgsConstructor @Builder @JsonInclude(JsonInclude.Include.NON_NULL) public static class ChatParameter { String type; List<String> required; Object properties; } }
ChatFunction 类中包含:名称,描述,参数等等字段 FunctionCallResult.java
package com.xxx.gpt.client.entity; import lombok.Data; @Data public class FunctionCallResult { String name; String arguments; }
FunctionCallResult 定义了名称,参数的字段 FunctionCallTest.java
package com.xxx.gpt.client.test; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.xxx.gpt.client.ChatGPTClient; import com.xxx.gpt.client.entity.*; import com.xxx.gpt.client.util.Proxys; import org.junit.Before; import org.junit.Test; import java.net.Proxy; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class FunctionCallTest { private ChatGPTClient chatGPTClient; @Before public void before() { Proxy proxy = Proxys.http("127.0.0.1", 7890); chatGPTClient = ChatGPTClient.builder() .apiKey("sk-6kchn0DasdfqOJqkc3aI665ct") // 填入自己的 key .timeout(900) .proxy(proxy) .apiHost("https://api.openai.com/") .build() .init(); } // 调用gpt的时候,带上函数信息,让GPT选择是否调用 @Test public void chat() { List<ChatFunction> functions = new ArrayList<>(); ChatFunction function = new ChatFunction(); function.setName("getCurrentWeather"); // 设置函数信息 function.setDescription("获取给定位置的当前天气"); function.setParameters(ChatFunction.ChatParameter.builder() .type("object") .required(Arrays.asList("location")) .properties(JSON.parseObject("{\n" + " \"location\": {\n" + " \"type\": \"string\",\n" + " \"description\": \"The city and state, e.g. San Francisco, " + "CA\"\n" + " },\n" + " \"unit\": {\n" + " \"type\": \"string\",\n" + " \"enum\": [\"celsius\", \"fahrenheit\"]\n" + " }\n" + " }")) .build()); // 添加到列表中 functions.add(function); // 构造 message Message message = Message.of("上海的天气怎么样?"); // 构造调用 api 参数 ChatCompletion chatCompletion = ChatCompletion.builder() .model(Model.GPT_3_5_TURBO_16K.getName()) .messages(Arrays.asList(message)) .functions(functions) .maxTokens(8000) .temperature(0.9) .build(); // 调用 ChatCompletionResponse response = chatGPTClient.chatCompletion(chatCompletion); ChatChoice choice = response.getChoices().get(0); Message res = choice.getMessage(); System.out.println(res); // 基于 finish reason 判断,如果是 function_call 就需要调用函数 if ("function_call".equals(choice.getFinishReason())) { FunctionCallResult functionCall = res.getFunctionCall(); String functionCallName = functionCall.getName(); // 如果需要调用的是 getCurrentWeather if ("getCurrentWeather".equals(functionCallName)) { String arguments = functionCall.getArguments(); JSONObject jsonObject = JSON.parseObject(arguments); String location = jsonObject.getString("location"); String unit = jsonObject.getString("unit"); // 得到最终的结果 String weather = getCurrentWeather(location, unit); res.setContent(""); // 将结果 weather 告诉GPT callWithWeather(weather, res, functions); } } } // 将结果传送给GPT private void callWithWeather(String weather, Message res, List<ChatFunction> functions) { Message message = Message.of("上海的天气怎么样?"); Message function1 = Message.ofFunction(weather); function1.setName("getCurrentWeather"); ChatCompletion chatCompletion = ChatCompletion.builder() .model(Model.GPT_3_5_TURBO_16K.getName()) .messages(Arrays.asList(message, res, function1)) .functions(functions) .maxTokens(8000) .temperature(0.9) .build(); ChatCompletionResponse response = chatGPTClient.chatCompletion(chatCompletion); ChatChoice choice = response.getChoices().get(0); Message res2 = choice.getMessage(); //上海目前天气晴朗,气温为 22 摄氏度。 System.out.println(res2.getContent()); } // 首先我们添加一个函数,函数是获取天气的信息,这里需要传入 location // return 我们这里的返回值是根据location构造出来的一个JSON, 这里设置的固定的,就是模拟接口,或者对接天气网站接口都可 public String getCurrentWeather(String location, String unit) { return "{ \"temperature\": 22, \"unit\": \"celsius\", \"description\": \"晴朗\" }"; } } // 本地有一个函数,将函数信息告诉chatgpt,并告诉chatgpt什么情况需要调用这个函数。由chatgpt判断是否需要调用该函数,如果需要在交互中进行调用。类似于委托机制
第一步,需要告诉GPT我们有哪些函数?也就是这些函数是我们本地定义的 第二步,是在调用GPT的时候带上函数信息,然后让GPT选择是否调用函数 第三步,解析GPT的返回,如果GPT需要调用函数,我们在本地根据GPT返回的参数,调用函数获取结果,在获取结果之后,将结果告诉GPT 通过GPT的函数调用的一个简单的示例 看到通过 GPT函数调用的这种方式,可以将我们本地的一些函数 可以和外部的一些第三方的工具做一个更好的集成 整体的这个模式,就类似于委托的机制 GPT根据我们的自然语言,也就是我们的 Prompt 自行去判断是不是需要调用函数 如果需要调用的话,然后再告诉我们,由我们完成调用 完成调用之后,再将调用的结果返回给它 整个过程是我们和GPT的程序上的密切交互 gptchatjsonclijavaapichatgptunitproxycodecto自然语言scriptaslasostemseotokenparseivaetf自然语言处理openaiprompt描述生成api文档结构化数据库回答问题语言转换open ai语言处理url语言交流