實作 Quick Replies 生成函式:完整指南

更新日期: 2025 年 2 月 12 日

在 AI 驅動的聊天機器人中,「建議回覆(Quick Replies)」能夠幫助使用者快速選擇合適的回應,提升對話效率與體驗。

本篇文章將帶你深入探討如何 透過 OpenAI API 生成 Quick Replies,並提供 完整 Python 程式碼,讓你能夠快速上手。

我們將一步步拆解 generate_quick_replies.py 的核心邏輯,涵蓋:

  1. 如何載入 Prompt(提示詞)
  2. 如何整合對話歷史、FAQ 清單、產品清單
  3. 如何向 OpenAI API 發送請求並解析回應
  4. 如何處理 JSON 解析錯誤
  5. 測試範例與執行結果

如果你希望在自己的專案中實現 Quick Replies 功能,這篇文章將是你的最佳參考指南!


主要概念與架構

Quick Replies 是什麼?

Quick Replies 是一種 預設建議回覆,用於幫助使用者在聊天機器人對話中快速選擇適當的回應。

例如,在電商客服對話中,AI 可能提供以下建議:

  • 「有哪些熱門商品?」
  • 「我要查詢訂單狀態」
  • 「如何聯絡客服?」

這些回覆可以 根據對話歷史、常見問題(FAQ)、產品清單等資料動態生成,提升互動體驗。

generate_quick_replies.py 的功能

import openai
import json
import os
from dotenv import load_dotenv

load_dotenv()
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")

def load_prompt():
    with open("quick_replies_prompt.txt", "r", encoding="utf-8") as f:
        return f.read()

# 生成 Quick Replies 的函式
def generate_quick_replies(chat_history, faq_list, product_list):
    prompt = load_prompt()

    try:
        client = openai.OpenAI(api_key=OPENAI_API_KEY)

        response = client.chat.completions.create(
            model="gpt-4o",
            response_format={"type": "json_object"},
            messages=[
                {"role": "system", "content": prompt},
                {"role": "user", "content": f"這是過去的對話歷史: {json.dumps(chat_history, ensure_ascii=False)}"},
                {"role": "user", "content": f"FAQ 清單: {json.dumps(faq_list, ensure_ascii=False)}"},
                {"role": "user", "content": f"產品清單: {json.dumps(product_list, ensure_ascii=False)}"},
            ],
            max_tokens=100
        )

        result = response.choices[0].message.content
        try:
            parsed_result = json.loads(result)
            if isinstance(parsed_result, dict) and "quick_replies" in parsed_result:
                return parsed_result["quick_replies"]  # ✅ 取出陣列,確保回傳 list
        except json.JSONDecodeError as e:
            print(f"❌ JSON 解析錯誤: {e}")
            print(f"❌ OpenAI API 回應: {result}")

        return None  # 解析失敗時回傳 None

    except Exception as e:
        print(f"發生錯誤: {e}")
        return None

# 測試函式
if __name__ == "__main__":
    test_data = {
        "chat_history": [
            {"role": "user", "content": "我要買送給愛好 3C 產品的朋友的禮物,該選哪個好?"},
            {"role": "assistant", "content": "推薦這幾款熱門 3C 產品:1. MacBook Pro 💻 2. iPad 0 元 📱"}
        ],
        "faq_list": ["如何成為會員", "如何取得優惠券", "退貨政策是什麼"],
        "product_list": ["MacBook Pro", "iPad 0 元", "高效保濕面膜", "無痕內衣"]
    }

    replies = generate_quick_replies(
        test_data["chat_history"], test_data["faq_list"], test_data["product_list"]
    )

    print("產生的 Quick Replies:")
    print(replies)

這支程式的主要任務是:

  1. 載入 Prompt,確保 AI 依照預設格式生成回應。
  2. 接收輸入數據(對話歷史、FAQ、產品清單)。
  3. 向 OpenAI API 發送請求,並取得 AI 產生的 Quick Replies。
  4. 解析 API 回應的 JSON 結果,並回傳建議回覆陣列。
  5. 處理 API 例外錯誤,確保程式穩定運行。

載入 OpenAI API Key

程式使用 .env 檔案來管理 API 金鑰,確保安全性:

import openai
import json
import os
from dotenv import load_dotenv

load_dotenv()
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")

這樣做的好處是:

避免 API Key 硬編碼
可透過環境變數安全存取
方便不同環境(開發、正式)切換 API Key

載入 Prompt

AI 需要一個 清楚的 Prompt 來生成正確的 Quick Replies。我們從 quick_replies_prompt.txt 載入這個提示詞:

def load_prompt():
    with open("quick_replies_prompt.txt", "r", encoding="utf-8") as f:
        return f.read()

這段 Prompt 會告訴 AI:

  • 它的角色與目標
  • 回應格式(JSON 格式)
  • 需要考慮的資料來源(對話歷史、FAQ、產品清單)

延伸閱讀:Python open() 函數完整指南

核心函式:generate_quick_replies

這是整個程式的核心,負責產生 Quick Replies。

def generate_quick_replies(chat_history, faq_list, product_list):
    prompt = load_prompt()

    try:
        client = openai.OpenAI(api_key=OPENAI_API_KEY)

        response = client.chat.completions.create(
            model="gpt-4o",
            response_format={"type": "json_object"},
            messages=[
                {"role": "system", "content": prompt},
                {"role": "user", "content": f"這是過去的對話歷史: {json.dumps(chat_history, ensure_ascii=False)}"},
                {"role": "user", "content": f"FAQ 清單: {json.dumps(faq_list, ensure_ascii=False)}"},
                {"role": "user", "content": f"產品清單: {json.dumps(product_list, ensure_ascii=False)}"},
            ],
            max_tokens=100
        )

定義函式

def generate_quick_replies(chat_history, faq_list, product_list):

這是一個 Python 函式,它接收 三個輸入參數

  • chat_history:過去的對話歷史(通常是一個 list)。
  • faq_list:常見問題清單(list)。
  • product_list:產品資訊(list)。

這些資訊將幫助 AI 產生更相關的 Quick Replies。

載入 Prompt

    prompt = load_prompt()

這行程式碼呼叫 load_prompt() 函式,從 quick_replies_prompt.txt 讀取預先定義的 Prompt(提示詞)

為什麼要這樣做?

  • 確保 AI 使用固定的格式與指令,讓輸出更穩定。
  • 方便修改 Prompt,而不需要動到 Python 程式碼。

設置 OpenAI API 客戶端

    try:
        client = openai.OpenAI(api_key=OPENAI_API_KEY)

這裡建立一個 OpenAI API 客戶端,並使用 .env 檔案中的 OPENAI_API_KEY 作為 API 金鑰。

為什麼用 try

  • 避免 API 連線錯誤 讓程式崩潰。
  • 如果 API Key 無效或網路異常,可以在 except 區塊處理錯誤。

發送 API 請求

        response = client.chat.completions.create(
            model="gpt-4o",
            response_format={"type": "json_object"},

這行程式碼向 OpenAI 的 GPT-4o 模型發送請求,並指定:

  • model="gpt-4o":使用 GPT-4o 模型。
  • response_format={"type": "json_object"}:要求 API 回應格式為 JSON,確保輸出可以被程式解析。

為什麼要 JSON 格式?

  • AI 產生的 Quick Replies 需要結構化數據,方便 Python 處理。
  • 避免 AI 回傳雜亂的文字格式,確保 API 回應可被程式碼解析。

準備 messages 參數

            messages=[
                {"role": "system", "content": prompt},
                {"role": "user", "content": f"這是過去的對話歷史: {json.dumps(chat_history, ensure_ascii=False)}"},
                {"role": "user", "content": f"FAQ 清單: {json.dumps(faq_list, ensure_ascii=False)}"},
                {"role": "user", "content": f"產品清單: {json.dumps(product_list, ensure_ascii=False)}"},
            ],

這部分定義了 messages,它是一個 列表(list),由多個訊息(字典 dict)組成。

🔹 第一則訊息 (role: system)

{"role": "system", "content": prompt}
  • 這是 系統訊息,用來設定 AI 的行為。
  • 它的 content 是從 quick_replies_prompt.txt 讀取的 Prompt,確保 AI 產生的 Quick Replies 符合我們的需求。

🔹 後續訊息 (role: user)

這三個 user 訊息提供 對話背景資料,讓 AI 生成更準確的回覆:

{"role": "user", "content": f"這是過去的對話歷史: {json.dumps(chat_history, ensure_ascii=False)}"}
{"role": "user", "content": f"FAQ 清單: {json.dumps(faq_list, ensure_ascii=False)}"}
{"role": "user", "content": f"產品清單: {json.dumps(product_list, ensure_ascii=False)}"}
  • json.dumps() 確保 chat_historyfaq_listproduct_list 轉換為 JSON 格式,這樣 AI 能正確解析這些資料,而不會誤判為普通文字。
  • ensure_ascii=False 確保中文不會變成 Unicode(如 \u53ef\u4ee5,保持可讀性。

為什麼要提供這些資訊?

  • chat_history:讓 AI 知道使用者的歷史對話,避免重複建議。
  • faq_list:幫助 AI 確保建議回覆與常見問題相關。
  • product_list:讓 AI 可根據產品資訊提供建議回覆(例如推薦商品)。

設定 max_tokens

max_tokens=100
  • max_tokens=100 限制回應的最大字數,防止 AI 生成過長的 Quick Replies。

為什麼限制 Token 數?

  • 控制 API 成本(token 越多,費用越高)。
  • 避免 回應太長,影響用戶體驗(Quick Replies 應該短小精悍)。

解析 OpenAI API 回應

        result = response.choices[0].message.content
        try:
            parsed_result = json.loads(result)
            if isinstance(parsed_result, dict) and "quick_replies" in parsed_result:
                return parsed_result["quick_replies"]  # ✅ 確保回傳 list
        except json.JSONDecodeError as e:
            print(f"❌ JSON 解析錯誤: {e}")
            print(f"❌ OpenAI API 回應: {result}")

        return None  # 解析失敗時回傳 None

這段程式碼的主要功能是 解析 OpenAI API 回應的 JSON 資料,並 確保正確取得 quick_replies 陣列。如果解析失敗,則回傳 None,避免程式崩潰。

接下來我們 逐行解析這段程式碼的細節,讓你完全理解它的運作方式。

取得 OpenAI API 回應

result = response.choices[0].message.content

response 是 OpenAI API 回傳的結果,通常是個字典(dict)。
choices[0] 代表 OpenAI 產生的第一個回應(通常 OpenAI API 會回傳多個選擇,但這裡只取第一個)。
.message.content 取得 AI 產生的回應內容,它應該是一個 JSON 格式的字串

嘗試解析 JSON

try:
    parsed_result = json.loads(result)

這裡使用 json.loads(result)將 AI 回應的 JSON 字串轉換為 Python 物件

💡 json.loads() 作用

  • 如果 result 是:
{
    "quick_replies": ["查詢訂單", "聯絡客服", "退貨政策"]
}
  • json.loads(result) 會轉換成:
{"quick_replies": ["查詢訂單", "聯絡客服", "退貨政策"]}
  • 如果 result 不是正確的 JSON(例如 OpenAI 回應一段純文字),json.loads() 會拋出錯誤(進入 except 區塊)。

確保回應格式正確

if isinstance(parsed_result, dict) and "quick_replies" in parsed_result:

這行程式碼做了 兩層檢查,確保 API 回應格式正確:

🔹 1️⃣ isinstance(parsed_result, dict)

確保 parsed_result 是字典(dict),因為 JSON 可能回傳不同格式(例如 liststr),如果不是 dict,我們就不會繼續執行。

🔸 可能的錯誤回應

["這是一個錯誤的回應"]

🔸 解析後的 Python 物件

["這是一個錯誤的回應"]  # 這是一個 list,不是 dict!

🚫 這會導致 isinstance(parsed_result, dict) 回傳 False,所以我們不會繼續執行,也就不會出錯。

🔹 2️⃣ "quick_replies" in parsed_result

確保 parsed_result 字典內有 "quick_replies" 這個鍵(key),避免 API 回傳錯誤訊息時出錯。

🔸 可能的錯誤回應

{"error": "請求失敗"}

🔸 解析後的 Python 物件

{"error": "請求失敗"}  # 沒有 "quick_replies"!

🚫 這時候 "quick_replies" not in parsed_result",我們不會繼續執行,避免程式崩潰。

🔹 預期的正確回傳格式

如果 OpenAI 回應正常,應該會回傳類似這樣的 JSON:

{
    "quick_replies": ["查詢訂單", "聯絡客服", "退貨政策"]
}

🔸 解析後的 Python 物件

{
    "quick_replies": ["查詢訂單", "聯絡客服", "退貨政策"]
}

這時候 isinstance(parsed_result, dict) 會回傳 True
"quick_replies" in parsed_result 也會回傳 True
程式會執行 return parsed_result["quick_replies"],回傳 ["查詢訂單", "聯絡客服", "退貨政策"]

這樣,主程式就能順利接收 AI 產生的 Quick Replies,並顯示給使用者! 🎯

取得 Quick Replies

return parsed_result["quick_replies"]  # ✅ 確保回傳 list

從 JSON 解析後的字典 parsed_result 取出 quick_replies 陣列,並回傳。
✅ 確保回傳的是 list,讓主程式可以使用這些建議回覆。

範例: 如果 AI 回傳:

{
    "quick_replies": ["查詢訂單", "聯絡客服", "退貨政策"]
}

解析後 parsed_result["quick_replies"] 會是:

["查詢訂單", "聯絡客服", "退貨政策"]

這樣 主程式可以直接使用這些 Quick Replies 來顯示給使用者!

JSON 解析失敗時的錯誤處理

except json.JSONDecodeError as e:
    print(f"❌ JSON 解析錯誤: {e}")
    print(f"❌ OpenAI API 回應: {result}")

如果 json.loads(result) 失敗(例如 OpenAI 回傳的是非 JSON 格式的文字),就會拋出 json.JSONDecodeError,進入 except 區塊:

print(f"❌ JSON 解析錯誤: {e}")

  • 顯示錯誤資訊,方便 Debug,知道是哪裡解析出錯。

print(f"❌ OpenAI API 回應: {result}")

  • 記錄 OpenAI API 回應的內容,方便找出錯誤原因。
  • 可能的錯誤範例: ❌ JSON 解析錯誤: Expecting value: line 1 column 1 (char 0) ❌ OpenAI API 回應: <html>...(這可能是 API 連線失敗,回傳 HTML 錯誤頁面)

解析失敗時回傳 None

return None  # 解析失敗時回傳 None

✅ 如果 OpenAI 回應的內容無法解析成 JSON 或不符合格式,則回傳 None
✅ 這樣主程式在收到 None 時,就可以知道 API 回應異常,並採取適當的錯誤處理(例如記錄日誌或重新請求)

錯誤處理

    except Exception as e:
        print(f"發生錯誤: {e}")
        return None

這樣做的好處: ✅ 確保 API 失敗時,程式不會崩潰
方便 Debug,讓開發者知道錯誤原因


測試與執行

if __name__ == "__main__":
    test_data = {
        "chat_history": [
            {"role": "user", "content": "我要買送給愛好 3C 產品的朋友的禮物,該選哪個好?"},
            {"role": "assistant", "content": "推薦這幾款熱門 3C 產品:1. MacBook Pro 💻 2. iPad 0 元 📱"}
        ],
        "faq_list": ["如何成為會員", "如何取得優惠券", "退貨政策是什麼"],
        "product_list": ["MacBook Pro", "iPad 0 元", "高效保濕面膜", "無痕內衣"]
    }

    replies = generate_quick_replies(
        test_data["chat_history"], test_data["faq_list"], test_data["product_list"]
    )

    print("產生的 Quick Replies:")
    print(replies)

這段程式碼的主要目的是 測試 generate_quick_replies() 函式是否能正確產生 Quick Replies(建議回覆)

讓我們逐行解析這段程式碼,確保你能完全理解它的運作方式。

if __name__ == "__main__":

if __name__ == "__main__":

這行程式碼的作用是:

確保這段測試程式只有在「直接執行這個 Python 檔案」時才會運行
如果這個檔案被其他程式引用(import),這段測試程式不會自動執行

為什麼需要這行?

  • 如果 generate_quick_replies.py 被當作模組引入 其他程式,測試資料就不應該被執行。
  • 這行 if __name__ == "__main__": 確保 這段測試程式只有在此程式被「獨立執行」時才會運行

延伸閱讀:模組的執行與匯入:__name__ 的角色

建立測試資料 test_data

test_data = {
    "chat_history": [
        {"role": "user", "content": "我要買送給愛好 3C 產品的朋友的禮物,該選哪個好?"},
        {"role": "assistant", "content": "推薦這幾款熱門 3C 產品:1. MacBook Pro 💻 2. iPad 0 元 📱"}
    ],
    "faq_list": ["如何成為會員", "如何取得優惠券", "退貨政策是什麼"],
    "product_list": ["MacBook Pro", "iPad 0 元", "高效保濕面膜", "無痕內衣"]
}

這裡定義了一組 模擬的測試資料,用來檢查 generate_quick_replies() 是否能正確產生建議回覆。

📌 測試資料包含三個部分:

1️⃣ chat_history(對話歷史)

  • role: user:使用者詢問購買建議
  • role: assistant:AI 提供推薦商品

2️⃣ faq_list(常見問題清單)

  • 包含三個 FAQ:「如何成為會員」、「如何取得優惠券」、「退貨政策是什麼」

3️⃣ product_list(產品清單)

  • 包含四個產品:「MacBook Pro」、「iPad 0 元」、「高效保濕面膜」、「無痕內衣」

為什麼要提供這些數據?

  • chat_history 讓 AI 知道用戶的上下文,避免重複問相同問題。
  • faq_list 幫助 AI 產生與常見問題相關的建議回覆
  • product_list 提供可推薦的商品,幫助 AI 生成更有價值的建議回覆

呼叫 generate_quick_replies()

replies = generate_quick_replies(
    test_data["chat_history"], test_data["faq_list"], test_data["product_list"]
)

這行程式碼的作用是:

將測試資料傳入 generate_quick_replies(),讓 AI 產生 Quick Replies
回傳的 replies 應該是一個 list,包含 AI 生成的建議回覆

可能的回傳結果(示例):

["推薦 MacBook Pro", "有沒有更便宜的 3C 產品?", "有哪些熱門商品?"]

這表示 AI 根據對話歷史、FAQ、產品清單,產生了適合的建議回覆。

輸出 AI 產生的 Quick Replies

print("產生的 Quick Replies:")
print(replies)

這段程式碼的作用是:

將 AI 產生的建議回覆輸出到終端機,方便檢查結果是否符合預期

如果測試成功,應該會輸出類似這樣的結果:

產生的 Quick Replies:
['推薦 MacBook Pro', '有沒有更便宜的 3C 產品?', '有哪些熱門商品?']

這樣我們就可以確認 generate_quick_replies() 是否能根據測試資料產生合適的 Quick Replies


結論與延伸

透過這篇文章,我們學習到:

  • 如何實作 Quick Replies 生成函式
  • 如何整合 OpenAI API 與聊天歷史、FAQ、產品資訊
  • 如何處理 JSON 解析錯誤,確保系統穩定
  • 如何進行測試,確保 AI 生成合理的建議回覆

延伸學習

接下來,你可以:

  • 優化 Prompt,提高 Quick Replies 的準確性
  • 增加 UI 介面整合,讓按鈕點擊更直覺
  • 記錄 AI 產生的回覆,分析使用者行為,持續優化體驗

希望這篇文章能幫助你打造更智能的 AI 聊天機器人!

Similar Posts