我正在尝试为餐厅创建一个 GPT 聊天机器人,可以询问顾客的联系信息和预订时间。在人工智能聊天机器人确定客户已向其提供所有这些详细信息后,我想运行我认为所谓的“操作”。我基本上想使用另一个 API 向对方发送电子邮件,表示我们将很快与您联系。然而,与此同时,我只想做一个console.log,上面写着“已确认”,这样我就知道人工智能理解它获得了所有详细信息,因此可以继续下一步(只是中间步骤)。然而,我正在努力解决如何从当前的代码转移到实际执行操作的情况,当前的代码只是根据特定的助手与用户聊天。这是我的代码(在后端的 Node 上运行,仅接收来自前端的响应并将其发送回):
const express = require('express');
const { OpenAI } = require('openai');
const cors = require('cors');
require('dotenv').config();
const app = express();
app.use(cors());
app.use(express.json());
const openai = new OpenAI(process.env.OPENAI_API_KEY);
app.post('/get-response', async (req, res) => {
const userMessage = req.body.message;
let threadId = req.body.threadId; // Receive threadId from the client
const assistantId = 'MYASSISTANTID'; // Replace with your actual assistant ID
// If no threadId or it's a new session, create a new thread
if (!threadId) {
const thread = await openai.beta.threads.create();
threadId = thread.id;
}
await openai.beta.threads.messages.create(threadId, {
role: "user",
content: userMessage,
});
// Use runs to wait for the assistant response and then retrieve it
const run = await openai.beta.threads.runs.create(threadId, {
assistant_id: assistantId,
});
let runStatus = await openai.beta.threads.runs.retrieve(
threadId,
run.id
);
// Polling mechanism to see if runStatus is completed
// This should be made more robust.
while (runStatus.status !== "completed") {
await new Promise((resolve) => setTimeout(resolve, 2000));
runStatus = await openai.beta.threads.runs.retrieve(threadId, run.id);
}
// //CHECKING FOR TABLE RESERVATION:
// // If the model output includes a function call
// if (runStatus.status === 'requires_action') {
// // You might receive an array of actions, iterate over it
// for (const action of runStatus.required_action.submit_tool_outputs.tool_calls) {
// const functionName = action.function.name;
// const arguments = JSON.parse(action.function.arguments);
// // Check if the function name matches 'table_reservation'
// if (functionName === 'table_reservation') {
// handleTableReservation(arguments);
// // Respond back to the model that the action has been handled
// await openai.beta.threads.runs.submit_tool_outputs(threadId, run.id, {
// tool_outputs: [{
// tool_call_id: action.id,
// output: { success: true } // You can include more details if needed
// }]
// });
// }
// }
// }
// Get the last assistant message from the messages array
const messages = await openai.beta.threads.messages.list(threadId);
// Find the last message for the current run
const lastMessageForRun = messages.data
.filter(
(message) => message.run_id === run.id && message.role === "assistant"
)
.pop();
// If an assistant message is found, console.log() it
assistantMessage = ""
if (lastMessageForRun) {
assistantMessage = lastMessageForRun.content[0].text.value
console.log(`${assistantMessage} \n`);
}
res.json({ message: assistantMessage, threadId: threadId });
});
const PORT = 3001;
app.listen(PORT, () => console.log(`Server listening on port ${PORT}`));
如果您查看上面的代码,您会意识到我尝试执行我所要求的操作,然后最终将其注释掉,因为它不起作用。
对于进一步的背景,我试图了解操作和工具是如何工作的,因为也许这就是我能够实现我想要做的事情的方式。我想出了以下我认为可能有用的代码(问题是我不知道如何组合这两段代码,并且下面的代码不使用我最终想要使用的助手) :
require('dotenv').config(); // This should be at the top of your file
const { OpenAI } = require('openai');
const openai = new OpenAI(process.env.OPENAI_API_KEY);
// Example dummy function hard coded to return the same weather
// In production, this could be your backend API or an external API
function getCurrentWeather(location) {
if (location.toLowerCase().includes("tokyo")) {
return JSON.stringify({ location: "Tokyo", temperature: "10", unit: "celsius" });
} else if (location.toLowerCase().includes("san francisco")) {
return JSON.stringify({ location: "San Francisco", temperature: "72", unit: "fahrenheit" });
} else if (location.toLowerCase().includes("paris")) {
return JSON.stringify({ location: "Paris", temperature: "22", unit: "fahrenheit" });
} else {
return JSON.stringify({ location, temperature: "unknown" });
}
}
function get_table_reservations(bookingTime, numGuests) {
if (bookingTime.toLowerCase().includes("4:30")) {
return JSON.stringify({ availability: "Not available"});
}
else if (!bookingTime) {
return JSON.stringify({ availability: "Please include a booking time"});
}
else {
return JSON.stringify({ availability: "Available", forGuests: numGuests});
}
}
async function runConversation() {
// Step 1: send the conversation and available functions to the model
const messages = [
{ role: "user", content: "I want a table reservation for 3 people." },
];
const tools = [
{
type: "function",
function: {
name: "get_current_weather",
description: "Get the current weather in a given location",
parameters: {
type: "object",
properties: {
location: {
type: "string",
description: "The city and state, e.g. San Francisco, CA",
},
unit: { type: "string", enum: ["celsius", "fahrenheit"] },
},
required: ["location"],
},
},
},
{
type: "function",
function: {
name: "get_table_reservations",
description: "Tell the user if a table is available for the number of guests and time they request",
parameters: {
type: "object",
properties: {
numGuests: {
type: "integer",
description: "The number of guests",
},
bookingTime: { type: "string", description: "The time requested for a reservation, eg. 8:30 PM" },
},
required: ["numGuests", "bookingTime"],
},
},
},
];
const response = await openai.chat.completions.create({
model: "gpt-3.5-turbo-1106",
messages: messages,
tools: tools,
tool_choice: "auto", // auto is default, but we'll be explicit
});
const responseMessage = response.choices[0].message;
// Step 2: check if the model wanted to call a function
const toolCalls = responseMessage.tool_calls;
if (responseMessage.tool_calls) {
// Step 3: call the function
// Note: the JSON response may not always be valid; be sure to handle errors
const availableFunctions = {
get_current_weather: getCurrentWeather,
get_table_reservations: get_table_reservations
}; // only one function in this example, but you can have multiple
messages.push(responseMessage); // extend conversation with assistant's reply
for (const toolCall of toolCalls) {
const functionName = toolCall.function.name;
const functionToCall = availableFunctions[functionName];
const functionArgs = JSON.parse(toolCall.function.arguments);
console.log('Arguments:', toolCall.function.arguments, 'name:', functionName); // Add this line to debug
const functionResponse = functionToCall(
functionArgs.bookingTime,
functionArgs.numGuests
);
messages.push({
tool_call_id: toolCall.id,
role: "tool",
name: functionName,
content: functionResponse,
}); // extend conversation with function response
}
const secondResponse = await openai.chat.completions.create({
model: "gpt-3.5-turbo-1106",
messages: messages,
}); // get a new response from the model where it can see the function response
return secondResponse.choices;
}
}
runConversation().then(console.log).catch(console.error);
或者,也许有一种更简单的方法可以通过 platform.openai 网站本身的助手页面来完成此操作。也许我需要在下面的屏幕截图中更改/添加一些内容,也许是一个函数。作为一个单独的问题,在助手 API 中添加函数的示例之一是“get_weather”,但我不确定它是如何工作的以及 get_weather 函数将如何运行或需要在哪里定义(也显示在下面的第二张截图)。
此外,如果有人能建议我在弄清楚这一步后如何开始使用电子邮件 API 来开始发送电子邮件,那将是一个很大的帮助(尽管我的问题的这一部分不太重要)
最后(我知道我问了很多问题),出于好奇,有人知道我是否可以用 Gemini 来实现与 GPT 助手所做的相同的事情吗?
使用助手 API。声明一个函数调用工具并描述函数的每个参数和函数。如果您给出函数的准确含义,ChatGPT 将返回调用发送电子邮件的函数所需的信息。对于 Node 或 Python,您不仅可以在 Git 上找到大量库。然后在这里开始学习如何使用助手 API:Assistant API
首先你必须创建一个助手。 Python示例取自OpenAI网站:
from openai import OpenAI
client = OpenAI()
my_assistant = client.beta.assistants.create(
instructions="You are a personal math tutor. When asked a question, write and run Python code to answer the question.",
name="Math Tutor",
tools=[{"type": "code_interpreter"}],
model="gpt-4",
)
print(my_assistant)
这是为了防止您想使用代码解释器,如果您想使用函数调用工具,请使用下面的代码,您必须更改工具数组,如下例所示,使用函数 (get_weather) 来检索天气预报并采用 2 个参数。您必须添加函数和参数的描述,以便让 ChatGPT 知道该函数的作用。它将从描述中了解是否以及何时调用您的函数以及要使用哪些参数,并根据它返回的结果创建答案。
"tools": [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Determine weather in my location",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state e.g. San Francisco, CA"
},
"unit": {
"type": "string",
"enum": [
"c",
"f"
]
}
},
"required": [
"location"
]
}
}
}
],
(函数声明实际上是一个 Josn Schema)您可以向数组添加更多工具。检索通常用于处理传递给 ChatGPT 的文件。
然后使用以下代码片段创建一个代表聊天的线程:
from openai import OpenAI
client = OpenAI()
empty_thread = client.beta.threads.create()
print(empty_thread)
ChatGPT 将返回这样的 Json:
{
"id": "thread_abc123",
"object": "thread",
"created_at": 1699012949,
"metadata": {}
}
现在您有一个绑定到线程(聊天)的助手。您可以选择在创建线程时添加消息,也可以使用添加消息 API 添加消息:
from openai import OpenAI
client = OpenAI()
thread_message = client.beta.threads.messages.create(
"thread_abc123",
role="user",
content="What is the weather in Rome ?",
)
print(thread_message)
现在您有了一个助手和一个线程,您可以处理发送到 ChatGPT 的消息。为此,请创建一个 Runb 对象,如下所示:
from openai import OpenAI
client = OpenAI()
run = client.beta.threads.runs.create(
thread_id="thread_abc123",
assistant_id="asst_abc123"
)
print(run)
您指定从之前的呼叫中收到的线程 ID 和助手 ID。 此时,您将通过首先拨打电话收到答案:
from openai import OpenAI
client = OpenAI()
run_steps = client.beta.threads.runs.steps.list(
thread_id="thread_abc123",
run_id="run_abc123"
)
print(run_steps)
获取运行步骤(ChatGPT 在做什么)。它返回的对象如下所示:
{
"id": "step_abc123",
"object": "thread.run.step",
"created_at": 1699063291,
"run_id": "run_abc123",
"assistant_id": "asst_abc123",
"thread_id": "thread_abc123",
"type": "message_creation",
"status": "completed",
"cancelled_at": null,
"completed_at": 1699063291,
"expired_at": null,
"failed_at": null,
"last_error": null,
"step_details": {
"type": "message_creation",
"message_creation": {
"message_id": "msg_abc123"
}
},
"usage": {
"prompt_tokens": 123,
"completion_tokens": 456,
"total_tokens": 579
}
}
检查状态是否等于“已完成”。完成后,使用类似于以下的代码片段获取消息:
from openai import OpenAI
client = OpenAI()
message = client.beta.threads.messages.retrieve(
message_id="msg_abc123",
thread_id="thread_abc123",
)
print(message)
调用结果将是以下Json:
{
"id": "msg_abc123",
"object": "thread.message",
"created_at": 1699017614,
"thread_id": "thread_abc123",
"role": "user",
"content": [
{
"type": "text",
"text": {
"value": "This is the message from ChatGPT",
"annotations": []
}
}
],
"file_ids": [],
"assistant_id": null,
"run_id": null,
"metadata": {}
}
“内容”片段包含ChatGPT的答案:
"content": [
{
"type": "text",
"text": {
"value": "This is the message from ChatGPT",
"annotations": []
}
}
],
实际上它也可以返回一些注释,但它是一个超出此示例的主题,您可以通过阅读以下链接的 OpenAI 文档来了解它:Assistants API
有任何问题吗?