實作 Quick Replies 生成函式:完整指南
更新日期: 2025 年 2 月 12 日
本文為 聊天機器人-建議回復 系列文,第 7 篇:
- 如何用「建議回覆」提升 AI 客服體驗?讓對話更快更準確!
- 如何設計高效的快速回復 (Quick Replies) 功能?—— 完整指南
- 如何取得 OpenAI 的 API 金鑰:詳細步驟與完整指南
- 使用 Python-dotenv 管理環境變數:完整指南
- OpenAI 套件介紹(Python)—— 從安裝到實戰應用
- 設計高效 Prompt 工程:提升 AI 生成 Quick Replies 的準確性
- 實作 Quick Replies 生成函式:完整指南 👈進度
- 結構化數據整合與上下文處理:提升 AI 生成 Quick Replies 的準確性
- 生成回覆與異常處理:確保 AI 提供高效、可靠的建議回覆
- 自動化測試與效能監控:確保 Quick Replies 生成穩定可靠
- 優化策略與擴展應用:提升 AI 建議回覆(Quick Replies)的效能與適應性
在 AI 驅動的聊天機器人中,「建議回覆(Quick Replies)」能夠幫助使用者快速選擇合適的回應,提升對話效率與體驗。
本篇文章將帶你深入探討如何 透過 OpenAI API 生成 Quick Replies,並提供 完整 Python 程式碼,讓你能夠快速上手。
我們將一步步拆解 generate_quick_replies.py 的核心邏輯,涵蓋:
- 如何載入 Prompt(提示詞)
- 如何整合對話歷史、FAQ 清單、產品清單
- 如何向 OpenAI API 發送請求並解析回應
- 如何處理 JSON 解析錯誤
- 測試範例與執行結果
如果你希望在自己的專案中實現 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)
這支程式的主要任務是:
- 載入 Prompt,確保 AI 依照預設格式生成回應。
- 接收輸入數據(對話歷史、FAQ、產品清單)。
- 向 OpenAI API 發送請求,並取得 AI 產生的 Quick Replies。
- 解析 API 回應的 JSON 結果,並回傳建議回覆陣列。
- 處理 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_history
、faq_list
、product_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 可能回傳不同格式(例如 list
或 str
),如果不是 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__":
確保 這段測試程式只有在此程式被「獨立執行」時才會運行。
建立測試資料 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 聊天機器人!