使用 ChatGPT API 建立對話系統 學習筆記 - 4

2023/07/21閱讀時間約 21 分鐘
這一系列文章其實就是 Andrew Ng 大大與 OpenAI 合作的一門免費課程【Building Systems with the ChatGPT API】的筆記。很建議大家直接看原本的課程影片,內容蠻淺顯易懂的。

在上一篇文章中,我們探討了如何將大型語言模型與我們的外部程式以及資源做整合,進而生成回應訊息。接下來我們通常會對生成的訊息進行做合適性的確認以及是否是合理的回覆的評估。

輸出內容的合適性確認

輸出內容的合適性確認方式,我們仍然選擇使用 OpenAI 的 Moderation API,使用方法如下:
# 這個訊息就是上個章節最後語言模型分成的回覆訊息
final_response_to_customer = f"""
以上是我們店裡的 SmartX Pro 手機和 FotoSnap 單眼相機的資訊。
SmartX Pro 手機擁有6.1吋顯示器、128GB 儲存空間、12MP 雙鏡頭和5G 網路等功能。
FotoSnap 單眼相機則擁有24.2MP 感光元件、1080p 影片、
3 吋 LCD 和可更換鏡頭等功能。
此外,我們店裡還有多款電視產品可供選擇。
CineView 4K 液晶電視擁有55吋顯示器、4K 解析度、HDR 和智慧電視等功能。
CineView 8K 液晶電視則擁有65吋顯示器、8K 解析度、HDR 和智慧電視等功能。
CineView OLED 電視則擁有55吋顯示器、4K 解析度、HDR 和智慧電視等功能。
此外,我們還有 SoundMax 家庭劇院和 SoundMax 音箱等產品,
可以升級您的電視聲光效果。
如果您對這些產品有任何問題或需要更多資訊,請隨時向我們詢問。
"""
response = openai.Moderation.create(
    input=final_response_to_customer
)
moderation_output = response["results"][0]
print(moderation_output)
--- 以下是 api 回覆的內容,通常只需要注意 flagged 是否為 true ---
>> {
   "categories": {
     "harassment": false,
     "harassment/threatening": false,
     "hate": false,
     "hate/threatening": false,
     "self-harm": false,
     "self-harm/instructions": false,
     "self-harm/intent": false,
     "sexual": false,
     "sexual/minors": false,
     "violence": false,
     "violence/graphic": false
   },
   "category_scores": {
     "harassment": 8.845762e-09,
     "harassment/threatening": 2.1843086e-08,
     "hate": 1.0149355e-09,
     "hate/threatening": 6.4688717e-09,
     "self-harm": 2.2744202e-09,
     "self-harm/instructions": 4.1273363e-09,
     "self-harm/intent": 1.8380901e-10,
     "sexual": 1.2166727e-06,
     "sexual/minors": 1.5611114e-08,
     "violence": 1.6215482e-07,
     "violence/graphic": 1.8128114e-08
   },
   "flagged": false
 }

是否解答了使用者詢問的評估

另一個不可忽視的評估環節是判斷回覆的訊息是否真正解答了使用者的疑問。對此,我們將採用一項全新的提示來進行檢視,其具體內容如下:
system_message = f"""
您是一位助理,主要負責評估客戶服務代表的回答是否足夠滿足客戶的問題, \
並且也驗證所有助理引用的產品資訊是否正確。 \
產品資訊以及用戶與客戶服務代表的訊息將以3個反引號(即```)進行區隔。 \
只需用Y或N字母來回應,不需要任何標點符號: \
如果輸出充分地回答了問題,並且回應正確地使用了產品資訊,則回答「Y」; \
否則,則回答「N」。
只輸出單一字母。
"""
customer_message = f"""
告訴我有關SmartX ProPhone和FotoSnap相機的資訊,
就是那款數位單眼相機的。另外也告訴我你們的電視有哪些。
"""
product_information = """
{
     "SmartX ProPhone": {
         "name": "SmartX ProPhone",
         "category": "手機和配件",
         "brand": "SmartX",
         "model_number": "SX-PP10",
         "warranty": "一年",
         "rating": 4.6,
         "features": ["6.1 吋顯示器", "128GB 儲存空間", "12MP 雙鏡頭", "5G 網路"],
         "description": "一款功能強大並具有先進照相功能的智慧手機",
         "price": 899.99
      },
      ... 中間省略 ...
      "FotoSnap 拍立得相機": {
         "name": "FotoSnap 拍立得相機",
         "category": "相機和攝影機",
         "brand": "FotoSnap",
         "model_number": "FS-IC10",
         "warranty": "一年",
         "rating": 4.1,
         "features": ["立即列印", "內建閃光燈", "自拍鏡", "可攜式電池"],
         "description": "用這款有趣和便攜的拍立得相機創造即時回憶。",
         "price": 69.99
     }
}
"""
q_a_pair = f"""
客戶訊息:{customer_message}
產品資訊:{product_information}
客服回覆:{final_response_to_customer}
回覆是否正確地使用了查詢到的資訊?
回覆是否足夠地回答了問題?
輸出 Y 或 N
"""
messages = [
     {'role': 'system', 'content': system_message},
     {'role': 'user', 'content': q_a_pair}
]
response = get_completion_from_messages(messages, max_tokens=1)
print(response)
--- 回覆的訊息 ---
>> Y

整體流程的匯整

最後,我們將所有我們在先前文章中所學習到的ChatGPT應用實作結構集結一起,將所有步驟整合在同一流程,讓所有的過程一目了然。
# 這個程序總和了之前幾個課程中的所有步驟,讓大家可以看到整個 ChatGPT 應用的完整流程
def process_user_message(user_input, all_messages, debug=True):
     delimiter = "```"
     
     # 步驟 1:使用 Moderation API 來檢查輸入是否違反正常使用規則
     response = openai.Moderation.create(input=user_input)
     moderation_output = response["results"][0]
     
     if moderation_output["flagged"]:
         print("步驟 1: 輸入被 Moderation API 檢查出有問題。")
         return "很抱歉, 我們無法處理這訊息"
     if debug: print("步驟 1: 通過訊息適用度檢查。")
      		
     # 步驟 2-1:從使用者的訊息中提取產品類別和產品名稱
     category_and_product_response = utils.find_category_and_product_only(user_input, utils.get_products_and_category())
     #print(f"category_and_product_response: {category_and_product_response}")
      
     # 步驟 2-2:將使用者詢問的產品轉換為產品列表
     category_and_product_list = utils.read_string_to_list(category_and_product_response)
     #print(f"category_and_product_list: {category_and_product_list}")
      
     if debug: print("步驟 2: 提取產品列表。")
      
     # 步驟 3:如果找到產品,則查找它們
     product_information = utils.generate_output_string(category_and_product_list)
     
     if debug:
         print(f"步驟 3: 查詢產品資訊。")
         #print(f"product_information: {product_information}")
      
     # 步驟 4:回答使用者問題
     system_message = f"""
     你是一家大型電子商店的客服助理。\
     以友好和樂於助人的口吻回答,並提供簡潔的答案。\
     請確保向使用者提出相關的後續問題。"""
     messages = [
         {'role': 'system', 'content': system_message},
         {'role': 'user', 'content': f"{delimiter}{user_input}{delimiter}"},
         {'role': 'assistant', 'content': f"Relevant product information:\n{product_information}"}
     ]
      
     final_response = get_completion_from_messages(all_messages + messages)
     if debug:print(f"步驟 4: 生成回應。")
     all_messages = all_messages + messages[1:]
      
     # 步驟 5:將回應再次傳送給 Moderation API 做適用度檢查
     response = openai.Moderation.create(input=final_response)
     moderation_output = response["results"][0]
      
     if moderation_output["flagged"]:
         if debug: print("步驟 5: 回應被 Moderation API 檢查出有問題。")
         return "很抱歉, 我們無法提供這訊息"
      
     if debug: print("步驟 5: 回應通過適用度檢查。")
      
     # 步驟 6:詢問模型回應是否足以回答使用者的問題
     user_message = f"""
     Customer message: {delimiter}{user_input}{delimiter}
     Agent response: {delimiter}{final_response}{delimiter}
     
     是否回應足以回答使用者的問題? (Y/N)
     """
     messages = [
         {'role': 'system', 'content': system_message},
         {'role': 'user', 'content': user_message}
     ]
     evaluation_response = get_completion_from_messages(messages)
      
     if debug:
         print(f"步驟 6: 模型完成回應的評估。")
         #print(f"evaluation_response: {evaluation_response}")
      
     # 步驟 7:如果是(通過評估),則使用此回答;如果不是(無法通過評估),則說將使用者連接到人員
     if "Y" in evaluation_response:   # 使用 "in" 而不是 "==" 來更安全地處理模型輸出變化(例如,"Y." 或 "Yes")
         if debug: print("步驟 7: 模型通過回應的評估。")
         return final_response, all_messages
     else:
         if debug:
             print(f"步驟 7: 模型未通過回應的評估。")
             #print(f"user_input: {user_input}, final_response: {final_response}\n")
         neg_str = "很抱歉, 我們無法提供這訊息,我們將會將您轉接到服務人員。"
         return neg_str, all_messages
 user_input = """
 告訴我有關SmartX ProPhone和FotoSnap相機的資訊,
 就是那款數位單眼相機的。另外也告訴我你們的電視有哪些。
 """
 response,_ = process_user_message(user_input,[])
 print(response)
透過上述流程,我們可以鮮明地掌握每個內部處理步驟,以及最終產出的回覆訊息:
步驟 1: 通過訊息適用度檢查。
步驟 2: 提取產品列表。
步驟 3: 查詢產品資訊。
步驟 4: 生成回應。
步驟 5: 回應通過適用度檢查。
步驟 6: 模型完成回應的評估。
步驟 7: 模型通過回應的評估。
關於SmartX ProPhone和FotoSnap相機的資訊如下:
SmartX ProPhone是一款功能強大並具有先進照相功能的智慧手機。它擁有6.1吋顯示器、128GB儲存空間、12MP雙鏡頭和5G網路。價格為899.99美元。
FotoSnap相機是一款多功能的單眼相機,具有24.2MP感光元件、1080p影片、3吋LCD和可更換鏡頭。價格為599.99美元。
我們的電視產品包括CineView 4K液晶電視、CineView 8K液晶電視和CineView OLED電視。CineView 4K液晶電視擁有55吋顯示器、4K解析度、HDR和智慧電視功能,價格為599.99美元。CineView 8K液晶電視擁有65吋顯示器、8K解析度、HDR和智慧電視功能,價格為2999.99美元。CineView OLED電視擁有55吋顯示器、4K解析度、HDR和智慧電視功能,價格為1499.99美元。
請問您對這些產品有任何特定的問題嗎?
這就是我們的ChatGPT應用程式處理訊息的整體輪廓,除此之外,我們還將說明更多有關回應訊息評估的細節。我們將在這個系列的下一篇文章中與大家分享。

完整程式碼連結

最後,本篇文章的完整程式碼您可以參考以下連結,
為什麼會看到廣告
Ted Chen
Ted Chen
一個近幾年專注於 語言教育 / 自然語言處理 / 大型語言模型應用 的 IT 人 https://www.facebook.com/Chen.Ching.Tai
留言0
查看全部
發表第一個留言支持創作者!