Update the node example as "function_call" is deprecated. (#934)

Co-authored-by: Logan Kilpatrick <23kilpatrick23@gmail.com>
This commit is contained in:
Haomin Liu 2023-12-19 23:29:31 +08:00 committed by GitHub
parent 561b3afd6e
commit 82efc971d1

View File

@ -4,10 +4,6 @@ OpenAI functions enable your app to take action based on user inputs. This means
In this tutorial, you will build an app that uses OpenAI functions along with the latest version of the Node.js SDK. The app runs in the browser, so you only need a code editor and, e.g., VS Code Live Server to follow along locally. Alternatively, write your code directly in the browser via [this code playground at Scrimba.](https://scrimba.com/scrim/c6r3LkU9)
If you prefer watching screencasts over reading, then you can check out [this scrim, which walks through the code line-by-line:](https://scrimba.com/scrim/co0044b2d9b9b7f5bf16e0391)
<ScrimPlayer scrimId="co0044b2d9b9b7f5bf16e0391" />
## What you will build
Our app is a simple agent that helps you find activities in your area.
@ -71,34 +67,41 @@ async function getCurrentWeather(latitude, longitude) {
For OpenAI to understand the purpose of these functions, we need to
describe them using a specific schema. We'll create an array called
`functionDefinitions` that contains one object per function. Each object
will have three keys: `name`, `description`, and `parameters`.
`tools` that contains one object per function. Each object
will have two keys: `type`, `function`, and the `function` key has
three subkeys: `name`, `description`, and `parameters`.
```js
const functionDefinitions = [
const tools = [
{
name: "getCurrentWeather",
description: "Get the current weather in a given location",
parameters: {
type: "object",
properties: {
longitude: {
type: "string",
},
latitude: {
type: "string",
type: "function",
function: {
name: "getCurrentWeather",
description: "Get the current weather in a given location",
parameters: {
type: "object",
properties: {
latitude: {
type: "string",
},
longitude: {
type: "string",
},
},
required: ["longitude", "latitude"],
},
required: ["longitude", "latitude"],
},
}
},
{
name: "getLocation",
description: "Get the user's location based on their IP address",
parameters: {
type: "object",
properties: {},
},
type: "function",
function: {
name: "getLocation",
description: "Get the user's location based on their IP address",
parameters: {
type: "object",
properties: {},
},
}
},
];
```
@ -136,7 +139,7 @@ async function agent(userInput) {
const response = await openai.chat.completions.create({
model: "gpt-4",
messages: messages,
functions: functionDefinitions,
tools: tools,
});
console.log(response);
}
@ -151,9 +154,9 @@ properties:
GPT-4).
- `messages` - The entire history of messages between the user and the
AI up until this point.
- `functions` - A description of the functions our app has access to.
Here, we'll we use the `functionDefinitions` array we created
earlier.
- `tools` - A list of tools the model may call. Currently, only
functions are supported as a tool., we'll we use the `tools` array we
created earlier.
## Running our app with a simple input
@ -177,35 +180,41 @@ to the console like this:
message: {
role: "assistant",
content: null,
function_call: {
name: "getLocation", // The function OpenAI wants us to call
tool_calls: [
id: "call_CBwbo9qoXUn1kTR5pPuv6vR1",
type: "function",
function: {
name: "getLocation",
arguments: "{}"
}
}
]
},
finish_reason: "function_call" // OpenAI wants us to call a function
logprobs: null,
finish_reason: "tool_calls" // OpenAI wants us to call a function
}],
usage: {
prompt_tokens: 134,
completion_tokens: 6,
total_tokens: 140
}
system_fingerprint: null
}
```
This response tells us that we should call one of our functions, as it contains the following key: `finish:_reason: "function_call"`.
This response tells us that we should call one of our functions, as it contains the following key: `finish_reason: "tool_calls"`.
The name of the function can be found in the
`response.choices[0].message.function_call.name` key, which is set to
`response.choices[0].message.tool_calls[0].function.name` key, which is set to
`"getLocation"`.
## Turning the OpenAI response into a function call
Now that we have the name of the function as a string, we'll need to
translate that into a function call. To help us with that, we'll gather
both of our functions in an object called `availableFunctions`:
both of our functions in an object called `availableTools`:
```js
const availableFunctions = {
const availableTools = {
getCurrentWeather,
getLocation,
};
@ -213,15 +222,15 @@ const availableFunctions = {
This is handy because we'll be able to access the `getLocation` function
via bracket notation and the string we got back from OpenAI, like this:
`availableFunctions["getLocation"]`.
`availableTools["getLocation"]`.
```js
const { finish_reason, message } = response.choices[0];
if (finish_reason === "function_call") {
const functionName = message.function_call.name;
const functionToCall = availableFunctions[functionName];
const functionArgs = JSON.parse(message.function_call.arguments);
if (finish_reason === "tool_calls" && message.tool_calls) {
const functionName = message.tool_calls[0].function.name;
const functionToCall = availableTools[functionName];
const functionArgs = JSON.parse(message.tool_calls[0].function.arguments);
const functionArgsArr = Object.values(functionArgs);
const functionResponse = await functionToCall.apply(null, functionArgsArr);
console.log(functionResponse);
@ -229,7 +238,7 @@ if (finish_reason === "function_call") {
```
We're also grabbing ahold of any arguments OpenAI wants us to pass into
the function: `message.function_call.arguments`.
the function: `message.tool_calls[0].function.arguments`.
However, we won't need any arguments for this first function call.
If we run the code again with the same input
@ -273,7 +282,7 @@ simplicity.
At the top of the `agent` function, we'll create a loop that lets us run
the entire procedure up to five times.
If we get back `finish_reason: "function_call"` from GPT, we'll just
If we get back `finish_reason: "tool_calls"` from GPT, we'll just
push the result of the function call to the `messages` array and jump to
the next iteration of the loop, triggering a new request.
@ -285,14 +294,14 @@ for (let i = 0; i < 5; i++) {
const response = await openai.chat.completions.create({
model: "gpt-4",
messages: messages,
functions: functionDefinitions,
tools: tools,
});
const { finish_reason, message } = response.choices[0];
if (finish_reason === "function_call") {
const functionName = message.function_call.name;
const functionToCall = availableFunctions[functionName];
const functionArgs = JSON.parse(message.function_call.arguments);
if (finish_reason === "tool_calls" && message.tool_calls) {
const functionName = message.tool_calls[0].function.name;
const functionToCall = availableTools[functionName];
const functionArgs = JSON.parse(message.tool_calls[0].function.arguments);
const functionArgsArr = Object.values(functionArgs);
const functionResponse = await functionToCall.apply(null, functionArgsArr);
@ -354,8 +363,8 @@ to call the `getCurrentWeather` function with
arguments. This is data it got back from the first function call we did.
```js
{role: "assistant", content: null, function_call: {name: "getLocation", arguments: "{}"}}
{role: "assistant", content: null, function_call: {name: "getCurrentWeather", arguments: " { "longitude": "10.859", "latitude": "59.955" }"}}
{"role":"assistant","content":null,"tool_calls":[{"id":"call_Cn1KH8mtHQ2AMbyNwNJTweEP","type":"function","function":{"name":"getLocation","arguments":"{}"}}]}
{"role":"assistant","content":null,"tool_calls":[{"id":"call_uc1oozJfGTvYEfIzzcsfXfOl","type":"function","function":{"name":"getCurrentWeather","arguments":"{\n\"latitude\": \"10.859\",\n\"longitude\": \"59.955\"\n}"}}]}
```
You've now built an AI agent using OpenAI functions and the Node.js SDK! If you're looking for an extra challenge, consider enhancing this app. For example, you could add a function that fetches up-to-date information on events and activities in the user's location.
@ -386,35 +395,40 @@ async function getCurrentWeather(latitude, longitude) {
return weatherData;
}
const functionDefinitions = [
const tools = [
{
name: "getCurrentWeather",
description:
"Get the current weather in a given location given in latitude and longitude",
parameters: {
type: "object",
properties: {
latitude: {
type: "string",
},
longitude: {
type: "string",
type: "function",
function: {
name: "getCurrentWeather",
description: "Get the current weather in a given location",
parameters: {
type: "object",
properties: {
latitude: {
type: "string",
},
longitude: {
type: "string",
},
},
required: ["longitude", "latitude"],
},
required: ["longitude", "latitude"],
},
}
},
{
name: "getLocation",
description: "Get the user's location based on their IP address",
parameters: {
type: "object",
properties: {},
},
type: "function",
function: {
name: "getLocation",
description: "Get the user's location based on their IP address",
parameters: {
type: "object",
properties: {},
},
}
},
];
const availableFunctions = {
const availableTools = {
getCurrentWeather,
getLocation,
};
@ -436,15 +450,15 @@ async function agent(userInput) {
const response = await openai.chat.completions.create({
model: "gpt-4",
messages: messages,
functions: functionDefinitions,
tools: tools,
});
const { finish_reason, message } = response.choices[0];
if (finish_reason === "function_call") {
const functionName = message.function_call.name;
const functionToCall = availableFunctions[functionName];
const functionArgs = JSON.parse(message.function_call.arguments);
if (finish_reason === "tool_calls" && message.tool_calls) {
const functionName = message.tool_calls[0].function.name;
const functionToCall = availableTools[functionName];
const functionArgs = JSON.parse(message.tool_calls[0].function.arguments);
const functionArgsArr = Object.values(functionArgs);
const functionResponse = await functionToCall.apply(
null,