mirror of
https://github.com/openai/openai-cookbook
synced 2024-11-15 18:13:18 +00:00
Update the node example as "function_call" is deprecated. (#934)
Co-authored-by: Logan Kilpatrick <23kilpatrick23@gmail.com>
This commit is contained in:
parent
561b3afd6e
commit
82efc971d1
@ -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)
|
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
|
## What you will build
|
||||||
|
|
||||||
Our app is a simple agent that helps you find activities in your area.
|
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
|
For OpenAI to understand the purpose of these functions, we need to
|
||||||
describe them using a specific schema. We'll create an array called
|
describe them using a specific schema. We'll create an array called
|
||||||
`functionDefinitions` that contains one object per function. Each object
|
`tools` that contains one object per function. Each object
|
||||||
will have three keys: `name`, `description`, and `parameters`.
|
will have two keys: `type`, `function`, and the `function` key has
|
||||||
|
three subkeys: `name`, `description`, and `parameters`.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const functionDefinitions = [
|
const tools = [
|
||||||
{
|
{
|
||||||
|
type: "function",
|
||||||
|
function: {
|
||||||
name: "getCurrentWeather",
|
name: "getCurrentWeather",
|
||||||
description: "Get the current weather in a given location",
|
description: "Get the current weather in a given location",
|
||||||
parameters: {
|
parameters: {
|
||||||
type: "object",
|
type: "object",
|
||||||
properties: {
|
properties: {
|
||||||
longitude: {
|
latitude: {
|
||||||
type: "string",
|
type: "string",
|
||||||
},
|
},
|
||||||
latitude: {
|
longitude: {
|
||||||
type: "string",
|
type: "string",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
required: ["longitude", "latitude"],
|
required: ["longitude", "latitude"],
|
||||||
},
|
},
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
type: "function",
|
||||||
|
function: {
|
||||||
name: "getLocation",
|
name: "getLocation",
|
||||||
description: "Get the user's location based on their IP address",
|
description: "Get the user's location based on their IP address",
|
||||||
parameters: {
|
parameters: {
|
||||||
type: "object",
|
type: "object",
|
||||||
properties: {},
|
properties: {},
|
||||||
},
|
},
|
||||||
|
}
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
```
|
```
|
||||||
@ -136,7 +139,7 @@ async function agent(userInput) {
|
|||||||
const response = await openai.chat.completions.create({
|
const response = await openai.chat.completions.create({
|
||||||
model: "gpt-4",
|
model: "gpt-4",
|
||||||
messages: messages,
|
messages: messages,
|
||||||
functions: functionDefinitions,
|
tools: tools,
|
||||||
});
|
});
|
||||||
console.log(response);
|
console.log(response);
|
||||||
}
|
}
|
||||||
@ -151,9 +154,9 @@ properties:
|
|||||||
GPT-4).
|
GPT-4).
|
||||||
- `messages` - The entire history of messages between the user and the
|
- `messages` - The entire history of messages between the user and the
|
||||||
AI up until this point.
|
AI up until this point.
|
||||||
- `functions` - A description of the functions our app has access to.
|
- `tools` - A list of tools the model may call. Currently, only
|
||||||
Here, we'll we use the `functionDefinitions` array we created
|
functions are supported as a tool., we'll we use the `tools` array we
|
||||||
earlier.
|
created earlier.
|
||||||
|
|
||||||
## Running our app with a simple input
|
## Running our app with a simple input
|
||||||
|
|
||||||
@ -177,35 +180,41 @@ to the console like this:
|
|||||||
message: {
|
message: {
|
||||||
role: "assistant",
|
role: "assistant",
|
||||||
content: null,
|
content: null,
|
||||||
function_call: {
|
tool_calls: [
|
||||||
name: "getLocation", // The function OpenAI wants us to call
|
id: "call_CBwbo9qoXUn1kTR5pPuv6vR1",
|
||||||
|
type: "function",
|
||||||
|
function: {
|
||||||
|
name: "getLocation",
|
||||||
arguments: "{}"
|
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: {
|
usage: {
|
||||||
prompt_tokens: 134,
|
prompt_tokens: 134,
|
||||||
completion_tokens: 6,
|
completion_tokens: 6,
|
||||||
total_tokens: 140
|
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
|
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"`.
|
`"getLocation"`.
|
||||||
|
|
||||||
## Turning the OpenAI response into a function call
|
## Turning the OpenAI response into a function call
|
||||||
|
|
||||||
Now that we have the name of the function as a string, we'll need to
|
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
|
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
|
```js
|
||||||
const availableFunctions = {
|
const availableTools = {
|
||||||
getCurrentWeather,
|
getCurrentWeather,
|
||||||
getLocation,
|
getLocation,
|
||||||
};
|
};
|
||||||
@ -213,15 +222,15 @@ const availableFunctions = {
|
|||||||
|
|
||||||
This is handy because we'll be able to access the `getLocation` function
|
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:
|
via bracket notation and the string we got back from OpenAI, like this:
|
||||||
`availableFunctions["getLocation"]`.
|
`availableTools["getLocation"]`.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const { finish_reason, message } = response.choices[0];
|
const { finish_reason, message } = response.choices[0];
|
||||||
|
|
||||||
if (finish_reason === "function_call") {
|
if (finish_reason === "tool_calls" && message.tool_calls) {
|
||||||
const functionName = message.function_call.name;
|
const functionName = message.tool_calls[0].function.name;
|
||||||
const functionToCall = availableFunctions[functionName];
|
const functionToCall = availableTools[functionName];
|
||||||
const functionArgs = JSON.parse(message.function_call.arguments);
|
const functionArgs = JSON.parse(message.tool_calls[0].function.arguments);
|
||||||
const functionArgsArr = Object.values(functionArgs);
|
const functionArgsArr = Object.values(functionArgs);
|
||||||
const functionResponse = await functionToCall.apply(null, functionArgsArr);
|
const functionResponse = await functionToCall.apply(null, functionArgsArr);
|
||||||
console.log(functionResponse);
|
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
|
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.
|
However, we won't need any arguments for this first function call.
|
||||||
|
|
||||||
If we run the code again with the same input
|
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
|
At the top of the `agent` function, we'll create a loop that lets us run
|
||||||
the entire procedure up to five times.
|
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
|
push the result of the function call to the `messages` array and jump to
|
||||||
the next iteration of the loop, triggering a new request.
|
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({
|
const response = await openai.chat.completions.create({
|
||||||
model: "gpt-4",
|
model: "gpt-4",
|
||||||
messages: messages,
|
messages: messages,
|
||||||
functions: functionDefinitions,
|
tools: tools,
|
||||||
});
|
});
|
||||||
const { finish_reason, message } = response.choices[0];
|
const { finish_reason, message } = response.choices[0];
|
||||||
|
|
||||||
if (finish_reason === "function_call") {
|
if (finish_reason === "tool_calls" && message.tool_calls) {
|
||||||
const functionName = message.function_call.name;
|
const functionName = message.tool_calls[0].function.name;
|
||||||
const functionToCall = availableFunctions[functionName];
|
const functionToCall = availableTools[functionName];
|
||||||
const functionArgs = JSON.parse(message.function_call.arguments);
|
const functionArgs = JSON.parse(message.tool_calls[0].function.arguments);
|
||||||
const functionArgsArr = Object.values(functionArgs);
|
const functionArgsArr = Object.values(functionArgs);
|
||||||
const functionResponse = await functionToCall.apply(null, functionArgsArr);
|
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.
|
arguments. This is data it got back from the first function call we did.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
{role: "assistant", content: null, function_call: {name: "getLocation", arguments: "{}"}}
|
{"role":"assistant","content":null,"tool_calls":[{"id":"call_Cn1KH8mtHQ2AMbyNwNJTweEP","type":"function","function":{"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_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.
|
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,11 +395,12 @@ async function getCurrentWeather(latitude, longitude) {
|
|||||||
return weatherData;
|
return weatherData;
|
||||||
}
|
}
|
||||||
|
|
||||||
const functionDefinitions = [
|
const tools = [
|
||||||
{
|
{
|
||||||
|
type: "function",
|
||||||
|
function: {
|
||||||
name: "getCurrentWeather",
|
name: "getCurrentWeather",
|
||||||
description:
|
description: "Get the current weather in a given location",
|
||||||
"Get the current weather in a given location given in latitude and longitude",
|
|
||||||
parameters: {
|
parameters: {
|
||||||
type: "object",
|
type: "object",
|
||||||
properties: {
|
properties: {
|
||||||
@ -403,18 +413,22 @@ const functionDefinitions = [
|
|||||||
},
|
},
|
||||||
required: ["longitude", "latitude"],
|
required: ["longitude", "latitude"],
|
||||||
},
|
},
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
type: "function",
|
||||||
|
function: {
|
||||||
name: "getLocation",
|
name: "getLocation",
|
||||||
description: "Get the user's location based on their IP address",
|
description: "Get the user's location based on their IP address",
|
||||||
parameters: {
|
parameters: {
|
||||||
type: "object",
|
type: "object",
|
||||||
properties: {},
|
properties: {},
|
||||||
},
|
},
|
||||||
|
}
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const availableFunctions = {
|
const availableTools = {
|
||||||
getCurrentWeather,
|
getCurrentWeather,
|
||||||
getLocation,
|
getLocation,
|
||||||
};
|
};
|
||||||
@ -436,15 +450,15 @@ async function agent(userInput) {
|
|||||||
const response = await openai.chat.completions.create({
|
const response = await openai.chat.completions.create({
|
||||||
model: "gpt-4",
|
model: "gpt-4",
|
||||||
messages: messages,
|
messages: messages,
|
||||||
functions: functionDefinitions,
|
tools: tools,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { finish_reason, message } = response.choices[0];
|
const { finish_reason, message } = response.choices[0];
|
||||||
|
|
||||||
if (finish_reason === "function_call") {
|
if (finish_reason === "tool_calls" && message.tool_calls) {
|
||||||
const functionName = message.function_call.name;
|
const functionName = message.tool_calls[0].function.name;
|
||||||
const functionToCall = availableFunctions[functionName];
|
const functionToCall = availableTools[functionName];
|
||||||
const functionArgs = JSON.parse(message.function_call.arguments);
|
const functionArgs = JSON.parse(message.tool_calls[0].function.arguments);
|
||||||
const functionArgsArr = Object.values(functionArgs);
|
const functionArgsArr = Object.values(functionArgs);
|
||||||
const functionResponse = await functionToCall.apply(
|
const functionResponse = await functionToCall.apply(
|
||||||
null,
|
null,
|
||||||
|
Loading…
Reference in New Issue
Block a user