想和大家分享一下最近学习的Deeplearning.AI和openai联合打造ChatGPT Prompt Engineering在线课程.以下是我写的关于该课程的前五篇博客:
ChatGPT Prompt Engineering(一)
ChatGPT Prompt Engineering(二)
ChatGPT Prompt Engineering(三)
ChatGPT Prompt Engineering(四)
ChatGPT Prompt Engineering(五)
今天我们来学习第五部分内容:个性化的聊天机器人。
个性化的聊天机器人是指以聊天的模式专门针对特定任务来和用户交流,以完成答疑、解惑、或完成某个特定任务。不过首先我们需要设置通过API来访问ChatGPT的主要代码:
import openaiopenai.api_key ='YOUR_OPENAI_API_KEY'
def get_completion(prompt, model="gpt-3.5-turbo"):messages = [{"role": "user", "content": prompt}]response = openai.ChatCompletion.create(model=model,messages=messages,temperature=0, )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, )return response.choices[0].message["content"]
上面我们定义了两个访问ChatGPT的函数get_completion和get_completion_from_messages这两个函数都使用了ChatGPT的"gpt-3.5-turbo"模型,而get_completion_from_messages比get_completion多了一个入口参数temperature,也就是说get_completion_from_messages允许外面外部调用改函数时修改模型的temperature参数,关于temperature参数的功能我已在上一篇博客中介绍过,这里不再赘述。
“gpt-3.5-turbo”模型与之前的“text-davinci-003”相比在和用户对话的数据结构上有所差异,“gpt-3.5-turbo”模型给对话的双方增加了角色(role), 这里角色会分成3种: system、user、assistant。system和assistant都是ChatGPT自身的角色,user是用户的角色,其中system是ChatGPT的初始角色,用来告知ChatGPT在接下来和用户对话的过程中将扮演什么样的角色,一般我们会这样来定义system角色:“你是一位XXXX,”(如,你是一位律师,你是一位老师,你是一个程序员。。。),assistant和user角色用来保存聊天机器人和用户之间的对话内容。一般情况下为了让ChatGPT能记住对话过程中的上下文,我们会把部分或者全部的对话内容保存在对话的结构体(messages)中,这样ChatGPT就有了记忆上下文的能力。下面我们看一下模拟的ChatGPT的对话结构体:
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'} ]response = get_completion_from_messages(messages, temperature=1)
print(response)
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)
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)
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)
这里我们调用了get_completion_from_messages函数,并传递了对话结构体messages和temperature参数,同时我们将temperature置位1,这告诉ChatGPT可以产生随机性的结果。因此如果我们执行多次get_completion_from_messages函数那么ChatGPT可能会每次产生多种不同的结果的回复。同时我们注意到在最后一次的对话中ChatGPT能记住用户的名字叫Isa, 这是因为在最后一次的messages中存储了用户和ChatGPT的多伦对话,其中也包含了用户的名字,所以最后ChatGPT能记住用户的名字叫 Isa, 而之前的对话ChatGPT无法记住用户的名字,这是因为之前的messages中没有记录用户的名字。
订单机器人
接下来我们要让ChatGPT充当一个订单机器人,用户通过该机器人来订购披萨,而机器人的任务是为一个披萨店来收集用户的订单信息,并回答用户关于订购披萨的相关问题。下面我们看一下messages结构:
def collect_messages(_):prompt = inp.value_inputinp.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)
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 messagesinp = 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
这里的context变量就是ChatGPT与客户对话的结构体,下面把context变量中的"system"角色的内容翻译成中文,以便大家能更好的理解system角色的定义:
context1 = [ {'role':'system', 'content':"""
你是一个订单机器人,这是一项为比萨餐厅收集订单的自动化服务。 \
你先问候客户,然后收集订单,\
然后问是自取还是送货。 \
您等待收集整个订单,然后对其进行汇总并最后检查客户是否还想添加任何其他内容。 \
如果是送货,你索要一个地址。 \
最后你收款了。\
确保阐明所有选项、附加功能和尺寸,以便从菜单中唯一标识该项目。\
你以简短、非常友好的对话方式回应。 \
菜单包括\
意大利辣香肠披萨 12.95, 10.00, 7.00 \
芝士披萨 10.95, 9.25, 6.50 \
茄子披萨 11.95, 9.75, 6.75 \
薯条 4.50, 3.50 \
希腊沙拉 7.25 \
配料:\
额外的奶酪 2.00, \
蘑菇 1.50 \
香肠 3.00 \
加拿大培根 3.50 \
艾酱1.50\
辣椒 1.00 \
饮料:\
可乐 3.00, 2.00, 1.00 \
雪碧 3.00, 2.00, 1.00 \
瓶装水 5.00 \
"""} ] # accumulate messages
在定义system角色时我们首先告知ChatGPT它是一个订单机器人,主要任务是收集订单等待,在向ChatGPT交代了订购披萨的过程和步骤以后,接下来是菜单的内容,这样ChatGPT就可以根据菜单来向顾客推荐不同种类的披萨。下面是我们执行该程序后与订单机器人的聊天内容:
这里我们全程使用中文与ChatGPT进行了对话,虽然我们在定义ChatGPT的system角色时用的全部是英语,ChatGPT仍然可以将英语的菜单内容翻译成中文后再回复给我们,整个对话过程显得得非常专业和流畅。
下面我们把订单信息通过JSON格式输出:
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 '},
)response = get_completion_from_messages(messages, temperature=0)
print(response)
不足之处
这里我们定义的ChatGPT是一个订餐机器人,原则上它不应该回复和订餐无关的任何问题,我尝试了一些和订餐无关的话题,该订餐机器人也能正常回复,这说明我们的system角色定义仍然有改进的空间,应该在system角色定义的时候明确告知ChatGPT不应该回应任何与订餐无关的问题。
尝试改进
在之前的system角色定义中我们没有告诉ChatGPT哪些问题不应该回答,因此该机器人会回答任何与订餐无关的问题,这也就违背了我们初衷。为此我们可以在system角色定义的时候加入一些限制性的话语,通过这些限制性话语我们可以尝试让机器人礼貌的回绝任何与订餐无关的问题,下面我们将在角色定义的时候插入这样的语句:
这句话的意思是:“如果客户的问题与订购披萨无关,那么你就是说:抱歉,我只个订餐机器人,我无法回答任何与订购披萨无关的问题。”
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. \
If the customer's question has nothing to do with ordering pizza or \
ordering food, you say:Sorry, I'm an order bot and I can't answer questions \
not related to ordering pizza.\
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 messagesinp = 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
大体上说我们的改进取得了一定的效果,基本上机器人能够拒绝回答和订餐无关的问题,但我总感觉并不是十分完美,如果想要机器人严格的拒绝回答所有与订餐无关的问题,我们似乎还得教会机器人能够准确识别出客户的问题与订餐事件之间是否存在关系,以及这个关系的强弱。大家对这个问题有什么看法呢?
关于模型参数Temperature
如果模型有多个可选的结果,那么当temperature为0时,将会选择可能性最高的那个结果,如果调高temperature的值,那么就会增加模型挑选结果的随机性,也就是说可能性不高的结果也可能会选中,下面看个例子:
如果我对三种食物的实际喜爱程度分别是:pizza 53%, sushi 30%, tocos 5%, 也就是说我最喜欢的食物是pizza, 最不喜欢的是tacos, 居中的是sushi。当我们选中不同的Temperature时,会得到如下的结果:
当temperature为0时,模型会100%选中pizza, 而当temperature为0.3时,模型会有2/3的概率选中pizza,有1/3的概率选中sushi, 当temperature为0.7时,选中三种食物的概率各位1/3。所以temperature的越大,随机性就越大。这样解释大家能理解temperature的作用了吗?
总结
今天我们学习了如果利用ChatGPT开发一个个性化的聊天机器人,让它能代替人类完成某些特定任务,这其中我们需要详细的定义机器的system角色,以避免机器人回答与任务本身无关的问题。
我们还介绍了模型参数temperature的功能和作业,比如temperature越大,会使模型的输出结果更有随机性。
参考资料
DLAI - Learning Platform Beta