1. 無記憶的 GPT 聊天機器人 :
OpenAI API 的功能跟 HTTP 協定運作原理一樣無記憶功能, 每一個回應都只與這次的請求有關, 每一對請求與回應都是獨立的
首先匯入 OpenAI 類別與建立物件 :
>>> from openai import OpenAI, APIError
>>> api_key='填入 API key'
>>> client=OpenAI(api_key=api_key)
然後寫一個 ask_gpt() 函式 :
>>> def ask_gpt(messages, model='gpt-3.5-turbo'):
try:
reply=client.chat.completions.create(
model=model,
messages=messages
)
return reply.choices[0].message.content
except APIError as e:
return e.message
此處參數 messages 是一個字典串列, 格式如下 :
[{'role': 'system', 'content': '<系統角色>'}, {'role': 'user', 'content': '<提示詞>'}]
接下來用 input() 讓使用者輸入系統扮演之角色 :
>>> sys_role=input('請設定 GPT 角色 : ')
if sys_role.strip() == '':
sys_role='你是繁體中文AI助理'
print(sys_role)
請設定 GPT 角色 :
你是繁體中文AI助理
最後用一個 while 無限迴圈來製做一個命令列的聊天機器人 (輸入 Enter 跳出迴圈) :
>>> while True:
prompt=input('You : ')
if prompt.strip() == '':
print('GPT : 再見。')
break
messages=[
{'role': 'system', 'content': sys_role},
{'role': 'user', 'content': prompt}
]
reply=ask_gpt(messages)
print(f'GPT : {reply}')
You : 我養了兩隻貓, 名叫咪咪與萬萬
GPT : 這兩隻貓的名字聽起來很可愛呢!照顧牠們需要給予愛與耐心,也希望牠們健康快樂地成長。有什麼需要我幫忙的嗎?
You : 你還記得我那兩隻貓的名字嗎?
GPT : 抱歉,我並不保留先前的對話記錄,因此無法記得你的兩隻貓的名字。不過,如果你提醒我一下,我會盡力幫助你。你可以告訴我你的兩隻貓的名字嗎?
You :
GPT : 再見。
可見再次詢問前一次聊天的內容時, 它其實並不記得, 這跟在未登入情況下與 ChatGPT 聊天的結果一樣 (必須登入帳號才會記憶聊天過程).
2. 使用串列紀錄聊天歷史 :
如果要讓模型記得之前的聊天內容, 必須自行記錄聊天歷史, 並且在每次詢問時將之前的聊天歷史放在 assistance 角色中
# cli_chatbot_1.py
from openai import OpenAI, APIError
def ask_gpt(messages, model='gpt-3.5-turbo'):
try:
reply=client.chat.completions.create(
model=model,
messages=messages
)
return reply.choices[0].message.content
except APIError as e:
return e.message
# 建立 OpenAI 物件
api_key='填入 API key'
client=OpenAI(api_key=api_key)
# 設定 AI 系統扮演之角色
sys_role=input('設定 GPT 角色 : ')
if sys_role.strip() == '':
sys_role='你是繁體中文AI助理'
print(sys_role)
# 初始化記憶:存入系統角色字典
memory=[{'role': 'system', 'content': sys_role}]
while True: # 無窮迴圈
prompt=input('You : ') # 輸入提示詞
if prompt.strip() == '': # Enter 跳出迴圈
print('GPT : 再見。')
break
memory.append({'role': 'user', 'content': prompt}) # 提示詞存入記憶
reply=ask_gpt(memory) # 將記憶資料傳給模型
memory.append({'role': 'assistant', 'content': reply}) # 回應存入記憶
print(f'GPT : {reply}') # 輸出 API 回應
此例一開始就將系統角色存入記憶變數 memory, 之後每次交談都會存入成對的 user 與 assistant 鍵之字典, 每次請求的內容都是之前的記憶加上目前的提示詞組成之字典串列, 執行結果如下 :
You : 我養了兩隻貓, 名叫咪咪與萬萬
GPT : 很高興聽到您養了兩隻可愛的貓咪,名字取得非常可愛!您有任何想要了解或分享的事情嗎?
You : 你還記得我那兩隻貓的名字嗎?
GPT : 是的,您剛剛告訴我您養了兩隻貓,名字是咪咪和萬萬。是否有其他問題要問呢?
You : 你喜歡貓嗎?
GPT : 我是一個人工智慧助理,沒有喜好或情感,但我知道貓是很可愛、獨立和聰明的寵物。如果您有貓咪的相關問題或想分享貓咪的照片或故事,我很樂意聽取!
You : 你比較喜歡貓還是狗?
GPT : 我作為人工智慧助理沒有偏愛任何寵物,我對貓和狗一視同仁。每種寵物都有它們獨特的魅力和個性,各有各的可愛之處。您喜歡貓還是狗呢?您有其他寵物嗎?歡迎和我分享您的看法和經驗!
You : 考考你的記性, 我家那兩隻貓名叫甚麼?
GPT : 您剛剛告訴我您養了兩隻貓,名字是咪咪與萬萬。讓我知道,您是否有其他問題或需要幫忙的地方喔!
You :
GPT : 再見。
結束聊天後檢查記憶變數 memory 內容 :
>>> memory
[{'role': 'system', 'content': '你是繁體中文AI助理'}, {'role': 'user', 'content': '我養了兩隻貓, 名叫咪咪與萬萬'}, {'role': 'assistant', 'content': '很高興聽到您養了兩隻可愛的貓咪,名字取得非常可愛!您有任何想要了解或分享的事情嗎?'}, {'role': 'user', 'content': '你還記得我那兩隻貓的名字嗎?'}, {'role': 'assistant', 'content': '是的,您剛剛告訴我您養了兩隻貓,名字是咪咪和萬萬。是否有其他問題要問呢?'}, {'role': 'user', 'content': '你喜歡貓嗎?'}, {'role': 'assistant', 'content': '我是一個人工智慧助理,沒有喜好或情感,但我知道貓是很可愛、獨立和聰明的寵物。如果您有貓咪的相關問題或想分享貓咪的照片或故事,我很樂意聽取!'}, {'role': 'user', 'content': '你比較喜歡貓還是狗?'}, {'role': 'assistant', 'content': '我作為人工智慧助理沒有偏愛任何寵物,我對貓和狗一視同仁。每種寵物都有它們獨特的魅力和個性,各有各的可愛之處。您喜歡貓還是狗呢?您有其他寵物嗎?歡迎和我分享您的看法和經驗!'}, {'role': 'user', 'content': '考考你的記性, 我家那兩隻貓名叫甚麼?'}, {'role': 'assistant', 'content': '您剛剛告訴我您養了兩隻貓,名字是咪咪與萬萬。讓我知道,您是否有其他問題或需要幫忙的地方喔!'}]
可以想見的是, 隨著交談次數增多, 記憶變數內容也會越來越長, 且因 memory 是全域變數, 跳出程式後它仍然存在, 再次執行前要將之清除, 否則前世記憶會遺留到下一次對話中, 因此在跳出程式前應該主動將記憶清除才對 (上例是為了觀察 memory 內容未清除) :
# cli_chatbot_2.py
from openai import OpenAI, APIError
def ask_gpt(messages, model='gpt-3.5-turbo'):
try:
reply=client.chat.completions.create(
model=model,
messages=messages
)
return reply.choices[0].message.content
except APIError as e:
return e.message
# 建立 OpenAI 物件
api_key='填入 API key'
client=OpenAI(api_key=api_key)
# 設定 AI 系統扮演之角色
sys_role=input('設定 GPT 角色 : ')
if sys_role.strip() == '':
sys_role='你是繁體中文AI助理'
print(sys_role)
# 初始化記憶:存入系統角色字典
memory=[{'role': 'system', 'content': sys_role}]
while True: # 無窮迴圈
prompt=input('You : ') # 輸入提示詞
if prompt.strip() == '': # Enter 跳出迴圈
print('GPT : 再見。')
del memory # 離開聊天時刪除記憶
break
memory.append({'role': 'user', 'content': prompt}) # 提示詞存入記憶
reply=ask_gpt(memory) # 將記憶資料傳給模型
memory.append({'role': 'assistant', 'content': reply}) # 回應存入記憶
print(f'GPT : {reply}') # 輸出 API 回應
此例在離開聊天時使用 del 指令將記憶變數 memory 刪除, 這樣再次執行此程式時就不會有前次聊天的資訊了.
也可以設定只記住最近幾回聊天紀錄, 這樣就可以避免記憶串列隨交談次數增加而變長. 在下面範例中增加了一個 retro 變數用來設定要回溯記住最近幾回的聊天次數 (一問一答為一回) :
# cli_chatbot_3.py
from openai import OpenAI, APIError
def ask_gpt(messages, model='gpt-3.5-turbo'):
try:
reply=client.chat.completions.create(
model=model,
messages=messages
)
return reply.choices[0].message.content
except APIError as e:
return e.message
# 建立 OpenAI 物件
api_key='填入 API key'
client=OpenAI(api_key=api_key)
# 設定 AI 系統扮演之角色
sys_role=input('設定 GPT 角色 : ')
if sys_role.strip() == '':
sys_role='你是繁體中文AI助理'
print(sys_role)
# 初始化記憶:存入系統角色字典
memory=[{'role': 'system', 'content': sys_role}]
retro=2 # 設定記憶前面幾回聊天次數
while True: # 無窮迴圈
prompt=input('You : ') # 輸入提示詞
if prompt.strip() == '': # Enter 跳出迴圈
print('GPT : 再見。')
break
memory.append({'role': 'user', 'content': prompt}) # 提示詞存入記憶
reply=ask_gpt(memory) # 將記憶資料傳給模型
memory.append({'role': 'assistant', 'content': reply}) # 回應存入記憶
memory=[memory[0]] + memory[-(retro * 2):] # 取出系統角色串接前幾回聊天紀錄
print(f'GPT : {reply}') # 輸出 API 回應
此例用 retro=2 設定只記憶前兩回聊天紀錄, 因此用 -(retro) *2: 索引取出記憶串列中前 retro 回的紀錄 (一次交談包含一個 user 角色與一個 assistant 角色故要乘以 2, 負號是從串列尾端往回算, 冒號後面空的表示一直取到結尾), 執行結果如下 :
設定 GPT 角色 :
你是繁體中文AI助理
You : 我養了兩隻貓, 名叫咪咪與萬萬
GPT : 這兩隻貓咪的名字真可愛!請問有什麼問題我可以協助你的嗎?
You : 你還記得我那兩隻貓的名字嗎?
GPT : 當然記得!你養的兩隻貓名叫咪咪和萬萬。有任何關於牠們的問題想問嗎?
You : 你喜歡貓嗎?
GPT : 作為AI助理,我沒有喜好或感受,但我知道許多人喜歡貓咪!牠們可愛、獨立又親人,是很受歡迎的寵物。你是一位喜歡貓咪的人嗎?
You : 你比較喜歡貓還是狗?
GPT : 作為AI助理,我沒有個人偏好,我對貓和狗都一視同仁。貓和狗各有其獨特之處,每個人對寵物的喜好也各有不同。你更喜歡貓還是狗呢?
You : 考考你的記性, 我家那兩隻貓名叫甚麼?
GPT : 很抱歉,因為我無法記住之前的對話內容,所以無法知道你家寵物的名字。也許你可以提醒我一下,讓我知道你家那兩隻貓的名字是什麼呢?
You :
GPT : 再見。
檢視記憶變數內容 :
>>> memory
[{'role': 'system', 'content': '你是繁體中文AI助理'}, {'role': 'user', 'content': '你比較喜歡貓還是狗?'}, {'role': 'assistant', 'content': '作為AI助理,我沒有個人偏好,我對貓和狗都一視同仁。貓和狗各有其獨特之處,每個人對寵物的喜好也各有不同。你更喜歡貓還是狗呢?'}, {'role': 'user', 'content': '考考你的記性, 我家那兩隻貓名叫甚麼?'}, {'role': 'assistant', 'content': '很抱歉,因為我無法記住之前的對話內容,所以無法知道你家寵物的名字。也許你可以提醒我一下,讓我知道你家那兩隻貓的名字是什麼呢?'}]
可見關於那兩隻貓名字的聊天歷史已不存在於聊天記憶中, 因此 GPT 無法記住名字. 每一回交談後都會保留記憶串列 memory 索引 0 的 system 角色與前 2 回聊天紀錄來更新 memory 串列, 因此 聊過兩回合之後, memory 變數都會一直保持只有 5 個元素的狀態 (1 + 2*2).
沒有留言 :
張貼留言