
現今,越來越多的企業選擇透過 WhatsApp 使用聊天機械人,以與顧客互動、了解他們的需求,以及蒐集所需的資料。然而,他們在蒐集和整理資料時,往往面臨著諸多效率方面的挑戰。在這種情況下,WhatsApp Flows 便能大派用場。
只需將聊天機械人與 WhatsApp Flows 整合,企業便可以更高效地解讀收到的顧客資料。如此一來,聊天機械人能夠根據對話情景,啟動專為蒐集資料而設的特定 Flows 流程。
在本教學導覽中,您將使用 Llama 2 和 Python 來構建聊天機械人,並將其連結至 WhatsApp Flows,以提升其資料蒐集能力。在這個過程中,您將可見證 WhatsApp Flows 如何提升聊天機械人體驗的易用性,並提高顧客資料蒐集的準確性和效率。
聊天機械人會使用 WhatsApp Flows 來回覆用戶的要求和提示,以便蒐集資料。以本文所用的虛構西班牙酒店為例,它可讓用戶與聊天機械人交談、搜尋酒店所提供的服務之資訊,並聯絡酒店以尋求支援。
聊天機械人將配搭使用簡單的 if 陳述式和標準 Llama 2 模型,以便系統存取充足的常識知識庫。
第 1 部分:
使用 WhatsApp 管理工具的流程建造工具來建立 Flows 流程。
第 2 部分:
將 Llama 2 模型從 GGML 轉換為 GGUF。
在這部分,您需要使用流程建造工具來建立一些 Flows 流程。或者,您可以使用 Flows API;本文對此不作詳細闡述。
若要採取本部分的步驟,請確保您具備下列條件:
已安裝 ngrok。
最後,確保您已完成使用 Flows 所需執行的步驟。您亦可預覽完整專案程式碼。
首先,前往您 WhatsApp Business 帳戶的「流程」頁面。若這是您首次與 Flows 互動,您應該會看到一個標題為「開始建立流程」的按鈕。否則,此頁面右上方會顯示「建立流程」按鈕。
點擊畫面所顯示的按鈕以開啟對話框,並在當中輸入您 Flows 流程的一些詳細資訊:

首先,您需要建立一個 Flows 流程,讓用戶用來搜尋酒店所提供的服務之資訊。
在「名稱」欄位中輸入所需名稱。接著,在「類別」下拉式選單中,選擇「註冊」,並將「範本」下拉式選單設為「無」。點擊「提交」。
在下一個頁面中,畫面左側將顯示編輯工具,右側則會顯示預覽畫面。
將編輯工具的內容替換為您 Flows 流程的 JSON 標記。您可以查閱開發人員文件,進一步了解 Flow JSON。
儲存 Flows 流程;您的預覽畫面應與下圖相似:

此 Flows 流程包含一個畫面,用戶可在當中輸入其詳細資訊、選擇感興趣的服務,以及查閱一則選用的額外訊息。當用戶點擊「提交」時,這個 Flows 流程便會關閉,並將收到的資料傳送至您企業以供處理。傳輸此類資料的方法之一便是使用端點。不過,此專案不會用到端點。這些資料會傳送至支援聊天機械人的同一個 Webhook。
您可以使用各個動作來執行此傳輸程序。您需要使用 payload 物件,以定義傳遞至下一個畫面的資料:
...
"on-click-action": {
"name": "complete",
"payload": {
"firstname": "${form.first_name}",
"secondname": "${form.second_name}",
"services_interested": "${form.services_interested}",
"additional_info": "${form.additional_info}",
"flow_key": "agentconnect"
}
}
...
在此程式碼片段中,用戶的按鈕點擊動作會觸發 on-click-action,以擷取裝載中的資料。接著,它會將裝載傳送至 Webhook 伺服器,並透過 complete 動作關閉 Flows 流程。
您可以沿用分配任何變數的方法來分配 payload 鍵。相應的值可代表資料物件或 Flows 流程元件的名稱(類似 HTML 表格的名稱屬性)。
現在,您應會查看運作中的 Flows 流程,並使用「互動式預覽」切換按鈕來模擬真實的用戶體驗:

測試之後,您便可發佈目前仍處於「草稿」狀態的 Flows 流程。若要發佈此 Flows 流程,請開啟「儲存」右側的選單並點擊「發佈」。這個 Flows 流程現已準備就緒並可供使用。
現在,您需要建立「聯絡我們」Flows 流程。
首先,重複執行上文所述的初始 Flows 流程建立程序,但將類別設為「聯絡我們」。將編輯工具的內容替換為這個 JSON 標記,以顯示以下畫面:

發佈此 Flows 流程並繼續執行下一部分,以設定聊天機械人。該部分會用到 send_message、flow_details 和 flow_reply_processor 這 3 個函數;這些函數包含將 Flows 流程傳送給用戶的必要邏輯。該部分亦會提及處理傳入 Flows 流程裝載的邏輯。因此,即使您已構建聊天機械人,我們仍建議您仔細查閱該部分的內容。
接下來,您需要配置聊天機械人並將其整合到您的 Flows 流程。
在繼續操作之前,請確保您具備下列條件:
擁有 Python 的基本知識和最新版本。
已下載 HuggingFace 版本 Llama 2。HuggingFace Llama 2 模型無需使用任何其他工具或專用硬件。您亦可使用官方版本 Llama 2,但您將需進行額外設定。
擁有您帳戶的存取憑證和手機號碼編號。
擁有程式碼編輯工具。
聊天機械人將透過一組預先定義的指令碼來運作;該組指令碼旨在根據用戶輸入的內容,為其提供相應的協助。在初次互動時,聊天機械人會根據用戶的訊息,提供個人化問候語文字,以及一個文字選單。這些選項可迎合特定需求:酒店所提供的查詢服務、聯絡酒店的客戶服務人員,或與由 Llama 支援的聊天機械人互動。
使用英數字元回覆時,系統會將用戶連結至相應的服務或動作。然而,任何其他回覆均將觸發預設聊天機械人功能,以協助處理一般查詢,或根據進一步對話,引導用戶取得可用服務。
首先,在終端上運行以下指令以建立虛擬環境:
python -m venv venv
啟用此環境:
source venv/bin/activate
接著,安裝所需套件:
pip install requests flask llama-cpp-python python-dotenv
您需要使用 Flask 來建立路線並與 API 互動、使用 requests 來傳送互聯網要求、使用 llama-cpp-python 來與模型互動,並使用 python-dotenv 來載入環境變數。
接下來,建立名為 .env 的環境檔案和下列內容,以分配相應的值;VERIFY_TOKEN 可使用任何字串。
TOKEN =
ACCESS_TOKEN =
PHONE_NUMBER_ID =
在同一個目錄中,建立名為 main.py 的檔案,並開始新增您需要使用的套件:
import os
import re
import time
import uuid
import requests
from dotenv import load_dotenv
from flask import Flask, request, make_response, json
from llama_cpp import Llama
現在,初始化變數和類別。此程式碼片段亦會啟動 Flask 並呼叫 load_dotenv() 方法,以助載入變數:
app = Flask(__name__)
load_dotenv()
PHONE_NUMBER_ID = os.getenv('PHONE_NUMBER_ID')
url = f"https://graph.facebook.com/v18.0/{PHONE_NUMBER_ID}/messages"
TOKEN = os.getenv('TOKEN')
ACCESS_TOKEN = os.getenv('ACCESS_TOKEN')
code_prompt_texts = ["Contact us", "Chat with our chatbot", "YES", "NO"]
service_list = [
"Accommodation Services",
"Spa Services",
"Dining Services",
"Recreational Facilities",
"Business & Conference Services",
"Transportation Services",
"Accessibility Services",
"Pet-Friendly Services"
]service_list 會用於儲存酒店所提供的各項服務。code_prompt_texts 清單包含與用戶的輸入選擇相應的選項;這些選項分別是「1」、「2」、「是」和「否」,可使用下方函數來指定。下方函數有助將用戶的回覆配對至相應的選項。
def extract_string_from_reply(user_input):
match user_input:
case "1":
user_prompt = code_prompt_texts[0].lower()
case "2":
user_prompt = code_prompt_texts[1].lower()
case "Y":
user_prompt = code_prompt_texts[2].lower()
case "N":
user_prompt = code_prompt_texts[3].lower()
case _:
user_prompt = str(user_input).lower()
return user_prompt
程式碼會將字串轉換為小楷字母,以免運行條件式邏輯時出現配對錯誤的情形。match…case 架構會將用戶輸入的提示配對至輸出項目。舉例來說,用戶輸入「1」時將觸發 "Contact us" 功能。
接下來,以下函數包含使用 Python RegEx 套件 re 的 if 陳述式,以從顧客訊息當中搜尋特定字詞,從而判斷向用戶傳送哪類回覆:
def user_message_processor(message, phonenumber, name):
user_prompt = extract_string_from_reply(message)
if user_prompt == "yes":
send_message(message, phonenumber, "TALK_TO_AN_AGENT", name)
elif user_prompt == "no":
print("Chat terminated")
else:
if re.search("service", user_prompt):
send_message(message, phonenumber, "SERVICE_INTRO_TEXT", name)
elif re.search(
"help|contact|reach|email|problem|issue|more|information", user_prompt
):
send_message(message, phonenumber, "CONTACT_US", name)
elif re.search("hello|hi|greetings", user_prompt):
if re.search("this", user_prompt):
send_message(message, phonenumber, "CHATBOT", name)
else:
send_message(message, phonenumber, "SEND_GREETINGS_AND_PROMPT", name)
else:
send_message(message, phonenumber, "CHATBOT", name)
現在,訊息(如 "Hello there")將會觸發 send_message 方法,當中第二個引數為 SEND_GREETINGS_AND_PROMPT。以下是 send_message 方法;視乎具體情況,替換 <xxx> 之間的內容。
def send_message(message, phone_number, message_option, name):
greetings_text_body = (
"\nHello "
+ name
+ ". Welcome to our hotel. What would you like us to help you with?\nPlease respond with a numeral between 1 and 2.\n\n1. "
+ code_prompt_texts[0]
+ "\n2. "
+ code_prompt_texts[1]
+ "\n\nAny other reply will connect you with our chatbot."
)
# loading the list's entries into a string for display to the user
services_list_text = ""
for i in range(len(service_list)):
item_position = i + 1
services_list_text = (
f"{services_list_text} {item_position}. {service_list[i]} \n"
)
service_intro_text = f"We offer a range of services to ensure a comfortable stay, including but not limited to:\n\n{services_list_text}\n\nWould you like to connect with an agent to get more information about the services?\n\nY: Yes\nN: No"
contact_flow_payload = flow_details(
flow_header="Contact Us",
flow_body="You have indicated that you would like to contact us.",
flow_footer="Click the button below to proceed",
flow_id=str("<FLOW-ID>"),
flow_cta="Proceed",
recipient_phone_number=phone_number,
screen_id="CONTACT_US",
)
agent_flow_payload = flow_details(
flow_header="Talk to an Agent",
flow_body="You have indicated that you would like to talk to an agent to get more information about the services that we offer.",
flow_footer="Click the button below to proceed",
flow_id=str("<FLOW-ID>"),
flow_cta="Proceed",
recipient_phone_number=phone_number,
screen_id="TALK_TO_AN_AGENT",
)
match message_option:
case "SEND_GREETINGS_AND_PROMPT":
payload = json.dumps(
{
"messaging_product": "whatsapp",
"to": str(phone_number),
"type": "text",
"text": {"preview_url": False, "body": greetings_text_body},
}
)
case "SERVICE_INTRO_TEXT":
payload = json.dumps(
{
"messaging_product": "whatsapp",
"to": str(phone_number),
"type": "text",
"text": {"preview_url": False, "body": service_intro_text},
}
)
case "CHATBOT":
LLM = Llama(
model_path="/home/incognito/Downloads/llama-2-7b-chat.ggmlv3.q8_0.gguf.bin",
n_ctx=2048,
)
# create a text prompt
prompt = message
# generate a response (takes several seconds)
output = LLM(prompt)
payload = json.dumps(
{
"messaging_product": "whatsapp",
"to": str(phone_number),
"type": "text",
"text": {
"preview_url": False,
"body": output["choices"][0]["text"],
},
}
)
case "CONTACT_US":
payload = contact_flow_payload
case "TALK_TO_AN_AGENT":
payload = agent_flow_payload
case "FLOW_RESPONSE":
payload = json.dumps(
{
"messaging_product": "whatsapp",
"to": str(phone_number),
"type": "text",
"text": {"preview_url": False, "body": message},
}
)
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer " + ACCESS_TOKEN,
}
requests.request("POST", url, headers=headers, data=payload)
print("MESSAGE SENT")若訊息是簡單的問候語(SEND_GREETINGS_AND_PROMPT),回覆將包含額外的提示(greetings_text_body)。

同樣地,當用戶詢問關於酒店所提供服務的問題時,傳送給用戶的文字訊息(service_intro_text)便會包含相關服務。除了這些服務外,該訊息還會包含一則提示,提醒用戶選擇是否想與客戶服務人員交流。

若輸入內容需要聊天機械人作出回覆(CHATBOT),則您需要初始化該模型、為其提供訊息內容,並處理需要傳回給用戶的回覆。FLOW_RESPONSE 會顯示 Flows 流程所擷取的回覆。
CONTACT_US 和 TALK_TO_AN_AGENT 等其他選項則會將 Flows 流程裝載傳送至用戶。Flows 流程裝載來自 flow_details 函數,其主體如下所示。此裝載包含 Flows 流程的必要詳情,包括 FLOW_ID;您可以從 WhatsApp Business 帳戶的「流程」頁面獲取此類資訊。此外,您也可以在環境變數中定義這些編號。
def flow_details(flow_header,
flow_body,
flow_footer,
flow_id,
flow_cta,
recipient_phone_number,
screen_id
):
# Generate a random UUID for the flow token
flow_token = str(uuid.uuid4())
flow_payload = json.dumps({
"type": "flow",
"header": {
"type": "text",
"text": flow_header
},
"body": {
"text": flow_body
},
"footer": {
"text": flow_footer
},
"action": {
"name": "flow",
"parameters": {
"flow_message_version": "3",
"flow_token": flow_token,
"flow_id": flow_id,
"flow_cta": flow_cta,
"flow_action": "navigate",
"flow_action_payload": {
"screen": screen_id
}
}
}
})
payload = json.dumps({
"messaging_product": "whatsapp",
"recipient_type": "individual",
"to": str(recipient_phone_number),
"type": "interactive",
"interactive": json.loads(flow_payload)
})
return payload
此方法可產生隨機 UUID 以建立 action.parameters.flow_token。系統會將 action.parameters.flow_action_payload.screen 傳遞為參數(screen_id)。在理想情況下,它應代表執行 action.parameters.flow_cta 時,您想要向用戶顯示的初始畫面之編號。
最後,新增 Webhook 路線。當您在 Meta for Developers 將 Webhook 加至自家應用程式時,程式碼便會發起 Webhook GET 要求。若要求成功,系統便會傳回要求的 hub.challenge。
@app.route("/webhook", methods=["GET"])
def webhook_get():
if request.method == "GET":
if (
request.args.get("hub.mode") == "subscribe"
and request.args.get("hub.verify_token") == TOKEN
):
return make_response(request.args.get("hub.challenge"), 200)
else:
return make_response("Success", 403)
POST 要求會使用上文所述的 user_message_processor 方法來擷取並處理訊息裝載。由於此程式碼僅用於處理訊息裝載,因此擷取任何其他裝載時會出現錯誤。因此,您可使用 if 陳述式來檢查是否存在 messages 主體。
@app.route("/webhook", methods=["POST"])
def webhook_post():
if request.method == "POST":
request_data = json.loads(request.get_data())
if (
request_data["entry"][0]["changes"][0]["value"].get("messages")
) is not None:
name = request_data["entry"][0]["changes"][0]["value"]["contacts"][0][
"profile"
]["name"]
if (
request_data["entry"][0]["changes"][0]["value"]["messages"][0].get(
"text"
)
) is not None:
message = request_data["entry"][0]["changes"][0]["value"]["messages"][
0
]["text"]["body"]
user_phone_number = request_data["entry"][0]["changes"][0]["value"][
"contacts"
][0]["wa_id"]
user_message_processor(message, user_phone_number, name)
else:
# checking that there is data in a flow's response object before processing it
if (
request_data["entry"][0]["changes"][0]["value"]["messages"][0][
"interactive"
]["nfm_reply"]["response_json"]
) is not None:
flow_reply_processor(request)
return make_response("PROCESSED", 200)
此外,您可以使用名為 flow_reply_processor 的協助工具函數,從 Flows 流程中擷取回覆並將其傳回給用戶:
def flow_reply_processor(request):
request_data = json.loads(request.get_data())
name = request_data["entry"][0]["changes"][0]["value"]["contacts"][0]["profile"]["name"]
message = request_data["entry"][0]["changes"][0]["value"]["messages"][0]["interactive"]["nfm_reply"][
"response_json"]
flow_message = json.loads(message)
flow_key = flow_message["flow_key"]
if flow_key == "agentconnect":
firstname = flow_message["firstname"]
reply = f"Thank you for reaching out {firstname}. An agent will reach out to you the soonest"
else:
firstname = flow_message["firstname"]
secondname = flow_message["secondname"]
issue = flow_message["issue"]
reply = f"Your response has been recorded. This is what we received:\n\n*NAME*: {firstname} {secondname}\n*YOUR MESSAGE*: {issue}"
user_phone_number = request_data["entry"][0]["changes"][0]["value"]["contacts"][0][
"wa_id"]
send_message(reply, user_phone_number, "FLOW_RESPONSE", name)
此函數會使用 flow_key 鍵來區分這兩個 Flows 流程,並相應地擷取回覆,同時傳遞正確的首個畫面編號。
在執行程式碼前,將其與完整版本加以比較,並確認所有元素均為一致。
在繼續操作之前,先從您的終端執行此指令:
flask --app main run --port 5000
若執行成功,您應該會看到下列訊息:
* Running on http://127.0.0.1:5000
接下來,執行 ngrok http 5000 以取得與您應用程式相應的網址。複製此連結。
接著,前往您的 Meta for Developers 開發人員帳戶,點擊左側導覽面板中「WhatsApp」下方的「配置」選單:

在「Webhook」小卡片中,點擊「編輯」。
然後,在所開啟對話框的「回調網址」欄位中,貼上所複製的網址並附上 /webhook。
在「驗證憑證」欄位中,加入 .env 檔案的 TOKEN 變數所提供的憑證。點擊「驗證並儲存」以關閉對話框。
現在,在同一個小卡片中,點擊「管理」並檢查「訊息」欄位。該小卡片應如下所示:

Webhook 現已就緒。
您可以向自己的帳戶號碼傳送一則訊息,如「您好」。您應該會收到正確的回覆。嘗試使用選單所顯示的提示來回覆,以測試 Flows 流程:

以下是另一個螢幕截圖,當中顯示了聊天機械人的回覆。用戶要求簡單地翻譯一些內容,而聊天機械人可以做到這一點。

WhatsApp Flows 是一款供企業蒐集結構化資料的強大工具,有助改善顧客互動,並簡化企業與消費者之間的溝通交流。建立 Flows 流程的方式之一是使用 WhatsApp 管理工具的流程建造工具;該工具提供簡單易用的 Flows 流程設計介面。
本文的示範應用程式概要地介紹了如何利用 WhatsApp Flows,從而改善顧客互動及進行以資料為本的分析。若要用於更具體的專業用途,您亦可配置 Llama 2 和 WhatsApp Flows,將聊天機械人連結至自訂模型,或者使用專有資料來源來予以訓練,使其能夠回答有關您商品及其他功能的自然語言問題。
立即使用 WhatsApp Flows,改進顧客互動體驗並簡化應用程式的資料蒐集流程。立即試用。
訂閱以接收 Meta for Developers 的每月最新消息。