在这个笔记本中,您将探索如何利用聊天格式与专门为特定任务或行为定制的聊天机器人进行延长对话。
关于大型语言模型的一个令人兴奋的事情是,你只需付出适度的努力就可以用它来构建一个自定义聊天机器人。ChatGPT,这个网页接口,是你可以通过一个大型语言模型进行对话的一个方式。但是一个酷的事情是,你也可以用一个大型语言模型来建立你的自定义聊天机器人,可能扮演AI客户服务代理人或者餐厅的AI接单员的角色。在这个视频中,你将学习如何自己做到这一点。
我将详细描述OpenAI聊天补全格式的组件,然后你将自己建立一个聊天机器人。那么我们开始吧。首先,我们会像往常一样设置OpenAI Python包。所以像ChatGPT这样的聊天模型实际上是被训练来接受一系列消息作为输入,然后返回一个模型生成的消息作为输出。因此,尽管聊天格式被设计为使这样的多轮对话变得容易,我们在之前的视频中看到,它对于没有任何对话的单轮任务也同样有用。
接下来,我们要定义两个助手函数。这是我们在所有视频中一直在使用的那个,"get_completion"函数。但是如果你仔细看看,我们给出了一个提示,但是在函数内部,我们实际上是把这个提示放入了看起来像某种用户消息的东西里。这是因为ChatGPT模型是一个聊天模型,这意味着它被训练来接受一系列消息作为输入,然后返回一个模型生成的消息作为输出。所以用户消息是输入,然后助手消息是输出。在这个视频中,我们实际上将使用一个不同的助手函数,而不是把一个单一的提示作为输入并得到一个单一的补全,我们将传入一系列的消息,这些消息可以来自各种不同的角色。所以我会描述那些。这里是一系列消息的一个例子,第一条消息是一个系统消息,它提供了一个总体的指示,然后在这条消息之后,用户和助手之间有轮流对话,这将继续进行。如果你曾经使用过ChatGPT,网页接口,那么你的消息就是用户消息,然后ChatGPT的消息就是助手消息。所以系统消息有助于设置助手的行为和角色,并且它作为对话的高级指示。你可以把它想象成在助手的耳边低语,引导它的回应,而用户并不知道系统消息。因此,作为用户,如果你曾经使用过ChatGPT,你可能不知道ChatGPT的系统消息中有什么。系统消息的好处在于,它为你,开发者,提供了一种方式,可以在不让请求本身成为对话的一部分的情况下,构建对话。所以你可以引导助手,并在其耳边低语,引导其回应,而不让用户知道。
那么现在,让我们试着在对话中使用这些信息。所以我们将使用我们新的辅助函数来从信息中获取完成。我们也在使用更高的温度。所以系统消息说,"你是一个说着莎士比亚式语言的助手"。所以这是我们在描述助手应该如何行事。然后第一个用户消息是,"给我讲个笑话"。接下来的是,"为什么鸡要过马路?"然后最后一个用户消息是,"我不知道"。所以如果我们运行这个,回应是 "为了到达另一边"。让我们再试一次。 "为了到达另一边,公正的先生或女士"。这是一个古老而经典的,从未失败过。所以这就是我们的莎士比亚式回应。让我们再试一件事。因为我想让这个助手的消息更明显。所以在这里,让我们来打印整个消息响应。所以为了让这更明显。这个回应是助手的消息。所以角色是助手,然后内容就是消息本身。所以这就是辅助函数里发生的事情。
我们只是在提取消息的内容。 那么现在,让我们做另一个示例。所以这里我们的消息是,系统消息是 "你是一个友好的聊天机器人",第一个用户消息是, "嗨,我的名字是Isa"。我们希望得到第一个用户消息。所以让我们执行这个第一个助手的消息。所以第一条消息是, "你好,Isa!很高兴见到你。我今天怎么能帮助你?" 现在让我们试另一个例子。所以这里我们的消息是系统消息, "你是一个友好的聊天机器人",第一个用户消息是, "是的,你能提醒我我的名字是什么吗?"让我们得到回应。正如你所看到的,模型实际上并不知道我的名字。所以每次与语言模型的对话都是一个单独的交互,这意味着你必须提供所有当前对话中模型需要参考的相关信息。如果你希望模型从中提取,或者引用早期对话的部分,你必须在输入模型的信息中提供早期的交流内容。所以我们将这称为上下文。让我们试试看。所以现在我们已经给模型提供了它需要的上下文,也就是我的名字,在前面的信息中,我们将提问同样的问题,我们将问我的名字是什么。
模型能够回应,因为它在我们输入的消息列表中有所有它需要的上下文。所以现在你要建立自己的聊天机器人。这个聊天机器人将被称为 "OrderBot",我们将自动化收集用户提示和助手回应,以建立这个 "OrderBot"。它将在一个披萨餐厅接收订单,所以首先我们将定义这个辅助函数,它将收集我们的用户消息,这样我们就可以避免手动输入,就像我们在上面所做的那样,这将从一个用户界面收集提示,并将其添加到一个名为 "context"的列表中,然后每次都会用这个上下文调用模型。模型的回应也被添加到上下文中,所以模型的消息被添加到上下文中,用户的消息被添加到上下文中,等等,所以它就变得越来越长。这样模型就有了决定下一步要做什么的信息。所以现在我们将设置并运行这个用户界面来显示 Autobot。所以这就是上下文,它包含了包含菜单的系统消息。
请注意,每次我们调用语言模型,我们都将使用相同的上下文,而且随着时间的推移,上下文在不断积累。 然后让我们执行这个。好的,我会说, "嗨,我想订一份披萨"。助手说,"好的,你想要订哪种披萨呢?我们有意大利辣香肠、奶酪和茄子披萨。"嗯。 "它们多少钱?",很好,我们有价格。我想我想要一个中等大小的茄子披萨。所以你可以想象,我们可以继续这个对话。让我们看看我们在系统消息中放了什么。所以,"你是 Autobot,一个自动化服务,用于收集披萨餐厅的订单。你首先向客户打招呼,然后收集订单,然后询问是否是自取或送货。你等待收集整个订单,然后总结并最后一次确认客户是否想添加其他东西。如果是送货,你可以询问地址。最后,你收集支付。确保明确所有选项、额外的和大小,以从菜单中唯一地识别出物品。你以简短、非常会话式、友好的风格回应。菜单包括。"然后,这里我们有菜单。 所以,让我们回到我们的对话,看看助手是否一直在遵循指示。好的,助手问我们是否想要任何配料,这是我们在系统消息中指定的。所以,我想我们不需要额外的配料。好的, "你还想要点什么吗?"让我们来点水。实际上,还有薯条。小份还是大份?这很好,因为我们在系统消息中要求助手明确额外的和边菜。所以,你明白了,也请随时自己玩玩。
你可以暂停视频,然后继续在你自己的笔记本上运行这个。所以,现在我们可以要求模型创建一个我们可以根据对话发送给订单系统的 JSON 摘要。所以,我们现在正在追加另一个系统消息,这是一个指令,我们说, "创建前面的食品订单的 JSON 摘要。为每项物品分别列出价格。字段应该是 1) 披萨,包括边菜, 2) 配料列表, 3) 饮料列表,和 4) 边菜列表",最后,总价。
你也可以在这里使用用户消息,不一定非得是系统消息。那么,我们来执行这个。注意,在这种情况下,我们使用的是较低的温度,因为对于这种任务,我们希望输出相当稳定。对于一个会话代理,你可能想使用一个更高的温度。然而,在这种情况下,我可能也会使用较低的温度,因为对于一个客户的助手聊天机器人,你可能希望输出更加可预测一些。因此,这里我们有了我们的订单摘要。所以,如果我们想的话,可以将此提交到订单系统。
所以我们已经完成了,你已经建立了你自己的订单聊天机器人。随意定制它,并玩转系统消息以改变聊天机器人的行为,使其扮演具有不同知识的不同角色。
Setup
ini
import os
import openai
from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv()) # read local .env file
openai.api_key = os.getenv('OPENAI_API_KEY')
ini
def get_completion(prompt, model="gpt-3.5-turbo"):
messages = [{"role": "user", "content": prompt}]
response = openai.ChatCompletion.create(
model=model,
messages=messages,
temperature=0, # this is the degree of randomness of the model's output
)
return response.choices[0].message["content"]
def get_completion_from_messages(messages, model="gpt-3.5-turbo", temperature=0):
response = openai.ChatCompletion.create(
model=model,
messages=messages,
temperature=temperature, # this is the degree of randomness of the model's output
)
# print(str(response.choices[0].message))
return response.choices[0].message["content"]
ini
messages = [
{'role':'system', 'content':'You are an assistant that speaks like Shakespeare.'},
{'role':'user', 'content':'tell me a joke'},
{'role':'assistant', 'content':'Why did the chicken cross the road'},
{'role':'user', 'content':'I don't know'} ]
scss
response = get_completion_from_messages(messages, temperature=1)
print(response)
scss
messages = [ {'role':'system', 'content':'You are friendly chatbot.'}, {'role':'user', 'content':'Hi, my name is Isa'} ]
response = get_completion_from_messages(messages, temperature=1)
print(response)
scss
messages = [ {'role':'system', 'content':'You are friendly chatbot.'}, {'role':'user', 'content':'Yes, can you remind me, What is my name?'} ]
response = get_completion_from_messages(messages, temperature=1)
print(response)
scss
messages = [ {'role':'system', 'content':'You are friendly chatbot.'},{'role':'user', 'content':'Hi, my name is Isa'},{'role':'assistant', 'content': "Hi Isa! It's nice to meet you. \
Is there anything I can help you with today?"},{'role':'user', 'content':'Yes, you can remind me, What is my name?'} ]
response = get_completion_from_messages(messages, temperature=1)
print(response)
OrderBot
我们可以自动化收集用户提示和助手响应来构建一个订购机器人。这个订购机器人将在披萨餐厅接受订单。
go
def collect_messages(_):
prompt = inp.value_input
inp.value = ''
context.append({'role':'user', 'content':f"{prompt}"})
response = get_completion_from_messages(context)
context.append({'role':'assistant', 'content':f"{response}"})
panels.append(
pn.Row('User:', pn.pane.Markdown(prompt, width=600)))
panels.append(
pn.Row('Assistant:', pn.pane.Markdown(response, width=600, style={'background-color': '#F6F6F6'})))
return pn.Column(*panels)
ini
import panel as pn # GUI
pn.extension()
panels = [] # collect display
context = [ {'role':'system', 'content':"""
You are OrderBot, an automated service to collect orders for a pizza restaurant. \
You first greet the customer, then collects the order, \
and then asks if it's a pickup or delivery. \
You wait to collect the entire order, then summarize it and check for a final \
time if the customer wants to add anything else. \
If it's a delivery, you ask for an address. \
Finally you collect the payment.\
Make sure to clarify all options, extras and sizes to uniquely \
identify the item from the menu.\
You respond in a short, very conversational friendly style. \
The menu includes \
pepperoni pizza 12.95, 10.00, 7.00 \
cheese pizza 10.95, 9.25, 6.50 \
eggplant pizza 11.95, 9.75, 6.75 \
fries 4.50, 3.50 \
greek salad 7.25 \
Toppings: \
extra cheese 2.00, \
mushrooms 1.50 \
sausage 3.00 \
canadian bacon 3.50 \
AI sauce 1.50 \
peppers 1.00 \
Drinks: \
coke 3.00, 2.00, 1.00 \
sprite 3.00, 2.00, 1.00 \
bottled water 5.00 \
"""} ] # accumulate messages
inp = pn.widgets.TextInput(value="Hi", placeholder='Enter text here...')
button_conversation = pn.widgets.Button(name="Chat!")
interactive_conversation = pn.bind(collect_messages, button_conversation)
dashboard = pn.Column(
inp,
pn.Row(button_conversation),
pn.panel(interactive_conversation, loading_indicator=True, height=300),
)
dashboard
makefile
messages = context.copy()
messages.append(
{'role':'system', 'content':'create a json summary of the previous food order. Itemize the price for each item\
The fields should be 1) pizza, include size 2) list of toppings 3) list of drinks, include size 4) list of sides include size 5)total price '},
)
#The fields should be 1) pizza, price 2) list of toppings 3) list of drinks, include size include price 4) list of sides include size include price, 5)total price '},
response = get_completion_from_messages(messages, temperature=0)
print(response)