Khi bạn sử dụng ChatGPT hay Claude, chắc hẳn bạn đã thấy text xuất hiện từng ký tự một, như thể có người đang gõ phím thật sự. Đó gọi là streaming response (phản hồi truyền trực tuyến) hay hiệu ứng typewriter. Trong bài viết này, mình sẽ hướng dẫn bạn cách implement tính năng này trong n8n workflow một cách dễ hiểu nhất, dù bạn chưa từng đụng đến code.
Tại sao nên dùng n8n + HolySheep AI?
Trước khi đi vào chi tiết, mình muốn chia sẻ lý do mình chọn combo này:
- n8n là công cụ automation workflow miễn phí, mã nguồn mở, không cần server riêng
- HolySheep AI cung cấp API tương thích OpenAI với giá chỉ từ $0.42/MTok (DeepSeek V3.2) - tiết kiệm đến 85% so với OpenAI
- Tốc độ phản hồi trung bình dưới 50ms, hỗ trợ WeChat/Alipay, đăng ký nhận tín dụng miễn phí khi đăng ký
- Stream response hoạt động mượt mà với cả GPT-4.1, Claude Sonnet 4.5, Gemini 2.5 Flash
Streaming Response là gì?
Để đơn giản nhất: thay vì chờ AI trả lời xong rồi hiển thị toàn bộ (có thể mất vài giây), streaming cho phép nhận từng phần câu trả lời ngay khi AI generate. Người dùng thấy text xuất hiện dần dần, trải nghiệm tự nhiên hơn nhiều.
Chuẩn bị trước khi bắt đầu
- Tài khoản n8n (có thể dùng bản Cloud miễn phí hoặc self-hosted)
- API Key từ HolySheep AI
- Kiến thức cơ bản về HTTP request (mình sẽ giải thích kỹ)
Bước 1: Lấy API Key từ HolySheep AI
Sau khi đăng ký tài khoản HolySheep AI, bạn vào Dashboard > API Keys > Create New Key. Copy key đó lại, giữ kỹ như mật khẩu. Nếu chưa rõ, cứ xem ảnh chụp màn hình bên dưới:
YOUR_HOLYSHEEP_API_KEY
Bảng giá tham khảo (cập nhật 2026):
- DeepSeek V3.2: $0.42/MTok - Rẻ nhất
- Gemini 2.5 Flash: $2.50/MTok - Cân bằng
- GPT-4.1: $8/MTok - Mạnh nhất
- Claude Sonnet 4.5: $15/MTok - Premium
Bước 2: Tạo Workflow cơ bản trong n8n
Mình sẽ hướng dẫn tạo workflow đơn giản nhất trước. Sau đó mới thêm tính năng streaming.
2.1. Thêm node HTTP Request
Trong n8n, click + > tìm HTTP Request > kéo vào canvas.
2.2. Cấu hình Request
{
"url": "https://api.holysheep.ai/v1/chat/completions",
"method": "POST",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "Bearer YOUR_HOLYSHEEP_API_KEY"
},
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "model",
"value": "deepseek-v3.2"
},
{
"name": "messages",
"value": "[{\"role\": \"user\", \"content\": \"Xin chào, hãy kể cho tôi nghe về bạn\"}]"
},
{
"name": "stream",
"value": true
}
]
}
}
Bước 3: Xử lý Stream Response
Đây là phần quan trọng nhất. Khi bạn bật stream: true, API sẽ trả về dữ liệu theo định dạng Server-Sent Events (SSE). Mỗi chunk sẽ chứa một phần nhỏ text, thường là vài ký tự.
3.1. Thêm node Code để parse SSE
Thêm node Code sau HTTP Request:
// JavaScript xử lý SSE stream từ HolySheep AI
// Dữ liệu nhận vào là text dạng SSE, ta cần tách từng chunk
const responseData = $input.item.json.data;
const lines = responseData.split('\n');
let fullText = '';
const chunks = [];
for (const line of lines) {
if (line.startsWith('data: ')) {
const jsonStr = line.slice(6); // Bỏ "data: "
if (jsonStr === '[DONE]') {
break;
}
try {
const chunk = JSON.parse(jsonStr);
const content = chunk.choices?.[0]?.delta?.content;
if (content) {
fullText += content;
chunks.push({
text: content,
fullResponse: fullText
});
}
} catch (e) {
// Bỏ qua JSON parse error
}
}
}
return {
json: {
fullText: fullText,
chunks: chunks,
chunkCount: chunks.length
}
};
Bước 4: Tạo Webhook để hiển thị real-time
Để người dùng thấy được hiệu ứng typewriter, bạn cần một webhook trả về từng chunk. Cấu hình n8n workflow như sau:
4.1. Cấu trúc Workflow hoàn chỉnh
┌─────────────┐
│ Webhook │ ← Trigger endpoint
└──────┬──────┘
│
┌──────▼──────┐
│ HTTP Request│ ← Gọi HolySheep AI stream
└──────┬──────┘
│
┌──────▼──────┐
│ Code │ ← Parse SSE chunks
└──────┬──────┘
│
┌──────▼──────┐
│ Respond │ ← Trả về cho frontend
└─────────────┘
4.2. Code xử lý stream hoàn chỉnh
// n8n Code node - Xử lý streaming response hoàn chỉnh
// Tích hợp HolySheep AI với base_url chuẩn
const HOLYSHEEP_API_KEY = 'YOUR_HOLYSHEEP_API_KEY';
const BASE_URL = 'https://api.holysheep.ai/v1';
// Lấy user message từ webhook
const userMessage = $input.item.json.body?.message || 'Xin chào';
const response = await fetch(${BASE_URL}/chat/completions, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': Bearer ${HOLYSHEEP_API_KEY}
},
body: JSON.stringify({
model: 'deepseek-v3.2', // Model rẻ nhất, $0.42/MTok
messages: [{ role: 'user', content: userMessage }],
stream: true
})
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
let fullText = '';
let chunkCount = 0;
const chunks = [];
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value);
const lines = chunk.split('\n');
for (const line of lines) {
if (line.startsWith('data: ')) {
const jsonStr = line.slice(6);
if (jsonStr === '[DONE]') continue;
try {
const data = JSON.parse(jsonStr);
const content = data.choices?.[0]?.delta?.content;
if (content) {
fullText += content;
chunkCount++;
chunks.push({
index: chunkCount,
text: content,
timestamp: new Date().toISOString()
});
}
} catch (e) {
// Ignore parse errors
}
}
}
}
// Trả về kết quả cho node tiếp theo
return {
json: {
success: true,
userMessage: userMessage,
fullResponse: fullText,
chunks: chunks,
stats: {
totalChunks: chunkCount,
totalLength: fullText.length,
avgChunkSize: (fullText.length / chunkCount).toFixed(2)
}
}
};
Bước 5: Frontend để hiển thị Typewriter Effect
Để có hiệu ứng đẹp mắt, bạn cần code frontend. Dưới đây là ví dụ HTML đơn giản:
<!DOCTYPE html>
<html lang="vi">
<head>
<meta charset="UTF-8">
<title>AI Typewriter Demo - HolySheep AI</title>
<style>
#chat-container {
max-width: 600px;
margin: 50px auto;
font-family: Arial, sans-serif;
}
#output {
border: 1px solid #ddd;
padding: 20px;
min-height: 200px;
border-radius: 8px;
background: #f9f9f9;
line-height: 1.6;
}
.cursor {
animation: blink 1s infinite;
}
@keyframes blink {
0%, 50% { opacity: 1; }
51%, 100% { opacity: 0; }
}
input, button {
padding: 10px 15px;
margin-top: 15px;
border-radius: 4px;
}
input { flex: 1; border: 1px solid #ddd; }
button { background: #4CAF50; color: white; border: none; cursor: pointer; }
button:hover { background: #45a049; }
</style>
</head>
<body>
<div id="chat-container">
<h2>💬 Chat AI với Hiệu ứng Typewriter</h2>
<div id="output"><span class="cursor">█</span></div>
<div style="display: flex;">
<input type="text" id="message" placeholder="Nhập tin nhắn...">
<button onclick="sendMessage()">Gửi</button>
</div>
</div>
<script>
// Thay bằng webhook URL của n8n
const WEBHOOK_URL = 'https://your-n8n-instance.com/webhook/ai-stream';
const output = document.getElementById('output');
async function sendMessage() {
const message = document.getElementById('message').value;
if (!message) return;
output.innerHTML = '<span class="cursor">█</span>';
try {
// Gọi n8n webhook
const response = await fetch(WEBHOOK_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message })
});
const data = await response.json();
// Typewriter effect
const fullText = data.fullResponse || '';
await typewriterEffect(fullText);
} catch (error) {
output.innerHTML = '❌ Lỗi: ' + error.message;
}
}
async function typewriterEffect(text) {
output.innerHTML = '';
const cursor = document.createElement('span');
cursor.className = 'cursor';
cursor.textContent = '█';
for (let i = 0; i < text.length; i++) {
output.textContent += text[i];
output.appendChild(cursor);
await sleep(20 + Math.random() * 30); // 20-50ms delay
}
cursor.remove();
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
</script>
</body>
</html>
Bước 6: Demo với Server-Sent Events trực tiếp
Nếu bạn muốn response thật sự real-time (từng ký tự hiện ngay), dùng SSE trực tiếp từ n8n:
// Nút "Respond to Webhook" trong n8n
// Cấu hình Response Format: "Response Head"
// Nội dung Response Body (sử dụng Expression):
/*
{{ $json.chunks.map(c => data: ${JSON.stringify({text: c.text})}).join('\n') }}
data: [DONE]
*/
// Tùy chọn Response Headers:
{
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache",
"Connection": "keep-alive"
}
// Frontend xử lý SSE trực tiếp
const output = document.getElementById('output');
const eventSource = new EventSource(https://api.holysheep.ai/v1/chat/completions? +
new URLSearchParams({
message: document.getElementById('message').value
}));
// Lưu ý: n8n cần proxy qua để xử lý authentication
// Code này minh họa concept, thực tế cần backend proxy
eventSource.onmessage = (event) => {
if (event.data === '[DONE]') {
eventSource.close();
return;
}
try {
const data = JSON.parse(event.data);
output.textContent += data.text;
} catch (e) {}
};
eventSource.onerror = () => {
eventSource.close();
};
Kiểm tra và Debug
Để test workflow, click Test Workflow trong n8n. Bạn sẽ thấy:
- Node HTTP Request hiển thị raw response từ API
- Node Code parse và tách chunks thành công
- Thời gian phản hồi trung bình dưới 50ms với HolySheep AI
Mẹo: Thêm node Log giữa các bước để debug dễ hơn. Trong n8n, click vào kết nối > Add Node > Log.
Lỗi thường gặp và cách khắc phục
1. Lỗi "Invalid API Key" hoặc 401 Unauthorized
// ❌ SAI: Thiếu Bearer prefix
"Authorization": "YOUR_HOLYSHEEP_API_KEY"
// ✅ ĐÚNG: Phải có "Bearer " phía trước
"Authorization": "Bearer YOUR_HOLYSHEEP_API_KEY"
// Kiểm tra lại:
// 1. Vào https://www.holysheep.ai/dashboard/api-keys
// 2. Copy đúng API key (bắt đầu bằng "hs-" hoặc "sk-")
// 3. Không copy thừa/kém ký tự
2. Lỗi "stream is not supported" hoặc 400 Bad Request
// ❌ SAI: stream phải là boolean, không phải string
"stream": "true"
// ✅ ĐÚNG: stream là boolean
"stream": true
// Kiểm tra lại:
// 1. Model cần hỗ trợ streaming (hầu hết đều có)
// 2. Dùng model đúng: "deepseek-v3.2", "gpt-4.1", "claude-sonnet-4.5"
// 3. Không dùng model cũ như "gpt-3.5-turbo" (không hỗ trợ streaming)
3. Lỗi SSE parsing - chunks không hiển thị đúng
// ❌ SAI: Không xử lý đúng format SSE
const lines = data.split('\n');
// Chỉ split là chưa đủ
// ✅ ĐÚNG: Parse đúng format SSE
const lines = data.split('\n');
let buffer = '';
for (const line of lines) {
if (line.startsWith('data: ')) {
const jsonStr = line.slice(6); // Luôn cắt 6 ký tự "data: "
// Bỏ qua comment lines
if (jsonStr.startsWith(':')) continue;
// Bỏ qua [DONE]
if (jsonStr === '[DONE]') break;
// Parse JSON
const chunk = JSON.parse(jsonStr);
const content = chunk.choices?.[0]?.delta?.content || '';
// Xử lý content ở đây
console.log('Chunk received:', content);
}
}
// Debug: Log raw response để xem format
console.log('Raw response:', data);
4. Lỗi CORS khi gọi trực tiếp từ browser
// ❌ Browser gọi trực tiếp sang HolySheep AI sẽ bị CORS
// Không bao giờ expose API key phía client
// ✅ ĐÚNG: Proxy qua n8n
// 1. Tạo n8n webhook endpoint
// 2. Frontend gọi webhook URL của n8n
// 3. n8n xử lý authentication với HolySheep AI
// Frontend code:
const response = await fetch('https://your-n8n.com/webhook/my-ai-chat', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message: userMessage })
});
// KHÔNG BAO GIỜ làm thế này:
// const response = await fetch('https://api.holysheep.ai/v1/...');
// API key sẽ bị lộ!
5. Lỗi chunk bị trùng lặp hoặc mất thứ tự
// ❌ Streaming không đảm bảo thứ tự nếu xử lý async sai
const chunks = data.split('data: ')
.map(s => JSON.parse(s)) // Parse song song = có thể sai thứ tự
// ✅ ĐÚNG: Xử lý tuần tự theo thứ tự nhận được
const lines = rawData.split('\n');
for (const line of lines) { // for...of giữ thứ tự
if (line.startsWith('data: ')) {
await processChunk(line); // Xử lý tuần tự
}
}
// Thêm sequence number để debug
const chunk = JSON.parse(jsonStr);
const index = chunk.choices?.[0]?.index; // HolySheep AI cung cấp index
console.log(Chunk ${index}:, content);
Tối ưu hiệu suất
Qua kinh nghiệm thực chiến của mình:
- Dùng DeepSeek V3.2 cho chi phí thấp nhất ($0.42/MTok) - phù hợp cho demo và prototype
- Batch chunks: Nhóm 3-5 chunks trước khi update UI để tránh render quá nhiều lần
- Debounce display: Chỉ update DOM mỗi 50-100ms thay vì mỗi chunk
- Compression: Bật gzip trên n8n webhook để giảm bandwidth
// Ví dụ: Tối ưu hiển thị với batching
class TypewriterBuffer {
constructor(delay = 50) {
this.buffer = '';
this.displayCallback = null;
this.delay = delay;
}
push(text) {
this.buffer += text;
this.scheduleFlush();
}
scheduleFlush() {
if (this.timeout) return;
this.timeout = setTimeout(() => {
if (this.displayCallback && this.buffer) {
this.displayCallback(this.buffer);
this.buffer = '';
}
this.timeout = null;
}, this.delay);
}
}
// Sử dụng:
const typewriter = new TypewriterBuffer(50);
typewriter.displayCallback = (text) => {
document.getElementById('output').textContent += text;
};
Kết luận
Việc implement streaming response với n8n và HolySheep AI thực ra không khó như bạn tưởng. Quan trọng là hiểu đúng format SSE, xử lý chunks tuần tự, và bảo mật API key bằng cách proxy qua n8n.
HolySheep AI là lựa chọn tuyệt vời với giá chỉ từ $0.42/MTok (DeepSeek V3.2), tốc độ dưới 50ms, và hỗ trợ thanh toán WeChat/Alipay. Đặc biệt, đăng ký ngay hôm nay để nhận tín dụng miễn phí giúp bạn thử nghiệm không giới hạn.
Nếu gặp khó khăn, để lại comment bên dưới, mình sẽ hỗ trợ ngay. Chúc bạn thành công!
👉 Đăng ký HolySheep AI — nhận tín dụng miễn phí khi đăng ký