(done) 吴恩达版提示词工程 8. 聊天机器人 (聊天格式设计,上下文内容,点餐机器人)

视频:https://www.bilibili.com/video/BV1Z14y1Z7LJ/?spm_id_from=333.337.search-card.all.click\&vd_source=7a1a0bc74158c6993c7355c5490fc600

别人的笔记:https://zhuanlan.zhihu.com/p/626966526


8. 聊天机器人(Chatbot)

关于大型语言模型的一个令人兴奋的事情是,你只需花费少量的精力,就可以使用它来构建自定义的聊天机器人。

ChatGPT 的 Web 界面,是一种使用大型语言模型进行聊天的对话界面。但一个很酷的事情是,你也可以使用大型语言模型来构建你的自定义聊天机器人,可以扮演一个 AI 客服代理或餐厅的 AI 订单员的角色。在这个视频中,你将学习如何来做聊天机器人。

我将更详细地描述 OpenAI 的聊天完成(Chat Completions)格式,然后你将自己构建一个聊天机器人。

8.1 聊天格式的设计

让我们开始吧。首先,我们将像往常一样设置 OpenAI Python 包。

ChatGPT 这样的聊天模型,实际上被训练成将一系列消息作为输入,并返回模型生成的消息作为输出。因此,尽管聊天格式的设计是为了使这样的多轮对话变得容易而设计的,但我们在之前的视频中已经看到,它对于没有对话的单回合任务也同样有效。

接下来,我们将定义两个辅助函数。

python 复制代码
import openai
import os
from openai import OpenAI

# 1. 根据环境变量获取 openai key
from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv())

openai.api_key = os.getenv('OPENAI_API_KEY') 

client = OpenAI()

def get_completion(prompt, model="gpt-3.5-turbo", temperature=0):
    messages = [{"role": "user", "content": prompt}]
    response = client.chat.completions.create(
        model=model,
        messages=messages,
        temperature=temperature, # 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 = client.chat.completions.create(
    model=model,
    messages=messages,
    temperature=temperature, # this is the degree of randomness of the model's output
    )
    return response.choices[0].message.content

一个就是我们在视频中一直使用的 get_completion 函数。但看一下,我们给出了一个提示,在这个函数内部,我们实际是将这个提示放入看起来像某种用户消息的内容中。这是因为 ChatGPT 模型是一个聊天模型,这意味着它被训练成接受一系列消息作为输入,然后返回模型生成的消息作为输出。所以用户消息是一种输入,然后助理(模型)的消息是输出。

在这个视频中,我们将使用一个不同的辅助函数,而不是将单个的提示作为输入,并获得单个的输出结果。我们将传递一个消息列表,这些消息可以来自各种不同的角色。

下面我来描述一下。这里有一个消息列表的例子。第一条消息是系统消息,它给出了一个总体指令,然后在这条消息之后,我们在用户和助理之间有几轮对话,这种对话通常会继续下去。

python 复制代码
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'} ] 

如果你曾经使用过 ChatGPT 的 Web 界面,那么你输入的内容就是用户消息,然后 ChatGPT 输出的内容就是助理消息。

系统消息有助于在某种程度上设置助理的行为和角色,它充当了对话的高级指令。因此,你可以将其视为在助理耳边窃窃私语,并引导它的响应,而用户并不知道系统的消息。所以,作为用户,如果你曾经使用过 ChatGPT,你可能不知道 ChatGPT 的系统消息中有什么,这正是我们的意图。

系统消息的好处是,它为开发人员提供了一种构建对话框架的方法,而无需将请求本身作为对话的一部分。因此,你可以悄悄地引导助理,指导模型的回复,而不让用户意识到。

现在让我们试着在对话中使用这些消息。我们将使用新的辅助函数,从消息中获取完成情况。我们将使用更高的温度值。

python 复制代码
response = get_completion_from_messages(messages, temperature=1)
print(response) 

系统消息说,你是一个说话像莎士比亚的助理,这是我们向助手描述它应该如何表现。然后第一条用户消息是,给我讲个笑话。然后下一个问题是,鸡为什么过马路?最后的用户信息是,我不知道。

如果我们运行这个程序,系统的响应是:"去另一边"。

to get to the other side!

我们再来一次。这次的输出是:"去另一边,公平的先生/夫人,这是一个古老而经典的方法,永远不会失败。" 这就是我们莎士比亚式的回应。

To get to the other side, fair sir/madam! 'Tis an olden classic that never fails.

让我们再试一次。我想让它更清楚,让我们打印整个消息响应。

{ "content": "To get to the other side! Oh, that one always gets me.", "role": "assistant" } To get to the other side! Oh, that one always gets me.

为了更清楚,这个响应是一个助理消息,角色是助理,内容是消息本身。这就是这个辅助函数中发生的事情。我们只是传递了消息的内容。

8.2 上下文内容

现在,让我们再举一个例子。

这里我们的消息是,系统消息是"你是一个友好的聊天机器人",第一条用户消息是,"嗨,我的名字是 Isa"。我们想获得第一条用户信息,所以,让我们执行第一条助理消息。

python 复制代码
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) 

第一条消息是,""你好 Isa,很高兴认识你。今天我可以帮助的吗?"

{ "content": "Hello Isa! It is nice to meet you. How can I assist you today?", "role": "assistant" } Hello Isa! It is nice to meet you. How can I assist you today?

让我们再试试另一个例子。

这里我们的消息是,系统消息是,"你是一个友好的聊天机器人",第一条用户消息是,"是的,你能提醒我的名字是什么吗?"。

python 复制代码
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) 

让我们得到输出响应。

I'm sorry, but as an AI language model, I do not have access to information about your personal details like your name or any other kind of personal information. However, I am here to assist you with any general queries or have a friendly conversation.

正如你所看到的,模型实际上并不知道我的名字。因此,与语言模型的每次对话都是一次独立的交互,这意味着你必须提供所有相关的信息,以便模型在当前对话中使用。

如果你想让模型从前期的对话中引用内容,或者记住前期的对话内容,你就必须在模型的输入中提供前期的交流内容。我们将把这称为上下文。让我们试试这个。

python 复制代码
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) 

现在我们已经给出了模型需要的上下文。嗯,这是我在之前的消息中的名字,我们会问同样的问题,会问"我的名字是什么"。

Your name is Isa.

模型能够作出响应,因为它在我们输入的消息列表中,拥有所有上下文内容。

所以现在你要建立自己的聊天机器人了。

8.3 点餐机器人(OrderBot)

这个聊天机器人被称为 OrderBot(点餐机器人)。

为了构建这个 OrderBot,我们将自动收集用户的提示和助理的响应。它将在披萨店接受订单,所以首先我们将定义这个辅助函数。辅助函数将收集我们的用户信息,这样我们就不需要像上面那样手工输入信息。这将从下面建立的用户界面中收集提示,然后将其追加到一个称为"上下文(context)"的列表中,然后它每次都会调用这个带有上下文的模型。然后模型响应也会被添加到上下文中,所以模型消息的被添加到上下文中,用户消息也被添加到上下文中,以此类推,所以它越来越长。通过这种方式,模型就获得了它所需要的信息来决定下一步要做什么。

python 复制代码
import panel as pn # GUI

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, styles={'background-color': '#F6F6F6'})))

    return pn.Column(*panels) 

现在我们将设置并运行这个用户界面(UI)来显示订单机器人。这里是上下文,它包含了包括菜单的系统消息。请注意,每次我们调用语言模型时,我们都会使用相同的上下文,并且这个上下文会随着时间的推移而不断构建。

python 复制代码
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 

上面的代码用 WSL-vscode-jupyter 是无法运行的,需要在 windows 安装 anaconda 配置 jupyter notebook 才行。具体参考这两篇博客:【windows anaconda 配置 ipynb 环境】 和 【windows anaconda jupyter notebook 怎么才能开飞机?】

大概的样子如下:通过 UI 和点餐机器人交互:

我说:嗨,我想点一份披萨。

助理说:太好了,你想点什么披萨?我们有意大利香肠、奶酪和茄子披萨。

我说:它们多少钱?

助理:(各种比萨的价格)

太好了,助理告诉了我们比萨的价格。我想我觉得可以点中号的茄子披萨。所以,正如你所能想象的,我们可以继续这个对话。

让我们看看我们在系统消息中放了什么。

你是订单机器人,为一家披萨店收集订单的自动化服务,你首先要问候顾客,然后接受订单,然后问是自取还是配送。你等待收集整个订单,然后进行汇总,最后检查客户是否还想添加其他东西。如果是配送,你可以询问配送地址。最后,你收到付款,确保清晰地描述所有选项、附加服务、额外费用和尺寸,以便从菜单中精确地识别项目。你以简短的、健谈的、友好的风格来回答客户。系统信息还包括菜单,这里我们有全部的菜单。

让我们回到我们的对话中,看看助理是否一直在遵循指示。

很好,助理问我们是否需要配料,我们在系统信息中指定了这一点。我回答我们不需要额外的配料。

当然可以。还有什么想要点的吗?嗯,我来点水。事实上,我输入的是薯条。

小份还是大份?很好,因为我们在系统消息中要求助理说明额外配料。

这样你就明白了,你可以随意自己玩这个过程。你可以暂停视频,在左边的 Notebook 上运行这个点餐机器人。

现在我们可以要求模型创建一个 JSON 摘要,可以在对话的基础上生成订单,将其发送到订单系统。所以我们现在要加上另一条系统消息,这是一条指令,要求创建一个关于以上对话中食物订单的 JSON 摘要,逐项列出每种食物的价格,字段应该是一个披萨,包括配菜,两张配料列表,三张饮料列表,四个面列表,最后是总价格。你也可以在这里使用用户消息,这不一定是系统消息。

python 复制代码
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) 

让我们来执行一下。

注意,在这种情况下,我们使用较低的温度参数。因为对于这些类型的任务,我们希望输出是相当可预测的。对于一个对话式助理,你可能希望使用更高的温度值。但对这种点餐机器人,我会使用较低的温度值,因为对于客户助理聊天机器人来说,我们希望输出是更加可预测的。

于是,这里我们得到订单的摘要。如果需要,我们可以将其提交给订单系统。这就是我们所需要的。

Sure, here's a JSON summary of the order:

json 复制代码
{
 "pizza": [
 {
 "type": "pepperoni",
 "size": "large",
 "price": 12.95
 },
 {
 "type": "cheese",
 "size": "medium",
 "price": 9.25
 }
 ],
 "toppings": [
 {
 "type": "extra cheese",
 "price": 2.00
 },
 {
 "type": "mushrooms",
 "price": 1.50
 }
 ],
 "drinks": [
 {
 "type": "coke",
 "size": "large",
 "price": 3.00
 },
 {
 "type": "sprite",
 "size": "small",
 "price": 2.00
 }
 ],
 "sides": [
 {
 "type": "fries",
 "size": "large",
 "price": 4.50
 }
 ],
 "total_price": 35.20
}

好的,现在你已经建立了自己的点餐聊天机器人。

你可以自行地定制,可以使用系统消息来改变聊天机器人的行为,让它扮演具有不同知识的不同角色。

相关推荐
信息快讯4 分钟前
【机器学习驱动的智能化电池管理技术与应用】
人工智能·机器学习
进来有惊喜16 分钟前
循环神经网络RNN---LSTM
人工智能·rnn·深度学习
Chrome深度玩家17 分钟前
如何下载Google Chrome适用于AI语音交互的特制版
前端·人工智能·chrome
Xiaoxiaoxiao020917 分钟前
GAEA情感坐标背后的技术原理
人工智能·web3·区块链
敲敲敲-敲代码21 分钟前
【PyCharm- Python- ArcGIS】:安装一个和 ArcGIS 不冲突的独立 Python让PyCharm 使用 (解决全过程记录)
python·arcgis·pycharm
崔高杰25 分钟前
On the Biology of a Large Language Model——Claude团队的模型理解文章【论文阅读笔记】其一CLT与LLM知识推理
论文阅读·人工智能·笔记·语言模型·自然语言处理
猿榜编程40 分钟前
python基础-requests结合AI实现自动化数据抓取
开发语言·python·自动化
一键三联啊1 小时前
【FastJSON】的parse与parseObject
linux·前端·python
ICT_SOLIDWORKS1 小时前
智诚科技苏州SOLIDWORKS授权代理商的卓越之选
大数据·人工智能·科技·软件工程
新知图书1 小时前
OpenCV彩色图像分割
人工智能·opencv·计算机视觉