提示工程(7):构建点餐聊天机器人(Chatbot)

这是我们提示工程(Prompt Engineering)的最后一章,我们来构建一个聊天点餐机器人。

import openai
openai.api_key="Your openai key"

我们写两个辅助函数。
1. 单轮聊天:我们将prompt给大模型。
2. 多轮聊天:我们把聊天的消息串给大模型。

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 
    )
    return response.choices[0].message["content"]


def get_completion_from_messages(messages, model="gpt-3.5-turbo", temperature=0.0):
    response = openai.ChatCompletion. create(
        model = model, 
        messages = messages,
        temperature=temperature, # this is the degree of rand
    )
    return response.choices[0].message[ "content" ]

我们这一系列的文章和示例都常常会用到get_completion()这个函数:
1. 将入参的prompt,我们会封装成一个message。这个message的角色是user,内容是我们的提示prompt;
2. 在调用openai.ChatCompletion函数时,我们把message做为参数初始化了。

除了user这个角色,openai还有一个隐藏的角色system。这个角色是用来告诉大模型要做什么。 \

“系统system”提供高级指令,“用户user”提出查询或提示,“助手assistant”是模型的响应。请见下图分解。

1. 理解上下文

我们给一个聊天的消息串来初始化大模型,然其按之前的风格接着聊下去。这里的温度是0.7,越高的温度,随机性会越高。

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 = 0.7)
print(response)
{
  "role": "assistant",
  "content": "To reach the other side, but lo, the other side was full of jesters and mirth, and the chicken found itself in a most amusing predicament!"
}
To reach the other side, but lo, the other side was full of jesters and mirth, and the chicken found itself in a most amusing predicament!

2. 聊天记忆

大模型只能记得当下一次对话的内容,对之前的内容是没有记忆的。请看下面的示例。

首先我和大模型打个招呼,自称我是Lisa。

messages = [
    {'role':'system', 'content': 'Your are friendly chatbot.'},
    {'role':'user', 'content': 'Hi, my name is Isa'} ]
response = get_completion_from_messages(messages, temperature=0.7)
print(response)
{
  "role": "assistant",
  "content": "Hello Isa! How can I assist you today?"
}
Hello Isa! How can I assist you today?

问大模型我是谁,大模型是不记得的。请见下例。

messages = [
    {'role':'system', 'content': 'Your are friendly chatbot.'},
    {'role':'user', 'content': 'Yes, can you remind me, what is my name?'} ]
response = get_completion_from_messages(messages, temperature=0.7)
print(response)
{
  "role": "assistant",
  "content": "I'm sorry, but as a chatbot, I don't have access to personal information or memory. Therefore, I don't know your name."
}
I'm sorry, but as a chatbot, I don't have access to personal information or memory. Therefore, I don't know your name.

假如我们把上述的聊天消息都一次给大模型,它就会记得你是Lisa.

messages = [
    {'role':'system', 'content': 'Your are friendly chatbot.'},
    {'role':'user', 'content': 'Hi, my name is Isa'},
    {'role':'assistant', 'content': 'Hi Isa! It \'s a nice to meet you.'},
    {'role':'assistant', 'content': 'Is there anything I can hlep you with today?'},
    {'role':'user', 'content': 'Yes, can you remind me, what is my name?'} ]

response = get_completion_from_messages(messages, temperature=0.7)
print(response)
{
  "role": "assistant",
  "content": "Your name is Isa."
}
Your name is Isa.

有了上下文,大模型就会记住Lisa这个名称。

现在我们来创新一个chatbot。
第1个方法collect_messages()是用来收集用户信息。

3.创建聊天机器人

定义消息收集函数用于收集我们的聊天消息。这个函数会从我们下面构建的用户界面中收集消息,奖后将其附加到一个名为上下文的列表中,并在每次调用模型时使用该上下文。同时,模型的响应也会被添加到上下文。

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)

这是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

这是可选择的Topping,右边是价格
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

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!")

# button_conversation.on_click(collect_messages),
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

以下是我们的聊天记录。




现在我们完成了定餐聊天机器人的开发。你也可以用上述方法改变机器人的行为,以适应不同的场景。

Troubleshooting

在调试上面聊天机器人遇到很多奇怪的问题,花了很长时间才调通。总结2个:
1. panel的TextInput控件时常取不到值,即用户输入的内容,时深无法传参到函数。如我输入:”What types of Pizza do you have?”,这句话没有接收到。
解决办法:换成google chrome浏览器(之前我用的是safari浏览器)

  1. 点击chat按钮,交互界面一直在运行但实际上卡住了,也会回运行collect_message()函数。
    解法办法:用”’!python3.11 -m pip install ipywidgets”’重装了ipywidgets就好了。因为Jupyter Notebook运行的环境是python 3.11,而pip install默认是用更新版本的python来安装。所有,要指定版本python3.11再安装一次ipywidgets。
!python3.11 -m pip install panel
!python3.11 -m pip install ipywidgets

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注