Nâng caoHướng dẫnClaude APINguồn: Anthropic

Zalo Mini App + Claude — Xây dựng trợ lý tư vấn sản phẩm thông minh

Nghe bài viết
00:00

Điểm nổi bật

Nhấn để đến mục tương ứng

  1. 1 Mẫu đầu tiên đang giảm giá 20% nè!", "products": ["SKU001", "SKU045", "SKU078"] } Kịch bản 2: Khách cần tư vấn Khách mô tả nhu cầu chung, Claude hỏi thêm để hiểu rõ rồi mới gợi ý.
  2. 2 Claude xử lý dựa trên dữ liệu đơn hàng và chính sách cửa hàng.
  3. 3 Tìm kiếm catalog sản phẩm Để Claude tư vấn chính xác, bạn cần truyền catalog sản phẩm phù hợp vào context.
  4. 4 Đơn vị tiền tệ và format số Luôn hiển thị giá bằng VND, format có dấu chấm ngăn cách hàng nghìn (ví dụ: 1.299.000d).
  5. 5 Khi khách chọn sản phẩm, Claude hướng dẫn các bước tiếp theo: Bổ sung vào system prompt: Khi khách muốn đặt hàng: 1.
black and silver laptop computer

Zalo là nền tảng nhắn tin phổ biến nhất Việt Nam với hơn 75 triệu người dùng. Zalo Mini App cho phép doanh nghiệp xây dựng ứng dụng nhẹ chạy trực tiếp trong Zalo mà không cần cài đặt riêng. Khi kết hợp với Claude API, bạn có thể tạo ra một trợ lý tư vấn sản phẩm thông minh, hiểu ngữ cảnh tiếng Việt và đưa ra gợi ý phù hợp cho từng khách hàng.

Tổng quan Zalo Mini App SDK

Zalo Mini App là framework cho phép phát triển ứng dụng web chạy trong hệ sinh thái Zalo. Kiến trúc gồm ba thành phần chính:

  • Frontend (Mini App): Giao diện người dùng viết bằng HTML, CSS, JavaScript hoặc framework như React. Chạy trong WebView của Zalo.
  • Zalo SDK: Cung cấp API truy cập thông tin người dùng, thanh toán ZaloPay, chia sẻ, thông báo và các tính năng native của Zalo.
  • Backend Server: Server riêng của bạn xử lý logic nghiệp vụ, lưu trữ dữ liệu và tích hợp Claude API.

Một số khả năng quan trọng của Zalo Mini App SDK:

  • Xác thực người dùng qua Zalo OAuth — lấy được tên, avatar, số điện thoại (nếu người dùng cho phép)
  • Gửi thông báo (notification) đến người dùng qua Zalo OA
  • Thanh toán trực tiếp qua ZaloPay
  • Chia sẻ nội dung lên Zalo feed hoặc nhóm chat
  • Truy cập vị trí, camera, và các API thiết bị

Kiến trúc hệ thống tổng thể

Luồng hoạt động của trợ lý tư vấn sản phẩm:

  1. Khách hàng mở Mini App trong Zalo, xác thực tự động qua Zalo OAuth
  2. Giao diện chat hiển thị, khách hàng nhập câu hỏi hoặc mô tả nhu cầu
  3. Frontend gửi tin nhắn đến backend server qua REST API hoặc WebSocket
  4. Backend xử lý: tìm kiếm catalog sản phẩm, xây dựng context, gọi Claude API
  5. Claude phân tích nhu cầu, đối chiếu với catalog, trả về gợi ý sản phẩm kèm lý do
  6. Backend format kết quả và gửi về frontend hiển thị dạng card sản phẩm

Cấu trúc thư mục dự án

zalo-product-advisor/
  ├── mini-app/                 # Zalo Mini App frontend
  │   ├── src/
  │   │   ├── pages/
  │   │   │   ├── chat.jsx      # Giao diện chat chính
  │   │   │   └── product.jsx   # Chi tiết sản phẩm
  │   │   ├── components/
  │   │   │   ├── ChatBubble.jsx
  │   │   │   ├── ProductCard.jsx
  │   │   │   └── QuickReply.jsx
  │   │   └── utils/
  │   │       └── zalo-sdk.js   # Wrapper cho Zalo SDK
  │   └── app-config.json
  ├── server/                   # Backend Node.js
  │   ├── routes/
  │   │   ├── chat.js           # API xử lý tin nhắn
  │   │   └── products.js       # API sản phẩm
  │   ├── services/
  │   │   ├── claude.js         # Tích hợp Claude API
  │   │   ├── catalog.js        # Tìm kiếm catalog
  │   │   └── conversation.js   # Quản lý lịch sử hội thoại
  │   └── server.js
  └── package.json

Tích hợp Claude API cho tư vấn sản phẩm

Phần cốt lõi của hệ thống là cách bạn thiết kế system prompt và truyền dữ liệu sản phẩm cho Claude. Dưới đây là module tích hợp Claude API:

// server/services/claude.js
const Anthropic = require("@anthropic-ai/sdk");

const client = new Anthropic({ apiKey: process.env.CLAUDE_API_KEY });

const SYSTEM_PROMPT = [
  "Bạn là trợ lý tư vấn sản phẩm cho cửa hàng. Nhiệm vụ:",
  "- Hiểu nhu cầu khách hàng qua hội thoại tự nhiên bằng tiếng Việt",
  "- Gợi ý sản phẩm phù hợp từ catalog được cung cấp",
  "- Giải thích lý do gợi ý ngắn gọn, thân thiện",
  "- Nếu không có sản phẩm phù hợp, nói rõ và đề xuất thay thế",
  "- Không bịa thông tin sản phẩm ngoài catalog",
  '- Trả lời JSON với format: {"message": "...", "products": [...]}',
  "",
  "Quy tắc giao tiếp:",
  '- Xưng "mình", gọi khách là "bạn"',
  "- Ngắn gọn, không quá 3 câu cho phần message",
  "- Hỏi thêm nếu chưa đủ thông tin để tư vấn"
].join("\n");

async function getProductAdvice(conversationHistory, catalogContext) {
  const messages = conversationHistory.map(msg => ({
    role: msg.role,
    content: msg.content
  }));

  const systemWithCatalog = SYSTEM_PROMPT +
    "\n\nCatalog sản phẩm hiện có:\n" + catalogContext;

  const response = await client.messages.create({
    model: "claude-sonnet-4-20250514",
    max_tokens: 1024,
    system: systemWithCatalog,
    messages: messages
  });

  return JSON.parse(response.content[0].text);
}

module.exports = { getProductAdvice };

Thiết kế luồng hội thoại (Conversation Flow)

Một trợ lý tư vấn hiệu quả cần có luồng hội thoại rõ ràng. Dưới đây là các kịch bản chính:

Kịch bản 1: Khách biết rõ cần gì

Khách hàng mô tả cụ thể sản phẩm mong muốn. Claude tìm kiếm trong catalog và trả về kết quả ngay.

// Ví dụ hội thoại
Khách: "Tìm giúp mình áo thun cotton trắng size L, giá dưới 300k"
Claude: {
  "message": "Mình tìm được 3 áo thun cotton trắng size L dưới 300k cho bạn. Mẫu đầu tiên đang giảm giá 20% nè!",
  "products": ["SKU001", "SKU045", "SKU078"]
}

Kịch bản 2: Khách cần tư vấn

Khách mô tả nhu cầu chung, Claude hỏi thêm để hiểu rõ rồi mới gợi ý.

// Ví dụ hội thoại nhiều lượt
Khách: "Mình muốn mua quà sinh nhật cho bạn gái"
Claude: {
  "message": "Hay quá! Bạn gái bạn thích phong cách nào? Thời trang, phụ kiện hay mỹ phẩm? Budget bạn dự kiến bao nhiêu?",
  "products": []
}

Khách: "Cô ấy thích phong cách minimalist, budget khoảng 500k"
Claude: {
  "message": "Với phong cách minimalist và budget 500k, mình gợi ý 3 món quà này. Túi canvas và vòng tay bạc đang được nhiều bạn chọn làm quà tặng nhất!",
  "products": ["SKU120", "SKU089", "SKU203"]
}

Kịch bản 3: Hỗ trợ đơn hàng

Khách hỏi về tình trạng đơn hàng, đổi trả hoặc chính sách. Claude xử lý dựa trên dữ liệu đơn hàng và chính sách cửa hàng.

Tìm kiếm catalog sản phẩm

Để Claude tư vấn chính xác, bạn cần truyền catalog sản phẩm phù hợp vào context. Không nên đưa toàn bộ catalog (có thể hàng nghìn sản phẩm) mà cần lọc trước:

// server/services/catalog.js

async function searchCatalog(userMessage, filters = {}) {
  // Bước 1: Trích xuất keyword từ tin nhắn
  const keywords = extractKeywords(userMessage);

  // Bước 2: Tìm kiếm trong database
  let query = Product.find({
    $text: { $search: keywords.join(" ") },
    status: "active"
  });

  // Áp dụng filter nếu có
  if (filters.category) query = query.where("category", filters.category);
  if (filters.maxPrice) query = query.where("price").lte(filters.maxPrice);
  if (filters.minPrice) query = query.where("price").gte(filters.minPrice);

  // Bước 3: Giới hạn kết quả và format cho Claude
  const products = await query.limit(20).lean();

  return products.map(p => ({
    sku: p.sku,
    name: p.name,
    price: p.price,
    description: p.shortDescription,
    category: p.category,
    inStock: p.inventory > 0,
    rating: p.averageRating
  }));
}

function formatCatalogForClaude(products) {
  return products.map(p =>
    "[" + p.sku + "] " + p.name + " - " + p.price.toLocaleString() + "d | " + p.category + " | " + (p.inStock ? "Con hang" : "Het hang") + " | Rating: " + p.rating + "/5"
  ).join("\n");
}

module.exports = { searchCatalog, formatCatalogForClaude };

Quản lý lịch sử hội thoại

Để Claude hiểu ngữ cảnh xuyên suốt cuộc trò chuyện, bạn cần lưu và quản lý lịch sử hội thoại:

// server/services/conversation.js
const Redis = require("ioredis");
const redis = new Redis(process.env.REDIS_URL);

const MAX_HISTORY = 20;  // Giới hạn số tin nhắn
const TTL = 3600;         // Hết hạn sau 1 giờ

async function getHistory(sessionId) {
  const data = await redis.get(`conv:${sessionId}`);
  return data ? JSON.parse(data) : [];
}

async function addMessage(sessionId, role, content) {
  const history = await getHistory(sessionId);
  history.push({ role, content, timestamp: Date.now() });

  // Giữ lại MAX_HISTORY tin nhắn gần nhất
  const trimmed = history.slice(-MAX_HISTORY);
  await redis.setex(`conv:${sessionId}`, TTL, JSON.stringify(trimmed));
  return trimmed;
}

async function clearHistory(sessionId) {
  await redis.del(`conv:${sessionId}`);
}

module.exports = { getHistory, addMessage, clearHistory };

API endpoint xử lý tin nhắn

Route chính kết nối tất cả các module lại với nhau:

// server/routes/chat.js
const express = require("express");
const router = express.Router();
const { getProductAdvice } = require("../services/claude");
const { searchCatalog, formatCatalogForClaude } = require("../services/catalog");
const { getHistory, addMessage } = require("../services/conversation");

router.post("/api/chat", async (req, res) => {
  try {
    const { sessionId, message, userId } = req.body;

    // Lưu tin nhắn người dùng
    await addMessage(sessionId, "user", message);

    // Tìm sản phẩm liên quan
    const products = await searchCatalog(message);
    const catalogContext = formatCatalogForClaude(products);

    // Lấy lịch sử và gọi Claude
    const history = await getHistory(sessionId);
    const response = await getProductAdvice(history, catalogContext);

    // Lưu phản hồi
    await addMessage(sessionId, "assistant", JSON.stringify(response));

    // Enrich product data cho frontend
    const enrichedProducts = response.products.map(sku => {
      const product = products.find(p => p.sku === sku);
      return product || null;
    }).filter(Boolean);

    res.json({
      message: response.message,
      products: enrichedProducts
    });
  } catch (error) {
    console.error("Chat error:", error);
    res.status(500).json({ message: "Xin lỗi, hệ thống đang bận. Vui lòng thử lại sau." });
  }
});

module.exports = router;

Giao diện chat trên Zalo Mini App

Frontend cần tối ưu cho trải nghiệm trong Zalo. Một số lưu ý quan trọng:

  • Zalo Mini App chạy trong WebView nên cần test kỹ trên nhiều thiết bị Android và iOS
  • Sử dụng Zalo Design System để giao diện nhất quán với Zalo
  • Hỗ trợ Quick Reply buttons để khách dễ tương tác hơn
  • Hiển thị sản phẩm dạng card ngang có thể vuốt (swipeable carousel)
// mini-app/src/pages/chat.jsx
import { useEffect, useState, useRef } from "react";
import { getAccessToken } from "../utils/zalo-sdk";
import ChatBubble from "../components/ChatBubble";
import ProductCard from "../components/ProductCard";
import QuickReply from "../components/QuickReply";

function ChatPage() {
  const [messages, setMessages] = useState([]);
  const [input, setInput] = useState("");
  const [loading, setLoading] = useState(false);
  const chatEndRef = useRef(null);

  const quickReplies = [
    "Sản phẩm bán chạy nhất",
    "Đang có khuyến mãi gì?",
    "Tư vấn quà tặng",
    "Kiểm tra đơn hàng"
  ];

  async function sendMessage(text) {
    const userMsg = { role: "user", content: text };
    setMessages(prev => [...prev, userMsg]);
    setInput("");
    setLoading(true);

    try {
      const token = await getAccessToken();
      const res = await fetch(`${API_URL}/api/chat`, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "Authorization": `Bearer ${token}`
        },
        body: JSON.stringify({
          sessionId: token,
          message: text
        })
      });
      const data = await res.json();

      setMessages(prev => [...prev, {
        role: "assistant",
        content: data.message,
        products: data.products
      }]);
    } catch {
      setMessages(prev => [...prev, {
        role: "assistant",
        content: "Xin lỗi, mình chưa xử lý được. Bạn thử lại nhé!"
      }]);
    } finally {
      setLoading(false);
    }
  }

  useEffect(() => {
    chatEndRef.current?.scrollIntoView({ behavior: "smooth" });
  }, [messages]);

  return (
    <div className="chat-container">
      <div className="messages">
        {messages.map((msg, i) => (
          <div key={i}>
            <ChatBubble message={msg} />
            {msg.products?.length > 0 && (
              <div className="product-carousel">
                {msg.products.map(p => (
                  <ProductCard key={p.sku} product={p} />
                ))}
              </div>
            )}
          </div>
        ))}
        <div ref={chatEndRef} />
      </div>

      {messages.length === 0 && (
        <QuickReply options={quickReplies} onSelect={sendMessage} />
      )}

      <div className="input-area">
        <input value={input} onChange={e => setInput(e.target.value)}
          placeholder="Bạn cần tư vấn gì?" />
        <button onClick={() => sendMessage(input)} disabled={loading}>
          Gửi
        </button>
      </div>
    </div>
  );
}

Xử lý đặc thù tiếng Việt

Khi xây dựng trợ lý tư vấn cho người dùng Việt Nam, bạn cần lưu ý một số đặc thù về ngôn ngữ và văn hóa:

Xử lý viết tắt và tiếng lóng

Người dùng Zalo thường viết tắt hoặc dùng tiếng lóng. Bạn nên có một lớp tiền xử lý:

// Bảng mapping viết tắt phổ biến
const ABBREVIATIONS = {
  "ko": "không", "k": "không", "hok": "không",
  "dc": "được", "đc": "được",
  "j": "gì", "g": "gì",
  "bn": "bao nhiêu", "nhiu": "nhiêu",
  "sp": "sản phẩm",
  "ship": "giao hàng",
  "dt": "điện thoại",
  "tks": "cảm ơn", "tk": "cảm ơn"
};

function normalizeVietnamese(text) {
  let normalized = text.toLowerCase().trim();
  for (const [abbr, full] of Object.entries(ABBREVIATIONS)) {
    const regex = new RegExp(`\\b${abbr}\\b`, "gi");
    normalized = normalized.replace(regex, full);
  }
  return normalized;
}

Xưng hô phù hợp

Claude cần xưng hô phù hợp với văn hóa Việt Nam. Trong system prompt, quy định rõ cách xưng hô. Với đa số cửa hàng thương mại điện tử, xưng "mình" gọi "bạn" là lựa chọn an toàn và thân thiện. Tuy nhiên, nếu thương hiệu cao cấp, có thể chuyển sang "chúng tôi" gọi "anh/chị".

Đơn vị tiền tệ và format số

Luôn hiển thị giá bằng VND, format có dấu chấm ngăn cách hàng nghìn (ví dụ: 1.299.000d). Claude cần được hướng dẫn format giá đúng chuẩn Việt Nam trong system prompt.

Hỗ trợ đặt hàng

Ngoài tư vấn, trợ lý có thể hỗ trợ quy trình đặt hàng. Khi khách chọn sản phẩm, Claude hướng dẫn các bước tiếp theo:

Bổ sung vào system prompt:

Khi khách muốn đặt hàng:
1. Xác nhận sản phẩm, số lượng, size/màu (nếu có)
2. Hỏi địa chỉ giao hàng
3. Thông báo phí ship và tổng tiền
4. Hướng dẫn thanh toán qua ZaloPay hoặc COD
5. Tạo đơn hàng và gửi mã đơn cho khách

Format khi tạo đơn:
{"action": "create_order", "items": [...], "address": "...", "payment": "..."}

Triển khai và vận hành

Đăng ký Zalo Mini App

  1. Tạo tài khoản developer tại developers.zalo.me
  2. Tạo ứng dụng mới, chọn loại "Mini App"
  3. Cấu hình domain cho server backend
  4. Submit Mini App để Zalo review (thường mất 3-5 ngày làm việc)

Cấu hình môi trường

# .env cho backend server
CLAUDE_API_KEY=sk-ant-api03-...
ZALO_APP_ID=your_app_id
ZALO_APP_SECRET=your_app_secret
REDIS_URL=redis://localhost:6379
MONGODB_URI=mongodb://localhost:27017/product-advisor
PORT=3000

Tối ưu hiệu năng

  • Cache kết quả tìm kiếm: Cache catalog search results trong Redis với TTL 5-10 phút để giảm tải database
  • Streaming response: Sử dụng Claude streaming API để hiển thị phản hồi dần dần, cải thiện trải nghiệm chờ đợi
  • Rate limiting: Giới hạn số tin nhắn mỗi người dùng (ví dụ: 30 tin nhắn/phút) để kiểm soát chi phí API
  • Fallback: Khi Claude API không khả dụng, chuyển sang tìm kiếm catalog đơn giản và hiển thị kết quả không có tư vấn AI

Monitoring và analytics

Theo dõi các chỉ số quan trọng:

  • Số phiên hội thoại mỗi ngày và tỷ lệ chuyển đổi sang đặt hàng
  • Thời gian phản hồi trung bình của Claude API
  • Tỷ lệ câu hỏi mà Claude không trả lời được (cần cải thiện prompt hoặc catalog)
  • Chi phí API Claude theo ngày/tuần/tháng
  • Top 10 loại câu hỏi phổ biến nhất (để tối ưu quick replies và catalog)

Bảo mật và quyền riêng tư

Khi xử lý dữ liệu người dùng Zalo, cần tuân thủ:

  • Chỉ thu thập dữ liệu cần thiết cho việc tư vấn, không lưu trữ thông tin nhạy cảm
  • Tự động xóa lịch sử hội thoại sau thời gian quy định (TTL trong Redis)
  • Không gửi thông tin cá nhân (số điện thoại, địa chỉ) vào Claude API — chỉ gửi nội dung tin nhắn và catalog
  • Tuân thủ chính sách bảo mật của Zalo Platform và Nghị định 13/2023/ND-CP về bảo vệ dữ liệu cá nhân
  • Mã hóa dữ liệu truyền tải giữa Mini App, backend server và Claude API bằng HTTPS/TLS

Kiểm thử trước khi phát hành

Trước khi submit lên Zalo Store, cần kiểm thử kỹ lưỡng:

  • Test trên nhiều thiết bị Android (Samsung, Oppo, Xiaomi) và iOS với các phiên bản Zalo khác nhau
  • Kiểm tra xử lý lỗi khi mất mạng, API timeout, hoặc Claude trả về format sai
  • Test với các trường hợp biên: tin nhắn rỗng, tin nhắn quá dài, ký tự đặc biệt, nhiều ngôn ngữ
  • Load test với số lượng người dùng đồng thời dự kiến
  • Kiểm tra trải nghiệm khi catalog sản phẩm rỗng hoặc tất cả sản phẩm hết hàng

Chi phí vận hành ước tính

Với một cửa hàng có khoảng 1.000 phiên hội thoại mỗi ngày, mỗi phiên trung bình 5 lượt trao đổi:

  • Claude API (Sonnet): khoảng 150-300 USD/tháng tùy độ dài tin nhắn
  • Server (VPS 2 CPU, 4GB RAM): khoảng 200.000-500.000 VND/tháng
  • Redis Cloud: miễn phí cho tier cơ bản hoặc khoảng 5-10 USD/tháng
  • Tổng cộng: khoảng 5-10 triệu VND/tháng — khá hợp lý so với chi phí thuê nhân viên tư vấn

Bước tiếp theo

Bạn đã nắm được cách xây dựng trợ lý tư vấn sản phẩm thông minh trên Zalo Mini App với Claude. Để nâng cao hệ thống, hãy cân nhắc thêm các tính năng như gợi ý sản phẩm dựa trên lịch sử mua hàng, tích hợp ZaloPay cho thanh toán trong chat, và A/B testing các phiên bản system prompt khác nhau. Tham khảo thêm tại Thư viện Ứng dụng Claude.

Tính năng liên quan:Zalo Mini AppProduct RecommendationConversation FlowVietnamese UX

Bai viet co huu ich khong?

Bản quyền thuộc về tác giả. Vui lòng dẫn nguồn khi chia sẻ.

Bình luận (0)
Ảnh đại diện
Đăng nhập để bình luận...
Đăng nhập để bình luận
  • Đang tải bình luận...

Đăng ký nhận bản tin

Nhận bài viết hay nhất về sản phẩm và vận hành, gửi thẳng vào hộp thư của bạn.

Bảo mật thông tin. Hủy đăng ký bất cứ lúc nào. Chính sách bảo mật.