使用 ChatGPT API 建立系統 學習筆記 - 3

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

整合提示

在上一篇文章中,我們實際展示了「思考鏈」概念在實作過程中的運用。接著,我們將更進一步地示範如何將大型語言模型(LLM)與我們的其他程式碼進行深度整合。我們將以一個3C賣場的客服助理為例,展示如何在收到使用者訊息後提取出有助於我們進一步處理的提示(prompt),再將提取出的產品資訊與後端的產品資料庫結合,最後將整合後的完整資訊回傳給LLM,由LLM產生出最終的回應訊息。

使用者訊息的解析

接下來的範例中,我們將進一步分析客戶的詢問,並提供一份簡化的產品清單來限縮語言模型回答的範疇,最後會要求語言模型產生一份我們可以直接使用的Python物件列表。
delimiter = "####"
system_message = """
1. 你將會收到一些客戶服務查詢。客戶服務查詢將由 {delimiter} 字元作為分隔符。
2. 如果客戶訊息中的產品在下方允許產品清單中,你就輸出一個Python物件列表,
每個物件同時具有以下格式: 
'category': <以下其中一項:電腦和筆記本,手機和配件,電視和家庭劇院系統,
遊戲機和配件,音響設備,相機和攝影機> 
'products': <必須在以下列出的允許產品中找到的產品列表>
3. 客戶提到下方允許產品清單中的產品時,也同時在在物件屬性列出它對應的類別。
4. 如果客戶沒有特別提到什麼產品,你只要列出類別就好。
5. 如果客戶訊息中的產品不在下方允許產品清單中,你就輸出一個空列表。
6. 如果產品屬性是空的,也不要輸出類別屬性,直接輸出空列表。
允許的產品:
電腦和筆記型電腦類別:
TechPro Ultrabook
BlueWave 電競筆電
PowerLite 二合一電腦
TechPro 桌機
BlueWave Chromebook
... 中間省略 ...
相機和攝影機類別:
FotoSnap 單眼相機
ActionCam 4K 攝影機
FotoSnap 無反光鏡相機
ZoomMaster 攝影機
FotoSnap 拍立得相機
你只可以輸出Python物件列表,不能輸出其他任何資訊。
"""
使用者訊息的處理範例如下:
user_message_1 = f"""
請跟我介紹 SmartX ProPhone 和 FotoSnap 單眼相機, \
也順便告訴我你們是否有電視。 
"""  
# 中文版本的 prompt 如果沒有加上下方的 in-context learning 範例,
#GPT 的回應會莫名自己加上【回應: 】字樣。 
# 課程中的英文版本則不會。
in_context_user1 = "你們有賣 ProGamer 方向盤 嗎?"
in_context_assistant1 = [
{'category': '遊戲機和配件', 'products': 'ProGamer 方向盤'}]
in_context_user2 = "我正在找某個音響。"
in_context_assistant2 = [{'category': '音響設備'}]
messages =  [
  {'role':'system',
   'content': system_message},
  {'role':'user',
   'content': f"{delimiter}{in_context_user1}{delimiter}"},
  {'role':'assistant',
   'content': f"{in_context_assistant1}"},
  {'role':'user',
   'content': f"{delimiter}{in_context_user2}{delimiter}"},
  {'role':'assistant',
   'content': f"{in_context_assistant2}"},
  {'role':'user',
   'content': f"{delimiter}{user_message_1}{delimiter}"},
]
category_and_product_response_1 = get_completion_from_messages(messages)
print(category_and_product_response_1)
--- 以下是 LLm 的回覆 ---
[{'category': '手機和配件', 'products': ['SmartX ProPhone']},
 {'category': '相機和攝影機', 'products': ['FotoSnap 單眼相機']},
 {'category': '電視和家庭劇院系統', 'products': ['CineView 4K 液晶電視',
 'CineView 8K 液晶電視', 'CineView OLED 電視', 'SoundMax 家庭劇院']}]
在以上提示作業英翻中的過程中,我們遇到了一些小插曲。在我們將提示中文化後發現,ChatGPT對於中文的理解和處理相對於英文存在明顯的落差,這使得ChatGPT對中文提示的理解不如預期。因此,我們最後不僅重新修改了提示,還在傳入LLM的訊息中加入了in-context learning,這才讓LLM能夠按照我們的期待來處理訊息。

對於這部分,當大家在設計中文提示時,可能需要特別留意。

詳細資訊的取得

接下來我們將使用Python的dictionary物件來模擬一個小型資料庫,並從中提取詳細的資訊。具體的程式碼如下:
# 產品資訊
products = {
    "TechPro Ultrabook": {
        "name": "TechPro Ultrabook",
        "category": "電腦與筆記型電腦",
        "brand": "TechPro",
        "model_number": "TP-UB100",
        "warranty": "一年",
        "rating": 4.5,
        "features": ["13.3 吋顯示器", "8GB 記憶體", "256GB SSD硬碟", \
                     "Intel Core i5 處理器"],
        "description": "一款適合日常使用的輕薄 Ultrabook。",
        "price": 799.99     },
... 中間省略 ...
    "FotoSnap 拍立得相機": {
        "name": "FotoSnap 拍立得相機",
        "category": "相機和攝影機",
        "brand": "FotoSnap",
        "model_number": "FS-IC10",
        "warranty": "一年",
        "rating": 4.1,
        "features": ["立即列印", "內建閃光燈", "自拍鏡", "可攜式電池"],
        "description": "用這款有趣和便攜的拍立得相機創造即時回憶。",
        "price": 69.99     } 
}
以下則是一些資料提取的工具函式以及其使用範例:
def get_product_by_name(name):
    return products.get(name, None)
def get_products_by_category(category):
    return [product for product in products.values() \
            if product["category"] == category]
print(get_product_by_name("TechPro Ultrabook"))
>>> {'name': 'TechPro Ultrabook', 'category': '電腦與筆記型電腦',
     'brand': 'TechPro', 'model_number': 'TP-UB100', 'warranty': '一年',
     'rating': 4.5, 'features': ['13.3 吋顯示器', '8GB 記憶體',
     '256GB SSD硬碟', 'Intel Core i5 處理器'],
     'description': '一款適合日常使用的輕薄 Ultrabook。',
     'price': 799.99}
print(get_products_by_category("電腦與筆記型電腦"))
>>> [{'name': 'TechPro Ultrabook', 'category': '電腦與筆記型電腦',
 'brand': 'TechPro', 'model_number': 'TP-UB100', 'warranty': '一年',
 'rating': 4.5, 'features': ['13.3 吋顯示器', '8GB 記憶體',
 '256GB SSD硬碟', 'Intel Core i5 處理器'],
 'description': '一款適合日常使用的輕薄 Ultrabook。', 'price': 799.99},
 ... 中間省略 ...
 {'name': 'BlueWave Chromebook', 'category': '電腦與筆記型電腦',
 'brand': 'BlueWave', 'model_number': 'BW-CB100', 'warranty': '一年',
 'rating': 4.1, 'features': ['11.6 吋顯示器', '4GB 記憶體',
 '32GB eMMC 硬碟', 'Chrome 作業系統'],
 'description': '一款便捷的Chromebook,適合在網路上瀏覽和處理基本工作。.',
 'price': 249.99}]
接下來的工具函式則是用來將LLM回傳的訊息轉換成JSON物件:
import json
def read_string_to_list(input_string):
    if input_string is None:
        return None
    try:
        # 單引號改為雙引號,這樣才是合法的 JSON 字串格式
        input_string = input_string.replace("'", "\"")
        data = json.loads(input_string)
        return data
    except json.JSONDecodeError:
        print("Error: Invalid JSON string")
        return None
轉換成JSON物件的實際結果如下
category_and_product_list = read_string_to_list(category_and_product_response_1) 
print(category_and_product_list)
>> [{'category': '手機和配件', 'products': ['SmartX ProPhone']},
  {'category': '相機和攝影機', 'products': ['FotoSnap 單眼相機']},
  {'category': '電視和家庭劇院系統', 'products': [ 'CineView 4K 液晶電視',
 'CineView 8K 液晶電視', 'CineView OLED 電視', 'SoundMax 家庭劇院',
 'SoundMax 音箱'] }]
接下來,我們要展示的是將從訊息中提取的產品/產品類別資訊與外部資料結合的核心函式:
def generate_output_string(data_list):
    output_string = ""
    if data_list is None:
        return output_string
    for data in data_list:
        try:
            # 如果有 "products" 屬性,就代表是要查詢產品
            if "products" in data:
                products_list = data["products"]
                for product_name in products_list:
                    # 透過產品名稱取得產品資訊
                    product = get_product_by_name(product_name)
                    if product:
                        # 將產品資訊轉換為 JSON 格式,並加入換行符號
                        output_string += json.dumps(product, indent=4, ensure_ascii=False) + "\n"
                    else:
                        print(f"Error: Product '{product_name}' not found")
            # 如果有 "category" 屬性,就代表是要查詢類別
            elif "category" in data:
                category_name = data["category"]
                # 透過類別名稱取得產品資訊
                category_products = get_products_by_category(category_name)
                for product in category_products:
                    # 將產品資訊轉換為 JSON 格式,並加入換行符號
                    output_string += json.dumps(product, indent=4, ensure_ascii=False) + "\n"
            else:
                print("Error: Invalid object format")
        except Exception as e:
            print(f"Error: {e}")
     return output_string
以下是該函式的實際使用情況及結果:
product_information_for_user_message_1 = generate_output_string( \
     category_and_product_list)
print(product_information_for_user_message_1)
>> {
    "name": "SmartX ProPhone",
    "category": "手機和配件",
    "brand": "SmartX",
    "model_number": "SX-PP10",
    "warranty": "一年",
    "rating": 4.6,
    "features": [
        "6.1 吋顯示器",
        "128GB 儲存空間",
        "12MP 雙鏡頭",
        "5G 網路"
    ],
    "description": "一款功能強大並具有先進照相功能的智慧手機",
    "price": 899.99 }
{
    "name": "FotoSnap 單眼相機",
    "category": "相機和攝影機",
    "brand": "FotoSnap",
    "model_number": "FS-DSLR200",
    "warranty": "一年",
    "rating": 4.7,
    "features": [
        "24.2MP 感光元件", 
... 中間省略 ...
    "description": "使用這款時尚且音質出色的音響升級您的電視聲光效果。",
    "price": 199.99
}

整合資訊並生成回應訊息

有了以上的各種工具函式,我們現在可以將使用者的訊息從提取訊息到獲取詳細資訊,最後產生回應訊息的完整流程串連起來,具體的使用方法如下:
ystem_message = f"""
您是一家大型3C賣場的客服助理。 \
請以親切且樂於助人的態度回答問題,\
並確保您的答案簡潔明瞭。\
也要記得向用戶提出相關的追問。
"""
user_message_1 = f"""
請告訴我關於SmartX Pro手機以及 \
FotoSnap單眼相機的資訊。    \
另外也請介紹一下你們的電視產品。
"""
messages =  [
{'role':'system',  'content': system_message},
{'role':'user',  'content': user_message_1},
{'role':'assistant',  'content': f"""相關產品資訊:\n\
{product_information_for_user_message_1}"""},
]
final_response = get_completion_from_messages(messages)
print(final_response)
--- 以下是語言模型的回覆訊息 ---
>> 以上是我們店裡的 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 音箱等產品,
可以升級您的電視聲光效果。  如果您對這些產品有任何問題或需要更多資訊
,請隨時向我們詢問。
以上就是語言模型與外部系統整合的基本架構,如果你對完整的程式碼感興趣,可以參考這裡:HelloGPT/building-system-with-chatgpt-api-03-Chaining Prompts.ipynb at main · u8621011/HelloGPT (github.com)
為什麼會看到廣告
Ted Chen
Ted Chen
一個近幾年專注於 語言教育 / 自然語言處理 / 大型語言模型應用 的 IT 人 https://www.facebook.com/Chen.Ching.Tai
留言0
查看全部
發表第一個留言支持創作者!