Xin chào! Tôi là Minh, một lập trình viên đã xây dựng hơn 20 ứng dụng AI trong 3 năm qua. Hôm nay, tôi sẽ chia sẻ với bạn một bài hướng dẫn chi tiết nhất về cách thiết kế database để lưu trữ lịch sử trò chuyện và sở thích người dùng — dành cho người hoàn toàn chưa biết gì về API.

Tại Sao Cần Lưu Trữ Lịch Sử Trò Chuyện?

Khi bạn sử dụng ChatGPT hay Claude, bạn có thể tiếp tục cuộc trò chuyện từ nhiều ngày trước. Đó là vì hệ thống lưu trữ lại toàn bộ tin nhắn. Trong bài viết này, tôi sẽ hướng dẫn bạn tự xây dựng chức năng tương tự.

Trước tiên, bạn cần một tài khoản API để gọi AI. Tôi khuyên dùng HolySheheep AI vì:

Kiến Trúc Database Cơ Bản

Để lưu trữ lịch sử trò chuyện, bạn cần 3 bảng chính:

Bước 1: Cài Đặt Môi Trường

Đầu tiên, tạo thư mục project và cài đặt các thư viện cần thiết:

mkdir ai-chat-app
cd ai-chat-app
npm init -y
npm install express pg sequelize dotenv axios

Bước 2: Thiết Kế Database Với PostgreSQL

Tạo file database.js để kết nối và định nghĩa cấu trúc bảng:

const { Sequelize, DataTypes } = require('sequelize');

// Kết nối PostgreSQL
const sequelize = new Sequelize({
  dialect: 'postgres',
  host: 'localhost',
  port: 5432,
  database: 'ai_chat_db',
  username: 'postgres',
  password: 'your_password',
  logging: false
});

// Định nghĩa bảng Users
const User = sequelize.define('User', {
  id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
  username: { type: DataTypes.STRING, allowNull: false, unique: true },
  email: { type: DataTypes.STRING, allowNull: false, unique: true },
  created_at: { type: DataTypes.DATE, defaultValue: DataTypes.NOW }
});

// Định nghĩa bảng Conversations
const Conversation = sequelize.define('Conversation', {
  id: { type: DataTypes.UUID, defaultValue: DataTypes.UUIDV4, primaryKey: true },
  title: { type: DataTypes.STRING, defaultValue: 'Cuộc trò chuyện mới' },
  user_id: { type: DataTypes.INTEGER, references: { model: User, key: 'id' } }
});

// Định nghĩa bảng Messages
const Message = sequelize.define('Message', {
  id: { type: DataTypes.UUID, defaultValue: DataTypes.UUIDV4, primaryKey: true },
  conversation_id: { type: DataTypes.UUID, references: { model: Conversation, key: 'id' } },
  role: { type: DataTypes.ENUM('user', 'assistant', 'system'), allowNull: false },
  content: { type: DataTypes.TEXT, allowNull: false },
  tokens_used: { type: DataTypes.INTEGER, defaultValue: 0 }
});

// Định nghĩa bảng UserPreferences
const UserPreference = sequelize.define('UserPreference', {
  id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
  user_id: { type: DataTypes.INTEGER, references: { model: User, key: 'id' }, unique: true },
  model_preference: { type: DataTypes.STRING, defaultValue: 'gpt-4.1' },
  temperature: { type: DataTypes.FLOAT, defaultValue: 0.7 },
  max_tokens: { type: DataTypes.INTEGER, defaultValue: 2048 },
  theme: { type: DataTypes.STRING, defaultValue: 'light' },
  language: { type: DataTypes.STRING, defaultValue: 'vi' }
});

// Thiết lập quan hệ
User.hasMany(Conversation, { foreignKey: 'user_id' });
Conversation.belongsTo(User, { foreignKey: 'user_id' });

Conversation.hasMany(Message, { foreignKey: 'conversation_id', onDelete: 'CASCADE' });
Message.belongsTo(Conversation, { foreignKey: 'conversation_id' });

User.hasOne(UserPreference, { foreignKey: 'user_id' });
UserPreference.belongsTo(User, { foreignKey: 'user_id' });

// Khởi tạo database
async function initDatabase() {
  await sequelize.sync({ alter: true });
  console.log('✅ Database đã được khởi tạo thành công!');
}

module.exports = { sequelize, User, Conversation, Message, UserPreference, initDatabase };

Bước 3: Tạo API Server Hoàn Chỉnh

File app.js — Đây là file chính xử lý mọi thứ từ gọi AI đến lưu trữ:

require('dotenv').config();
const express = require('express');
const axios = require('axios');
const { initDatabase, User, Conversation, Message, UserPreference } = require('./database');

const app = express();
app.use(express.json());

// 🎯 Cấu hình HolySheep AI
const HOLYSHEEP_BASE_URL = 'https://api.holysheep.ai/v1';
const HOLYSHEEP_API_KEY = process.env.HOLYSHEEP_API_KEY;

// ============================================
// API 1: Gửi tin nhắn và nhận phản hồi từ AI
// ============================================
app.post('/api/chat', async (req, res) => {
  try {
    const { user_id, conversation_id, message, model } = req.body;

    // 1. Lấy hoặc tạo conversation
    let conversation;
    if (conversation_id) {
      conversation = await Conversation.findByPk(conversation_id);
    } else {
      conversation = await Conversation.create({ user_id });
    }

    // 2. Lấy sở thích người dùng
    const preferences = await UserPreference.findOne({ where: { user_id } });
    const selectedModel = model || preferences?.model_preference || 'gpt-4.1';

    // 3. Lấy lịch sử tin nhắn để gửi context
    const historyMessages = await Message.findAll({
      where: { conversation_id: conversation.id },
      order: [['created_at', 'ASC']]
    });

    // 4. Định dạng messages cho API
    const apiMessages = historyMessages.map(m => ({
      role: m.role,
      content: m.content
    }));
    apiMessages.push({ role: 'user', content: message });

    // 5. Lưu tin nhắn người dùng
    await Message.create({
      conversation_id: conversation.id,
      role: 'user',
      content: message
    });

    // 6. Gọi API HolySheep AI
    const response = await axios.post(
      ${HOLYSHEEP_BASE_URL}/chat/completions,
      {
        model: selectedModel,
        messages: apiMessages,
        temperature: preferences?.temperature || 0.7,
        max_tokens: preferences?.max_tokens || 2048
      },
      {
        headers: {
          'Authorization': Bearer ${HOLYSHEEP_API_KEY},
          'Content-Type': 'application/json'
        }
      }
    );

    const assistantMessage = response.data.choices[0].message.content;
    const tokensUsed = response.data.usage?.total_tokens || 0;

    // 7. Lưu phản hồi AI
    await Message.create({
      conversation_id: conversation.id,
      role: 'assistant',
      content: assistantMessage,
      tokens_used: tokensUsed
    });

    // 8. Trả về kết quả
    res.json({
      success: true,
      conversation_id: conversation.id,
      message: assistantMessage,
      model_used: selectedModel,
      tokens_used: tokensUsed,
      cost_usd: (tokensUsed / 1000000) * getModelPrice(selectedModel)
    });

  } catch (error) {
    console.error('Lỗi:', error.response?.data || error.message);
    res.status(500).json({ success: false, error: error.message });
  }
});

// ============================================
// API 2: Lấy lịch sử cuộc trò chuyện
// ============================================
app.get('/api/conversations/:userId', async (req, res) => {
  try {
    const conversations = await Conversation.findAll({
      where: { user_id: req.params.userId },
      include: [{
        model: Message,
        limit: 1,
        order: [['created_at', 'DESC']]
      }],
      order: [['created_at', 'DESC']]
    });
    res.json({ success: true, conversations });
  } catch (error) {
    res.status(500).json({ success: false, error: error.message });
  }
});

// ============================================
// API 3: Lấy tin nhắn trong cuộc trò chuyện
// ============================================
app.get('/api/messages/:conversationId', async (req, res) => {
  try {
    const messages = await Message.findAll({
      where: { conversation_id: req.params.conversationId },
      order: [['created_at', 'ASC']]
    });
    res.json({ success: true, messages });
  } catch (error) {
    res.status(500).json({ success: false, error: error.message });
  }
});

// ============================================
// API 4: Cập nhật sở thích người dùng
// ============================================
app.put('/api/preferences/:userId', async (req, res) => {
  try {
    const [preference, created] = await UserPreference.findOrCreate({
      where: { user_id: req.params.userId },
      defaults: req.body
    });

    if (!created) {
      await preference.update(req.body);
    }

    res.json({ success: true, preference });
  } catch (error) {
    res.status(500).json({ success: false, error: error.message });
  }
});

// ============================================
// API 5: Xóa cuộc trò chuyện
// ============================================
app.delete('/api/conversations/:conversationId', async (req, res) => {
  try {
    await Conversation.destroy({
      where: { id: req.params.conversationId }
    });
    res.json({ success: true, message: 'Đã xóa cuộc trò chuyện' });
  } catch (error) {
    res.status(500).json({ success: false, error: error.message });
  }
});

// Hàm lấy giá theo model (2026)
function getModelPrice(model) {
  const prices = {
    'gpt-4.1': 8.00,
    'claude-sonnet-4.5': 15.00,
    'gemini-2.5-flash': 2.50,
    'deepseek-v3.2': 0.42
  };
  return prices[model] || 8.00;
}

// Khởi động server
async function start() {
  await initDatabase();
  app.listen(3000, () => {
    console.log('🚀 Server chạy tại http://localhost:3000');
  });
}

start();

Bước 4: Tạo File Cấu Hình Môi Trường

Tạo file .env để lưu các thông tin nhạy cảm:

# Database PostgreSQL
DB_PASSWORD=your_postgres_password

HolySheep AI API Key - Đăng ký tại https://www.holysheep.ai/register

HOLYSHEEP_API_KEY=YOUR_HOLYSHEEP_API_KEY

Bước 5: Tạo Giao Diện Người Dùng

Tạo file public/index.html — Giao diện chat đơn giản:

<!DOCTYPE html>
<html lang="vi">
<head>
  <meta charset="UTF-8">
  <title>AI Chat App - HolySheep</title>
  <style>
    body { font-family: Arial, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; }
    .chat-container { border: 1px solid #ccc; border-radius: 10px; height: 400px; overflow-y: auto; padding: 20px; }
    .message { margin: 10px 0; padding: 10px; border-radius: 10px; }
    .user { background: #e3f2fd; margin-left: 50px; }
    .assistant { background: #f5f5f5; margin-right: 50px; }
    .input-area { display: flex; margin-top: 20px; }
    textarea { flex: 1; padding: 10px; border-radius: 5px; border: 1px solid #ccc; }
    button { padding: 10px 20px; margin-left: 10px; border-radius: 5px; border: none; background: #4CAF50; color: white; cursor: pointer; }
    button:hover { background: #45a049; }
    .meta { font-size: 12px; color: #666; margin-top: 5px; }
  </style>
</head>
<body>
  <h1>🤖 AI Chat App</h1>
  <p>Model: <select id="model">
    <option value="gpt-4.1">GPT-4.1 ($8/MTok)</option>
    <option value="claude-sonnet-4.5">Claude Sonnet 4.5 ($15/MTok)</option>
    <option value="gemini-2.5-flash">Gemini 2.5 Flash ($2.50/MTok)</option>
    <option value="deepseek-v3.2">DeepSeek V3.2 ($0.42/MTok) - Tiết kiệm nhất!</option>
  </select></p>
  
  <div class="chat-container" id="chatContainer"></div>
  
  <div class="input-area">
    <textarea id="userInput" placeholder="Nhập tin nhắn..." rows="2"></textarea>
    <button onclick="sendMessage()">Gửi</button>
  </div>
  
  <div class="meta" id="meta"></div>

  <script>
    let conversationId = null;
    const userId = 1; // Demo user

    async function sendMessage() {
      const input = document.getElementById('userInput');
      const message = input.value.trim();
      if (!message) return;

      // Hiển thị tin nhắn user
      appendMessage('user', message);
      input.value = '';

      try {
        const response = await fetch('/api/chat', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            user_id: userId,
            conversation_id: conversationId,
            message: message,
            model: document.getElementById('model').value
          })
        });

        const data = await response.json();
        
        if (data.success) {
          conversationId = data.conversation_id;
          appendMessage('assistant', data.message);
          document.getElementById('meta').innerHTML = 
            Model: ${data.model_used} | Tokens: ${data.tokens_used} | Chi phí: $${data.cost_usd.toFixed(4)};
        } else {
          appendMessage('assistant', 'Xin lỗi, đã xảy ra lỗi: ' + data.error);
        }
      } catch (error) {
        appendMessage('assistant', 'Lỗi kết nối: ' + error.message);
      }
    }

    function appendMessage(role, content) {
      const container = document.getElementById('chatContainer');
      const div = document.createElement('div');
      div.className = message ${role};
      div.innerHTML = <strong>${role === 'user' ? 'Bạn' : 'AI'}</strong>: ${content};
      container.appendChild(div);
      container.scrollTop = container.scrollHeight;
    }
  </script>
</body>
</html>

Chạy Ứng Dụng

Sau khi hoàn tất, chạy các lệnh sau để khởi động:

# 1. Cài đặt PostgreSQL và tạo database
createdb ai_chat_db

2. Chạy server

node app.js

3. Mở trình duyệt

Truy cập http://localhost:3000

Tối Ưu Hiệu Suất Và Chi Phí

Qua kinh nghiệm thực chiến, tôi nhận thấy:

Lỗi Thường Gặp Và Cách Khắc Phục

1. Lỗi "Invalid API Key" Khi Gọi HolySheep

Mô tả: Nhận được response 401 Unauthorized từ API.

Nguyên nhân: API key chưa được cấu hình đúng hoặc chưa sao chép đầy đủ.

Cách khắc phục:

// Kiểm tra file .env có chứa dòng này không (không có khoảng trắng thừa)
HOLYSHEEP_API_KEY=YOUR_HOLYSHEEP_API_KEY

// Nếu chưa có, đăng ký tại https://www.holysheep.ai/register để nhận API key

// Sau khi có key, restart server
node app.js

2. Lỗi "Conversation Not Found" Khi Lấy Tin Nhắn

Mô tả: API trả về mảng rỗng hoặc lỗi khi fetch messages.

Nguyên nhân: UUID conversation_id không đúng định dạng hoặc bị xóa.

Cách khắc phục:

// 1. Kiểm tra conversation_id trong database
// Chạy câu lệnh SQL trong PostgreSQL:
SELECT id, title, user_id, created_at FROM "Conversations" WHERE user_id = 1;

// 2. Nếu bảng trống, tạo conversation mới trước
// Gửi tin nhắn đầu tiên sẽ tự động tạo conversation

// 3. Kiểm tra UUID format có đúng không (36 ký tự với dấu gạch ngang)
// Ví dụ: "550e8400-e29b-41d4-a716-446655440000"

3. Lỗi "Connection Refused" Kết Nối Database

Mô tả: Server không thể kết nối PostgreSQL, báo lỗi ECONNREFUSED.

Nguyên nhân: PostgreSQL chưa được khởi động hoặc cấu hình port sai.

Cách khắc phục:

// Windows: Khởi động PostgreSQL Service
net start postgresql-x64-16

// macOS: Khởi động qua Homebrew
brew services start postgresql

// Linux (Ubuntu/Debian):
sudo systemctl start postgresql
sudo systemctl enable postgresql

// Kiểm tra PostgreSQL đang chạy port nào:
pg_lsclusters

// Chỉnh sửa database.js nếu port khác 5432:
const sequelize = new Sequelize({
  dialect: 'postgres',
  host: 'localhost',
  port: 5433, // Đổi port nếu cần
  ...
});

4. Lỗi "CORS Policy" Khi Gọi API Từ Frontend

Mô tả: Trình duyệt chặn request từ frontend sang backend.

Nguyên nhân: Server chưa cấu hình CORS headers.

Cách khắc phục:

// Cài đặt cors middleware
npm install cors

// Thêm vào app.js đầu tiên
const cors = require('cors');
app.use(cors({
  origin: 'http://localhost:3000', // Domain của frontend
  credentials: true
}));

5. Lỗi Chi Phí Token Quá Cao

Mô tả: Hóa đơn API tăng đột ngột dù traffic không đổi.

Nguyên nhân: Gửi quá nhiều tin nhắn cũ trong context, không giới hạn max_tokens.

Cách khắc phục:

// 1. Giới hạn số tin nhắn gửi cho AI (chỉ lấy 10 tin nhắn gần nhất)
const historyMessages = await Message.findAll({
  where: { conversation_id: conversation.id },
  order: [['created_at', 'DESC']],
  limit: 10 // Chỉ lấy 10 tin nhắn gần nhất
});

// 2. Giảm max_tokens trong preferences
await UserPreference.update({
  max_tokens: 512 // Giảm từ 2048 xuống 512
}, { where: { user_id: userId } });

// 3. Sử dụng model rẻ hơn cho simple tasks
const selectedModel = isSimpleTask ? 'deepseek-v3.2' : 'gpt-4.1';

Tổng Kết

Trong bài viết này, tôi đã hướng dẫn bạn:

Database thiết kế tốt sẽ giúp ứng dụng của bạn:

Nếu bạn muốn mở rộng, có thể thêm:

Bạn có câu hỏi nào không? Hãy để lại comment bên dưới, tôi sẽ trả lời trong vòng 24 giờ!

👉 Đăng ký HolySheep AI — nhận tín dụng miễn phí khi đăng ký