Chatbot này hoạt động thế nào?
Ví dụ: shop thời trang Mây ở TP.HCM bán online, mỗi tối nhận hàng trăm tin nhắn Zalo hỏi size, giá ship, còn màu không. Chủ shop muốn AI trả lời trước những câu lặp lại, câu khó thì để nhân viên xử lý sáng hôm sau.
Luồng xử lý gồm bốn bước:
- Khách nhắn tin cho Zalo OA của shop.
- Zalo gửi sự kiện đó tới webhook URL của bạn, tức một server Python nhỏ.
- Server lấy nội dung tin nhắn, gọi AI qua OpenAI SDK với base URL
https://api.macloudai.com/v1và một API key MaCloud AI. - Server gửi câu trả lời của AI lại cho khách qua API gửi tin nhắn của Zalo OA.
Phần AI (bước 3) là code của bạn và được viết đầy đủ ở dưới. Phần Zalo (bước 2 và 4) làm theo tài liệu chính thức của Zalo, vì Zalo có thể thay đổi giao diện và API.
Các bước thiết lập
- Tạo Zalo Official Account cho shop trên trang Zalo OA và hoàn tất các bước xác thực mà Zalo yêu cầu.
- Vào Zalo for Developers, tạo ứng dụng mới và liên kết ứng dụng với Official Account của shop.
- Trong trang quản lý ứng dụng, lấy access token của OA theo hướng dẫn của Zalo. Lưu nó vào biến môi trường, không ghi thẳng vào code.
- Đăng ký MaCloud AI, vào API Key tạo một key tên
zalo-shop-may, và nạp số dư nếu khoản dùng thử không đủ. - Chạy server Python ở bên dưới trên một máy có địa chỉ HTTPS công khai (VPS hoặc dịch vụ hosting).
- Trong trang quản lý ứng dụng Zalo, khai báo webhook URL là địa chỉ server, ví dụ
https://ten-mien-cua-ban/zalo/webhook, và bật sự kiện nhận tin nhắn văn bản từ người dùng. - Dùng một tài khoản Zalo khác nhắn thử cho OA, xem câu trả lời và kiểm tra chi phí ở mục Mức dùng.
Tên trường trong dữ liệu webhook, địa chỉ endpoint gửi tin nhắn, cách làm mới access token và các bước xác minh tên miền đều phải xem trong tài liệu chính thức của Zalo for Developers. Bài này không ghi các địa chỉ đó để tránh sai khi Zalo cập nhật.
Code server Python
Cài thư viện: pip install flask openai. Đặt biến môi trường MACLOUD_API_KEY (key sk-...) và ZALO_ACCESS_TOKEN. Lưu code thành bot.py:
import os
from flask import Flask, request, jsonify
from openai import OpenAI
client = OpenAI(base_url="https://api.macloudai.com/v1", api_key=os.environ["MACLOUD_API_KEY"])
MODEL = os.environ.get("MODEL", "tt-6-luna")
SYSTEM_PROMPT = (
"Bạn là nhân viên tư vấn của shop thời trang Mây ở TP.HCM, bán quần áo nữ online. "
"Trả lời ngắn gọn, thân thiện, xưng shop và gọi khách là bạn. "
"Size: S (45-50kg), M (50-55kg), L (55-60kg). Ship nội thành TP.HCM 1-2 ngày, tỉnh khác 3-5 ngày. "
"Không tự bịa giá hay khuyến mãi. Câu nào không chắc thì nói nhân viên sẽ trả lời sớm."
)
app = Flask(__name__)
history = {} # user_id -> các tin nhắn gần nhất
def ask_ai(user_id, text):
msgs = history.setdefault(user_id, [])
msgs.append({"role": "user", "content": text})
del msgs[:-10] # chỉ giữ 10 tin gần nhất để tiết kiệm token
r = client.chat.completions.create(
model=MODEL,
messages=[{"role": "system", "content": SYSTEM_PROMPT}] + msgs,
max_tokens=400,
)
answer = r.choices[0].message.content
msgs.append({"role": "assistant", "content": answer})
return answer
def parse_zalo_event(payload):
# Lấy ID người gửi và nội dung tin nhắn văn bản.
# Tên sự kiện và tên trường: kiểm tra lại theo tài liệu webhook của Zalo OA.
if payload.get("event_name") != "user_send_text":
return None, None
user_id = (payload.get("sender") or {}).get("id")
text = (payload.get("message") or {}).get("text")
return user_id, text
def send_zalo_message(user_id, text):
# Gửi tin nhắn qua API của Zalo OA bằng os.environ["ZALO_ACCESS_TOKEN"].
# Địa chỉ endpoint, header và cấu trúc body: xem tài liệu chính thức của Zalo.
# Khi chưa nối Zalo, in ra màn hình để thử phần AI.
print(f"[gửi tới {user_id}] {text}")
@app.post("/zalo/webhook")
def webhook():
payload = request.get_json(silent=True) or {}
user_id, text = parse_zalo_event(payload)
if user_id and text:
try:
reply = ask_ai(user_id, text)
except Exception as e:
print("Lỗi gọi AI:", e)
reply = "Shop đang bận một chút, nhân viên sẽ trả lời bạn sớm nhé."
send_zalo_message(user_id, reply)
return jsonify(ok=True)
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000)
Chạy python bot.py, rồi mở terminal khác gửi thử một sự kiện giả để kiểm tra phần AI trước khi nối Zalo:
curl -X POST http://localhost:8000/zalo/webhook \
-H "Content-Type: application/json" \
-d '{"event_name": "user_send_text", "sender": {"id": "test-1"}, "message": {"text": "Mình nặng 52kg mặc size gì?"}}'
Nếu terminal chạy server in ra câu trả lời, phần AI đã chạy. Việc còn lại là viết thân hàm send_zalo_message theo tài liệu gửi tin của Zalo.
Viết system prompt cho shop thế nào?
- Ghi rõ shop bán gì, ở đâu, giọng xưng hô (shop / bạn, em / anh chị) đúng như cách shop vẫn nhắn với khách.
- Đưa thông tin cố định vào: bảng size, thời gian ship, chính sách đổi trả.
- Cấm AI tự bịa giá, mã giảm giá hay tình trạng còn hàng. Những thông tin hay đổi nên lấy từ hệ thống của shop rồi chèn vào prompt.
- Dặn AI chuyển cho nhân viên khi khách khiếu nại hoặc hỏi ngoài phạm vi.
Mỗi tin nhắn tốn bao nhiêu?
Mỗi lần trả lời, bạn trả token đầu vào (system prompt + lịch sử + tin của khách) và token đầu ra (câu trả lời). Một tin nhắn shop thường chỉ vài trăm đến khoảng hai nghìn token. Giá từng mô hình, tính bằng đồng cho mỗi 1 triệu token:
Giá thực tế hiện tại
Ước tính theo giá ở trang mô hình: mỗi lượt chat 2.000 token input và 500 token output. Số tiền trừ thực tế xem trong bảng điều khiển.
| Mô hình | Mỗi lượt chat | 1.000 lượt chat |
|---|---|---|
| GEM 3.8 Flash | 7 ₫ | 7.389 ₫ |
| TT-6 Luna | 18 ₫ | 17.738 ₫ |
| TT-6.1 Terra | 12 ₫ | 12.105 ₫ |
| HK-5.5 | 6 ₫ | 5.808 ₫ |
| GEM 4 Argon | 141 ₫ | 141.087 ₫ |
| TT-6.1 Sol | 24 ₫ | 24.208 ₫ |
Muốn rẻ hơn: giữ system prompt ngắn, chỉ giữ vài tin gần nhất (code trên giữ 10), đặt max_tokens vừa đủ, và thử mô hình rẻ cho câu hỏi đơn giản. Đổi mô hình chỉ cần đặt biến MODEL, ví dụ deepseek-v4.1-flash hoặc hk-5-5. Cách tính chi tiết xem chi phí API tính theo token.
Đưa lên chạy thật cần lưu ý gì?
- Webhook phải là HTTPS công khai. Chạy trên VPS phía sau Nginx hoặc Caddy có chứng chỉ SSL, hoặc một dịch vụ hosting hỗ trợ Python.
- Biến
historytrong code chỉ nằm trong bộ nhớ, khởi động lại là mất. Chạy thật nên lưu vào Redis hoặc cơ sở dữ liệu. - Nên trả phản hồi cho Zalo nhanh, việc gọi AI có thể đưa vào hàng đợi chạy nền nếu lượng tin lớn.
- Access token của Zalo có thời hạn; cách làm mới xem tài liệu Zalo.
- Gặp lỗi
429thì đợi rồi thử lại; lỗi403thường là hết số dư, hãy nạp thêm trong Nạp tiền.
Mã nguồn tích hợp các công cụ khác (n8n, Cursor, LobeChat) có trong tài liệu.