Chat AIMô hìnhGiáTài liệuHướng dẫn

Làm chatbot Zalo OA trả lời khách bằng AI (GPT, Claude)

Tạo Zalo Official Account, đăng ký ứng dụng trên Zalo for Developers, lấy access token và khai báo webhook URL trỏ về server của bạn. Server Python nhận tin nhắn, gọi OpenAI SDK tới https://api.macloudai.com/v1 để AI soạn câu trả lời, rồi gửi lại qua API gửi tin của Zalo. Chi phí mỗi tin tính theo token.

Cập nhật 2026-11-01 · MaCloud AI

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/v1 và 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

  1. 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.
  2. 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.
  3. 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.
  4. Đă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 đủ.
  5. 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).
  6. 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.
  7. 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ìnhMỗi lượt chat1.000 lượt chat
GEM 3.8 Flash7 ₫7.389 ₫
TT-6 Luna18 ₫17.738 ₫
TT-6.1 Terra12 ₫12.105 ₫
HK-5.56 ₫5.808 ₫
GEM 4 Argon141 ₫141.087 ₫
TT-6.1 Sol24 ₫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 history trong 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 429 thì đợi rồi thử lại; lỗi 403 thườ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.

Câu hỏi thường gặp

Q1Có cần biết lập trình để làm chatbot Zalo bằng AI không?
Cần biết cơ bản để chạy một server Python và khai báo webhook. Phần gọi AI trong bài đã viết sẵn, bạn chủ yếu sửa system prompt cho đúng shop của mình.
Q2Dùng GPT hay Claude cho chatbot bán hàng?
Cả hai đều dùng được với cùng một key. Hãy thử vài chục câu hỏi thật của khách với từng mô hình, so cách trả lời và chi phí ở mục Mức dùng rồi chọn.
Q3Nội dung chat của khách có bị lưu lại không?
MaCloud AI không lưu nội dung hội thoại, chỉ ghi số token, tên mô hình và thời gian để tính phí. Dữ liệu bạn tự lưu trên server của mình thì do bạn quản lý.
Q4Địa chỉ API gửi tin nhắn của Zalo là gì?
Xem trong tài liệu chính thức của Zalo for Developers. Zalo có thể thay đổi endpoint và tham số, nên bài này không ghi cụ thể.
Q5Hết số dư thì chatbot sẽ thế nào?
Yêu cầu gọi AI bị từ chối với lỗi 403. Code mẫu sẽ gửi câu "nhân viên sẽ trả lời sớm". Nạp thêm là bot chạy lại ngay.

Hướng dẫn khác