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ì:
- Tỷ giá chỉ ¥1 = $1, tiết kiệm 85%+ so với các nhà cung cấp khác
- Hỗ trợ WeChat/Alipay cho người dùng Việt Nam
- Độ trễ dưới 50ms — cực kỳ nhanh
- Tín dụng miễn phí khi đăng ký
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:
- users — Lưu thông tin người dùng
- conversations — Lưu từng cuộc trò chuyện
- messages — Lưu từng tin nhắn trong cuộc trò chuyện
- user_preferences — Lưu sở thích người dùng
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:
- DeepSeek V3.2 giá chỉ $0.42/MTok — rẻ hơn GPT-4.1 đến 19 lần, phù hợp cho hầu hết use case
- Với độ trễ <50ms của HolySheep AI, người dùng gần như không nhận ra có độ trễ
- Nên lưu trữ context window hợp lý — không gửi quá nhiều tin nhắn cũ để tiết kiệm token
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:
- Thiết kế 4 bảng database để lưu trữ users, conversations, messages, và preferences
- Tạo REST API để gửi nhận tin nhắn với AI (sử dụng HolySheep AI)
- Xây dựng giao diện chat đơn giản
- Xử lý 5 lỗi phổ biến nhất khi làm việc với database và API
Database thiết kế tốt sẽ giúp ứng dụng của bạn:
- Mở rộng dễ dàng — Thêm features mới không ảnh hưởng đến dữ liệu cũ
- Truy vấn nhanh — Index đúng cách giúp load tin nhắn dưới 50ms
- Tiết kiệm chi phí — Chỉ gửi context cần thiết cho AI
Nếu bạn muốn mở rộng, có thể thêm:
- Bảng
attachments— Lưu file đính kèm - Bảng
feedback— Người dùng đánh giá câu trả lời AI - Bảng
usage_stats— Theo dõi chi phí theo ngày/tháng
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ý