Function Call 概念
- 關(guān)于 GPT 中API的function參數(shù),提供了一些能力
- 這個(gè)函數(shù)調(diào)用是 Open AI 在2023年的6.13號發(fā)布的新能力
- 根據(jù)它的官方描述, 函數(shù)調(diào)用能力可以讓模型輸出一個(gè)請求調(diào)用函數(shù)的消息
- 其中包含所需調(diào)用函數(shù)的信息,以及調(diào)用函數(shù)時(shí)所需攜帶的參數(shù)的信息
- 這種方式是一種將GPT的能力和外部的工具,外部的API連接起來的新的方式
函數(shù)調(diào)用的機(jī)制
- 那么應(yīng)該如何去使用函數(shù)調(diào)用?
- 首先我們需要去選擇函數(shù)調(diào)用的新模型
- 用戶在構(gòu)造message參數(shù)時(shí)候,需要主動的告訴模型有哪些函數(shù)
- GPT 知道我們有哪些函數(shù)之后,根據(jù)對于自然語言的理解,根據(jù)用戶的輸入
- GPT會自行的判斷何時(shí)需要調(diào)用這些函數(shù),然后會根據(jù)目標(biāo)函數(shù)它的描述生成符合要求的請求的參數(shù)
- 然后返回給我們,我們根據(jù)GPT的信息再去調(diào)用函數(shù)
函數(shù)的作用
- 第一種,進(jìn)行自然語言交流時(shí),通過調(diào)用外部工具回答問題
- 通過這種函數(shù)調(diào)用的能力,我們可以將GPT和第三方的工具去進(jìn)行一個(gè)集成,形成類似于GPT插件的這種模式
- 第二種,如果我們有特殊的對于自然語言處理的邏輯
- 我們可以利用GPT, 將自然語言轉(zhuǎn)換成調(diào)用API時(shí)使用的參數(shù), 或轉(zhuǎn)換成查詢數(shù)據(jù)庫時(shí)所使用的條件等等
- 第三種,我們可以利用這種能力從文本當(dāng)中去提取一些結(jié)構(gòu)化的數(shù)據(jù),這是函數(shù)的一些基礎(chǔ)的作用。
函數(shù)調(diào)用的使用
- 那么我們?nèi)绾稳ナ褂煤瘮?shù)調(diào)用呢?如何在它的聊天API的接口上去添加函數(shù)相關(guān)的這些參數(shù)呢?
- 為了實(shí)現(xiàn)函數(shù)調(diào)用的能力, 在API里面有新的請求的參數(shù)就是function, function call等等, 在官方的API文檔上可以查詢
- 在使用之前,我們先來了解一下函數(shù)調(diào)用的步驟
- 第一步, 當(dāng)我們?nèi)フ{(diào)用函數(shù)的時(shí)候,首先我們需要在請求參數(shù)當(dāng)中向API也就是向GPT去傳遞信息, 我們要告訴GPT, 我們有哪些可以調(diào)用的函數(shù)
- 第二步, 我們根據(jù)GPT的返回, 我們要去進(jìn)行解析, 判斷模型是不是需要調(diào)用函數(shù), 如果不需要,我們則不處理
- 如果需要調(diào)用函數(shù),我們這里要根據(jù)需要調(diào)用的函數(shù),根據(jù)GPT輸入的參數(shù)去進(jìn)行調(diào)用
- 調(diào)用完成之后,得到函數(shù)調(diào)用的結(jié)果
- 最后, 我們再將函數(shù)調(diào)用的結(jié)果添加到GPT的消息列表來告訴GPT
代碼實(shí)現(xiàn)
- 參考前文: https://blog.csdn.net/Tyro_java/article/details/134781021
1 )新增一些實(shí)現(xiàn)類,結(jié)構(gòu)如下
- src
- main
- java
- com.xxx.gpt.client
- entity
- ChatFunction.java
- FunctionCallResult.java
- …
- entity
- com.xxx.gpt.client
- java
- test
- java
- com.xxx.gpt.client.test
- FunctionCallTest.java
- …
- com.xxx.gpt.client.test
- java
- main
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 類中包含:名稱,描述,參數(shù)等等字段
FunctionCallResult.java文章來源:http://www.zghlxwxcb.cn/news/detail-763616.html
package com.xxx.gpt.client.entity;
import lombok.Data;
@Data
public class FunctionCallResult {
String name;
String arguments;
}
- FunctionCallResult 定義了名稱,參數(shù)的字段
FunctionCallTest.java文章來源地址http://www.zghlxwxcb.cn/news/detail-763616.html
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();
}
// 調(diào)用gpt的時(shí)候,帶上函數(shù)信息,讓GPT選擇是否調(diào)用
@Test
public void chat() {
List<ChatFunction> functions = new ArrayList<>();
ChatFunction function = new ChatFunction();
function.setName("getCurrentWeather"); // 設(shè)置函數(shù)信息
function.setDescription("獲取給定位置的當(dāng)前天氣");
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);
// 構(gòu)造 message
Message message = Message.of("上海的天氣怎么樣?");
// 構(gòu)造調(diào)用 api 參數(shù)
ChatCompletion chatCompletion = ChatCompletion.builder()
.model(Model.GPT_3_5_TURBO_16K.getName())
.messages(Arrays.asList(message))
.functions(functions)
.maxTokens(8000)
.temperature(0.9)
.build();
// 調(diào)用
ChatCompletionResponse response = chatGPTClient.chatCompletion(chatCompletion);
ChatChoice choice = response.getChoices().get(0);
Message res = choice.getMessage();
System.out.println(res);
// 基于 finish reason 判斷,如果是 function_call 就需要調(diào)用函數(shù)
if ("function_call".equals(choice.getFinishReason())) {
FunctionCallResult functionCall = res.getFunctionCall();
String functionCallName = functionCall.getName();
// 如果需要調(diào)用的是 getCurrentWeather
if ("getCurrentWeather".equals(functionCallName)) {
String arguments = functionCall.getArguments();
JSONObject jsonObject = JSON.parseObject(arguments);
String location = jsonObject.getString("location");
String unit = jsonObject.getString("unit");
// 得到最終的結(jié)果
String weather = getCurrentWeather(location, unit);
res.setContent("");
// 將結(jié)果 weather 告訴GPT
callWithWeather(weather, res, functions);
}
}
}
// 將結(jié)果傳送給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());
}
// 首先我們添加一個(gè)函數(shù),函數(shù)是獲取天氣的信息,這里需要傳入 location
// return 我們這里的返回值是根據(jù)location構(gòu)造出來的一個(gè)JSON, 這里設(shè)置的固定的,就是模擬接口,或者對接天氣網(wǎng)站接口都可
public String getCurrentWeather(String location, String unit) {
return "{ \"temperature\": 22, \"unit\": \"celsius\", \"description\": \"晴朗\" }";
}
}
// 本地有一個(gè)函數(shù),將函數(shù)信息告訴chatgpt,并告訴chatgpt什么情況需要調(diào)用這個(gè)函數(shù)。由chatgpt判斷是否需要調(diào)用該函數(shù),如果需要在交互中進(jìn)行調(diào)用。類似于委托機(jī)制
- 第一步,需要告訴GPT我們有哪些函數(shù)?也就是這些函數(shù)是我們本地定義的
- 第二步,是在調(diào)用GPT的時(shí)候帶上函數(shù)信息,然后讓GPT選擇是否調(diào)用函數(shù)
- 第三步,解析GPT的返回,如果GPT需要調(diào)用函數(shù),我們在本地根據(jù)GPT返回的參數(shù),調(diào)用函數(shù)獲取結(jié)果,在獲取結(jié)果之后,將結(jié)果告訴GPT
- 通過GPT的函數(shù)調(diào)用的一個(gè)簡單的示例
- 看到通過 GPT函數(shù)調(diào)用的這種方式,可以將我們本地的一些函數(shù)
- 可以和外部的一些第三方的工具做一個(gè)更好的集成
- 整體的這個(gè)模式,就類似于委托的機(jī)制
- GPT根據(jù)我們的自然語言,也就是我們的 Prompt 自行去判斷是不是需要調(diào)用函數(shù)
- 如果需要調(diào)用的話,然后再告訴我們,由我們完成調(diào)用
- 完成調(diào)用之后,再將調(diào)用的結(jié)果返回給它
- 整個(gè)過程是我們和GPT的程序上的密切交互
到了這里,關(guān)于AIGC: 關(guān)于ChatGPT中Function Call的調(diào)用的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!