Bỏ qua đến nội dung chính
AI Automation
Canvas n8n của workflow bản tin sáng: trigger 7h sáng và webhook, đọc RSS VnExpress, lấy 8 tin, gộp tiêu đề, AI viết bản tin bằng Ollama, trên nền tối có logo n8n

n8n workflow mẫu: 6 template tiếng Việt dùng ngay

AIDev TeamTham vấn chuyên môn: Nguyễn Việt Chung

Đăng 21 phút đọc1 lượt xem

Mục lục · 18

Sáu file JSON workflow tiếng Việt dán vào n8n là chạy: form liên hệ, bản tin công nghệ do AI tóm tắt, AI phân loại phản hồi khách, canh website sập, nhắc thời tiết và bot Telegram trả lời bằng AI. Mỗi n8n workflow đều chạy thật ngày 14/10/2026, gửi tin qua Telegram, kèm số đo và lỗi gặp phải.

n8n workflow mẫu (template) là một file JSON chứa sẵn các node và cách nối chúng. Bạn tải file về, vào n8n chọn Import from File hoặc copy nội dung rồi dán vào canvas, nối credential của mình, bấm Publish là chạy. Bài này có 6 template tiếng Việt mình dựng cho việc hay gặp ở cửa hàng và văn phòng nhỏ ở Việt Nam.

Cả 6 file mình chạy thật trên n8n 2.43.5 (bản ổn định ra ngày 14/10/2026) tự host, máy CPU 16 nhân không có GPU, kết quả gửi về Telegram:

  • Form liên hệ lưu khách vào bảng, tự đổi "+84 987.654.321" thành 0987654321, báo "Khách mới" qua Telegram trong chưa tới 1 giây.

  • Bản tin sáng đọc RSS VnExpress, AI chạy trên máy viết 5 dòng tóm tắt rồi gửi Telegram, mất 14 đến 26 giây.

  • Phân loại phản hồi khách: AI đúng cảm xúc 12/12 câu, đúng chủ đề 10/12 câu với model gemma4:e4b.

  • Canh website sập mỗi 5 phút, chỉ nhắn Telegram khi một trang đổi trạng thái chứ không nhắn lặp.

  • Nhắc thời tiết Hà Nội lúc 6 giờ sáng, không cần API key.

  • Bot Telegram trả lời khách bằng AI chạy trên máy, 7 đến 17 giây mỗi câu, và có lúc bịa giờ mở cửa.

Mới nghe tên n8n lần đầu thì đọc n8n là gì trước. Chưa có n8n để dán file vào thì làm theo bài tự host n8n bằng Docker, cài khoảng một phút.

#

Template

Khởi động bằng

Số node

Cần thêm gì

Thời gian chạy đo được

1

Form liên hệ → lưu khách → Telegram

Form Trigger

4

Bảng lien_he, Telegram

92 đến 121 ms (form), 0,9 s (tin Telegram)

2

Bản tin sáng: RSS → AI tóm tắt → Telegram

7h sáng + webhook

8

Ollama, Telegram

14,0 đến 26,1 s

3

Phân loại phản hồi khách bằng AI

Webhook POST

6

Ollama, bảng phan_hoi_khach

9,7 đến 13,1 s

4

Canh website sập → Telegram

Mỗi 5 phút + webhook

9

Bảng website_loi, Telegram

0,19 đến 4,4 s

5

Thời tiết sáng nay → Telegram

6h sáng + webhook

5

Telegram

1,9 đến 4,4 s

6

Bot Telegram trả lời bằng AI

Telegram Trigger

4

Ollama, Telegram, HTTPS

7 đến 17 s

n8n workflow mẫu là gì, dán vào n8n thế nào?

Một workflow trong n8n được lưu dưới dạng JSON: danh sách node (loại node, tham số, vị trí trên canvas) và phần connections ghi node nào nối sang node nào. Template chỉ là file JSON đó được chia sẻ cho người khác. Thư viện template chính thức của n8n ở n8n.io/workflows, phần lớn viết bằng tiếng Anh và dùng dịch vụ nước ngoài.

Theo tài liệu Export and import của n8n, có ba cách nạp: copy JSON rồi dán thẳng vào canvas bằng Ctrl+V, menu Import from File, hoặc Import from URL. Tài liệu cũng nhắc file xuất ra có kèm tên và ID credential, nên trước khi chia sẻ phải xóa đi. Sáu file dưới đây mình đã bỏ hết ID và chat_id, credential chỉ giữ tên.

Khi mình dán JSON vào canvas, n8n 2.43.5 hiện hộp hỏi "Pasting this from an AI tool?" và mời nối MCP. Bấm Skip là bỏ qua; nếu canvas vẫn trống thì dán lại lần nữa.

Hộp thoại Pasting this from an AI tool? hiện ra khi dán JSON workflow vào canvas n8n 2.43.5, có nút Skip và Connect n8n

Cần chuẩn bị gì trước khi nạp 6 template?

Bạn cần n8n bản 2.x tự host. Template 2, 3 và 6 cần thêm Ollama chạy model AI trên chính máy đó. Mình cài cả hai trên một máy thuê ở AIDev Cloud: n8n bằng lệnh một dòng get.n8n.io mất 61 giây, Ollama 0.40.4 mất 27 giây.

bash
$ curl -fsSL https://get.n8n.io | sh
✔ Started n8n 2.43.5 and sandbox services
n8n is running at: http://localhost:5678
$ curl -fsSL https://ollama.com/install.sh | sh
$ ollama pull gemma4:e4b
$ ollama pull qwen3.5:4b

n8n chạy trong Docker nên không gọi được Ollama qua localhost. Mình cho Ollama nghe mọi địa chỉ và thêm extra_hosts vào service n8n trong compose.yml, rồi đặt URL của credential Ollama là http://host.docker.internal:11434:

bash
$ printf "[Service]\nEnvironment=OLLAMA_HOST=0.0.0.0:11434\n" > /etc/systemd/system/ollama.service.d/override.conf
$ systemctl daemon-reload && systemctl restart ollama
yaml
  n8n:            # service n8n trong compose.yml, thêm 2 dòng dưới
    extra_hosts:
      - host.docker.internal:host-gateway

Đặt credential Ollama tên đúng Ollama trên máy. Lúc mình import lại file mẫu số 3, n8n tự gắn credential trùng tên mà không cần chọn tay. Mình cũng thêm GENERIC_TIMEZONE=Asia/Ho_Chi_Minh vào .env để lịch 7h sáng chạy theo giờ Việt Nam.

Ba template ghi dữ liệu vào Data table, bảng tính có sẵn trong n8n (mục Data tables ở trang Overview). Tạo trước ba bảng với đúng tên cột sau:

Bảng

Cột (kiểu)

Dùng ở template

lien_he

ho_ten, so_dien_thoai, nhu_cau, loi_nhan (string); sdt_hop_le (boolean)

1

phan_hoi_khach

noi_dung, cam_xuc, chu_de (string); can_goi_lai (boolean)

3

website_loi

url, loi (string); ma_http (number)

4

Node ghi bảng trong file mẫu chọn bảng theo tên chứ không theo ID. ID bảng mỗi máy một khác, chọn theo ID thì nạp sang máy khác sẽ lỗi (xem mục lỗi bên dưới).

Năm template gửi tin qua Telegram cần một bot và chat_id của bạn. Tạo bot ở BotFather (cách làm có trong bài OpenClaw Telegram), thêm credential Telegram API tên Telegram bot thử, rồi thay chữ CHAT_ID_CUA_BAN trong JSON bằng chat_id. Cách lấy chat_id nhanh nhất là chạy template 6 trước: nhắn /start cho bot, mở execution của node Telegram Trigger, số nằm ở message.chat.id.

Template 1: form liên hệ lưu khách, chuẩn hóa số điện thoại

Form Trigger tạo sẵn một trang form công khai ở /form/lien-he, không cần làm web riêng. Khách điền họ tên, số điện thoại, nhu cầu, lời nhắn. Node Code bỏ dấu cách, dấu chấm, đổi đầu +84 hoặc 84 thành 0, rồi kiểm tra đúng 10 số di động Việt Nam (đầu 03, 05, 07, 08, 09). Kết quả ghi vào bảng lien_he.

Trang form Liên hệ tư vấn do n8n tạo, có ô Họ và tên, Số điện thoại, danh sách Bạn cần gì và ô Lời nhắn

Mình điền 4 lần bằng trình duyệt tự động, mỗi lần từ lúc bấm Gửi tới khi hiện trang cảm ơn mất 92 đến 121 ms. Ba số viết kiểu khác nhau đều về đúng dạng 10 số, còn "12345" bị đánh dấu không hợp lệ:

Bảng lien_he trong n8n sau 4 lần gửi form: ba số điện thoại đã chuẩn hóa về dạng 0xxx và có dấu tích hợp lệ, số 12345 không có dấu tích

Trang cảm ơn vẫn hiện tiêu đề tiếng Anh "Form Submitted", câu tiếng Việt bạn đặt nằm ở dòng dưới. Sau node lưu bảng là node Telegram nhắn "Khách mới: họ tên, số điện thoại, nhu cầu, lời nhắn", số sai thì ghi thêm "(số sai)". Hai lần mình gửi form buổi tối, node Telegram mất 0,89 và 0,91 giây; trang cảm ơn vẫn hiện sau khoảng 80 ms vì form trả lời ngay khi nhận.

json
{"name":"1. Form liên hệ → lưu khách",
"nodes":[
{"parameters":{"formTitle":"Liên hệ tư vấn","formDescription":"Để lại số điện thoại, bên mình gọi lại trong giờ làm việc.","formFields":{"values":[{"fieldLabel":"Họ và tên","requiredField":true},{"fieldLabel":"Số điện thoại","placeholder":"0912 345 678","requiredField":true},{"fieldLabel":"Bạn cần gì","fieldType":"dropdown","fieldOptions":{"values":[{"option":"Báo giá"},{"option":"Hỗ trợ kỹ thuật"},{"option":"Hợp tác"},{"option":"Khác"}]},"requiredField":true},{"fieldLabel":"Lời nhắn","fieldType":"textarea"}]},"options":{"path":"lien-he","buttonLabel":"Gửi","appendAttribution":false,"respondWithOptions":{"values":{"formSubmittedText":"Cảm ơn bạn! Bên mình sẽ gọi lại trong giờ làm việc."}}}},"name":"Form liên hệ","type":"n8n-nodes-base.formTrigger","typeVersion":2.6,"position":[0,0]},
{"parameters":{"jsCode":"return $input.all().map(i => {\n  const f = i.json;\n  // bỏ dấu cách, chấm, gạch; +84 / 84 → 0\n  let sdt = String(f['Số điện thoại'] || '').replace(/[\\s.\\-()]/g, '');\n  if (sdt.startsWith('+84')) sdt = '0' + sdt.slice(3);\n  else if (sdt.startsWith('84') && sdt.length === 11) sdt = '0' + sdt.slice(2);\n  return { json: {\n    ho_ten: String(f['Họ và tên'] || '').trim(),\n    so_dien_thoai: sdt,\n    sdt_hop_le: /^0[35789]\\d{8}$/.test(sdt),   // di động VN: 10 số, đầu 03/05/07/08/09\n    nhu_cau: f['Bạn cần gì'] || '',\n    loi_nhan: f['Lời nhắn'] || '',\n  } };\n});"},"name":"Chuẩn hóa số điện thoại","type":"n8n-nodes-base.code","typeVersion":2,"position":[260,0]},
{"parameters":{"resource":"row","operation":"insert","dataTableId":{"__rl":true,"mode":"name","value":"lien_he"},"columns":{"mappingMode":"autoMapInputData","value":{},"matchingColumns":[],"schema":[]},"options":{}},"name":"Lưu vào bảng lien_he","type":"n8n-nodes-base.dataTable","typeVersion":1.1,"position":[520,0]},
{"parameters":{"resource":"message","operation":"sendMessage","chatId":"CHAT_ID_CUA_BAN","text":"={{ String(`Khách mới: ${$json.ho_ten}, ${$json.so_dien_thoai}${$json.sdt_hop_le ? '' : ' (số sai)'}\\nCần: ${$json.nhu_cau}\\n${$json.loi_nhan}` ?? '').replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\\*\\*/g, '').replace(/^[ \\t]*[*-][ \\t]+/gm, '• ') }}","additionalFields":{"appendAttribution":false,"parse_mode":"HTML"}},"name":"Báo Telegram","type":"n8n-nodes-base.telegram","typeVersion":1.2,"position":[780,0],"credentials":{"telegramApi":{"name":"Telegram bot thử"}}}
],
"connections":{"Form liên hệ":{"main":[[{"node":"Chuẩn hóa số điện thoại","type":"main","index":0}]]},"Chuẩn hóa số điện thoại":{"main":[[{"node":"Lưu vào bảng lien_he","type":"main","index":0}]]},"Lưu vào bảng lien_he":{"main":[[{"node":"Báo Telegram","type":"main","index":0}]]}},
"settings":{"executionOrder":"v1","timezone":"Asia/Ho_Chi_Minh"}}

Template 2: bản tin công nghệ buổi sáng do AI tóm tắt

Đúng 7 giờ sáng, workflow đọc RSS mục Khoa học công nghệ của VnExpress (lần chạy của mình trả về 60 tin), lấy 8 tin mới nhất, gộp tiêu đề và đoạn mô tả lại, rồi nhờ model AI viết bản tin 5 gạch đầu dòng và gửi qua Telegram. Có thêm một webhook GET /webhook/ban-tin-sang để bấm chạy thử bất cứ lúc nào.

Canvas template bản tin sáng trong n8n: hai trigger 7h sáng và webhook, đọc RSS VnExpress, lấy 8 tin, gộp tiêu đề, AI viết bản tin nối với Ollama Chat Model

Mình thử hai model chạy bằng CPU. qwen3.5:4b xong sau 18,4 giây nhưng viết "được ưu đãi miễn thuế thu nhập" trong khi tin gốc chỉ nói "được ưu đãi thuế thu nhập". gemma4:e4b lần đầu mất 26,1 giây và giữ đúng nghĩa, nên mình chọn làm mặc định. Buổi tối chạy thêm 3 lần với gemma4:e4b, mỗi lần 14,0 đến 15,7 giây tính cả gửi Telegram, và một trong ba lần nó cũng viết "ưu đãi miễn thuế thu nhập". Model nhỏ cỡ này đôi khi đổi nghĩa, nên coi bản tin là gợi ý đọc lướt và giữ link tin gốc.

Kết quả node AI viết bản tin trong n8n: đầu vào là 8 tin VnExpress, đầu ra là bản tin 5 gạch đầu dòng tiếng Việt do gemma4:e4b viết

Node Gửi bản tin Telegram bỏ dấu ** và đổi gạch đầu dòng * thành • trước khi gửi, vì Telegram hiện nguyên các ký tự đó. Ảnh dưới là lần gửi lúc 20:42, Telegram trả về ok: true và message_id sau 0,93 giây (chat_id đã che):

Node Gửi bản tin Telegram trong n8n: Parse Mode HTML, ô Text bỏ dấu sao, đầu ra ok true kèm message_id và nội dung bản tin, chat_id đã che
json
{"name":"2. Bản tin sáng: RSS → AI tóm tắt",
"nodes":[
{"parameters":{"rule":{"interval":[{"field":"days","triggerAtHour":7}]}},"name":"7h sáng hằng ngày","type":"n8n-nodes-base.scheduleTrigger","typeVersion":1.2,"position":[0,0]},
{"parameters":{"httpMethod":"GET","path":"ban-tin-sang","responseMode":"lastNode","options":{}},"name":"Chạy thử (webhook)","type":"n8n-nodes-base.webhook","typeVersion":2.2,"position":[0,200]},
{"parameters":{"url":"https://vnexpress.net/rss/khoa-hoc-cong-nghe.rss","options":{}},"name":"Đọc RSS VnExpress","type":"n8n-nodes-base.rssFeedRead","typeVersion":1.2,"position":[260,100]},
{"parameters":{"maxItems":8},"name":"Lấy 8 tin mới nhất","type":"n8n-nodes-base.limit","typeVersion":1,"position":[520,100]},
{"parameters":{"jsCode":"const tin = $input.all().map((i, k) => `${k + 1}. ${i.json.title} — ${i.json.contentSnippet || ''}`.slice(0, 300));\nreturn [{ json: { danh_sach: tin.join('\\n'), so_tin: tin.length } }];"},"name":"Gộp tiêu đề","type":"n8n-nodes-base.code","typeVersion":2,"position":[780,100]},
{"parameters":{"promptType":"define","text":"=Đây là {{ $json.so_tin }} tin khoa học công nghệ mới nhất:\n{{ $json.danh_sach }}\n\nViết bản tin buổi sáng bằng tiếng Việt: 1 câu mở đầu, sau đó 5 gạch đầu dòng chọn 5 tin đáng đọc nhất, mỗi dòng không quá 25 chữ. Không bịa thêm chi tiết ngoài nội dung trên."},"name":"AI viết bản tin","type":"@n8n/n8n-nodes-langchain.chainLlm","typeVersion":1.9,"position":[1040,100]},
{"parameters":{"model":"gemma4:e4b","options":{"think":false,"temperature":0.2}},"name":"Ollama Chat Model","type":"@n8n/n8n-nodes-langchain.lmChatOllama","typeVersion":1,"position":[1040,320],"credentials":{"ollamaApi":{"name":"Ollama trên máy"}}},
{"parameters":{"resource":"message","operation":"sendMessage","chatId":"CHAT_ID_CUA_BAN","text":"={{ String($json.text ?? '').replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\\*\\*/g, '').replace(/^[ \\t]*[*-][ \\t]+/gm, '• ') }}","additionalFields":{"appendAttribution":false,"parse_mode":"HTML"}},"name":"Gửi bản tin Telegram","type":"n8n-nodes-base.telegram","typeVersion":1.2,"position":[1300,100],"credentials":{"telegramApi":{"name":"Telegram bot thử"}}}
],
"connections":{"7h sáng hằng ngày":{"main":[[{"node":"Đọc RSS VnExpress","type":"main","index":0}]]},"Chạy thử (webhook)":{"main":[[{"node":"Đọc RSS VnExpress","type":"main","index":0}]]},"Đọc RSS VnExpress":{"main":[[{"node":"Lấy 8 tin mới nhất","type":"main","index":0}]]},"Lấy 8 tin mới nhất":{"main":[[{"node":"Gộp tiêu đề","type":"main","index":0}]]},"Gộp tiêu đề":{"main":[[{"node":"AI viết bản tin","type":"main","index":0}]]},"Ollama Chat Model":{"ai_languageModel":[[{"node":"AI viết bản tin","type":"ai_languageModel","index":0}]]},"AI viết bản tin":{"main":[[{"node":"Gửi bản tin Telegram","type":"main","index":0}]]}},
"settings":{"executionOrder":"v1","timezone":"Asia/Ho_Chi_Minh"}}

Template 3: AI phân loại phản hồi khách hàng có đúng không?

Đây là template mình thấy đáng dùng nhất cho shop online. Webhook nhận nội dung phản hồi (từ form, Zalo, email đã chuyển tiếp), node Information Extractor bắt AI trả về đúng 3 trường: cảm xúc (tích cực, tiêu cực, trung tính), chủ đề (giao hàng, đơn hàng, giá, đổi trả, chất lượng, thanh toán, tư vấn sản phẩm, khác) và có cần gọi lại khách hay không. Kết quả lưu vào bảng phan_hoi_khach.

bash
$ curl -X POST http://localhost:5678/webhook/phan-hoi -H 'Content-Type: application/json' \
    -d '{"noi_dung":"Shop giao nhầm màu, mình đặt đen mà nhận trắng"}'
{"noi_dung":"Shop giao nhầm màu, mình đặt đen mà nhận trắng","cam_xuc":"tiêu cực","chu_de":"giao hàng","can_goi_lai":true}
Bảng chi tiết node AI đọc phản hồi trong n8n: đầu vào là câu Đặt 2 hộp mà nhận có 1, đầu ra cam_xuc tiêu cực, chu_de đơn hàng, can_goi_lai true

Để biết AI đúng đến đâu, mình viết 12 phản hồi kiểu khách Việt hay nhắn (có cả "ship chậm vl"), tự gán nhãn đúng, rồi gửi lần lượt qua webhook với từng model:

Model (CPU, thinking tắt)

Cảm xúc

Chủ đề

Cần gọi lại

Thời gian mỗi câu (trung vị)

qwen3.5:4b

12/12

8/12

12/12

10,1 s

gemma4:e4b

12/12

10/12

11/12

10,8 s

Biểu đồ số phản hồi đúng trên 12 của qwen3.5:4b và gemma4:e4b theo cảm xúc, chủ đề và cần gọi lại, đo trên máy CPU 16 nhân

Cảm xúc thì cả hai đều đúng hết. Chủ đề là chỗ hay sai: "Có xuất hóa đơn VAT cho công ty không?" mình xếp vào thanh toán, hai model xếp vào tư vấn sản phẩm hoặc khác. "Tạm được, không có gì đặc biệt" cả hai đều xếp "khác", còn mình gán "chất lượng", câu này thật ra hiểu kiểu nào cũng được. Nếu chủ đề quan trọng với bạn, viết mô tả từng chủ đề kỹ hơn trong node hoặc thêm vài ví dụ vào System Prompt.

json
{"name":"3. Phân loại phản hồi khách bằng AI",
"nodes":[
{"parameters":{"httpMethod":"POST","path":"phan-hoi","responseMode":"responseNode","options":{}},"name":"Nhận phản hồi","type":"n8n-nodes-base.webhook","typeVersion":2.2,"position":[0,0]},
{"parameters":{"text":"={{ $json.body.noi_dung }}","schemaType":"fromAttributes","attributes":{"attributes":[{"name":"cam_xuc","type":"string","description":"Chỉ một trong: tích cực, tiêu cực, trung tính","required":true},{"name":"chu_de","type":"string","description":"Chỉ một trong: giao hàng, đơn hàng, giá, đổi trả, chất lượng, thanh toán, tư vấn sản phẩm, khác","required":true},{"name":"can_goi_lai","type":"boolean","description":"true nếu khách đang hỏi, cần shop xử lý việc gì, hoặc để lại số điện thoại; false nếu chỉ nhận xét","required":true}]},"options":{"systemPromptTemplate":"Bạn đọc phản hồi của khách hàng một cửa hàng online ở Việt Nam và phân loại đúng theo các trường được yêu cầu. Chỉ dùng đúng các giá trị được liệt kê."}},"name":"AI đọc phản hồi","type":"@n8n/n8n-nodes-langchain.informationExtractor","typeVersion":1.2,"position":[260,0]},
{"parameters":{"model":"gemma4:e4b","options":{"think":false,"temperature":0.2}},"name":"Ollama Chat Model","type":"@n8n/n8n-nodes-langchain.lmChatOllama","typeVersion":1,"position":[260,220],"credentials":{"ollamaApi":{"name":"Ollama trên máy"}}},
{"parameters":{"jsCode":"const goc = $('Nhận phản hồi').first().json.body.noi_dung;\nreturn $input.all().map(i => ({ json: { noi_dung: goc, ...i.json.output } }));"},"name":"Gắn nội dung gốc","type":"n8n-nodes-base.code","typeVersion":2,"position":[560,0]},
{"parameters":{"resource":"row","operation":"insert","dataTableId":{"__rl":true,"mode":"name","value":"phan_hoi_khach"},"columns":{"mappingMode":"autoMapInputData","value":{},"matchingColumns":[],"schema":[]},"options":{}},"name":"Lưu vào bảng phan_hoi_khach","type":"n8n-nodes-base.dataTable","typeVersion":1.1,"position":[820,0]},
{"parameters":{"respondWith":"json","responseBody":"={{ JSON.stringify($('Gắn nội dung gốc').first().json) }}","options":{}},"name":"Trả kết quả","type":"n8n-nodes-base.respondToWebhook","typeVersion":1.5,"position":[1080,0]}
],
"connections":{"Nhận phản hồi":{"main":[[{"node":"AI đọc phản hồi","type":"main","index":0}]]},"Ollama Chat Model":{"ai_languageModel":[[{"node":"AI đọc phản hồi","type":"ai_languageModel","index":0}]]},"AI đọc phản hồi":{"main":[[{"node":"Gắn nội dung gốc","type":"main","index":0}]]},"Gắn nội dung gốc":{"main":[[{"node":"Lưu vào bảng phan_hoi_khach","type":"main","index":0}]]},"Lưu vào bảng phan_hoi_khach":{"main":[[{"node":"Trả kết quả","type":"main","index":0}]]}},
"settings":{"executionOrder":"v1","timezone":"Asia/Ho_Chi_Minh"}}

Template 4: canh website sập mỗi 5 phút

Node Code đầu tiên chứa danh sách website cần canh, sửa ngay trong code. HTTP Request gọi từng trang với Full Response và Never Error bật, timeout 10 giây, phần Settings đặt On Error = Continue để tên miền chết không làm dừng cả workflow. Trang nào không trả mã 200 thì ghi vào bảng website_loi. Nhánh dưới là node Code "Chỉ khi đổi trạng thái" rồi node Telegram.

Canvas template canh website trong n8n: trigger mỗi 5 phút và webhook, danh sách website, gọi thử, tóm tắt kết quả, nhánh IF ghi lỗi vào bảng và nhánh Chỉ khi đổi trạng thái nối node Báo Telegram

Mình canh 3 địa chỉ: trang chủ aidev.edu.vn (200), một trang không tồn tại (404) và một tên miền bịa ra để thử lỗi DNS. Bảng ghi đúng hai dòng lỗi mỗi lần chạy, lỗi DNS có thông báo getaddrinfo ENOTFOUND.

Bảng website_loi trong n8n: mỗi lần chạy ghi một dòng 404 và một dòng mã 0 kèm lỗi getaddrinfo ENOTFOUND

Hai điều mình chỉ thấy khi để chạy thật nửa tiếng. Một là hai lần chạy đầu mất 0,2 giây, từ lần thứ ba trở đi mất 2,1 đến 2,2 giây, gần như toàn bộ chênh lệch nằm ở node Code đầu tiên (1.886 ms so với 9 ms). Mình đoán đó là lúc task runner, tiến trình chạy code của n8n, khởi động lại sau khi rảnh, nhưng chưa đo kỹ để chắc. Với lịch 5 phút thì 2 giây không đáng kể.

Hai là bảng ghi lại cùng một lỗi sau mỗi 5 phút, tức 24 dòng một giờ. Nhắn Telegram kiểu đó thì điện thoại kêu suốt, nên node "Chỉ khi đổi trạng thái" nhớ trạng thái lần trước của từng trang bằng $getWorkflowStaticData và chỉ cho đi tiếp trang vừa đổi từ sống sang lỗi hoặc ngược lại. Lần chạy đầu buổi tối gửi đúng 2 tin (trang 404 và tên miền chết), node Telegram mất 2,0 giây cho cả hai; bốn lần chạy sau đó (2 lần bấm webhook, 2 lần theo lịch 20:40 và 20:45) không gửi tin nào. Theo tài liệu của n8n, static data chỉ lưu khi workflow đã Published và chạy bằng trigger hoặc webhook, bấm Execute trên canvas thì không.

json
{"name":"4. Canh website sập mỗi 5 phút",
"nodes":[
{"parameters":{"rule":{"interval":[{"field":"minutes","minutesInterval":5}]}},"name":"Mỗi 5 phút","type":"n8n-nodes-base.scheduleTrigger","typeVersion":1.2,"position":[0,0]},
{"parameters":{"httpMethod":"GET","path":"kiem-web","responseMode":"onReceived","options":{}},"name":"Chạy thử (webhook)","type":"n8n-nodes-base.webhook","typeVersion":2.2,"position":[0,200]},
{"parameters":{"jsCode":"// Sửa danh sách ở đây\nreturn ['https://aidev.edu.vn', 'https://aidev.edu.vn/trang-khong-ton-tai', 'https://khong-co-ten-mien-nay-aidev.vn']\n  .map(url => ({ json: { url } }));"},"name":"Danh sách website","type":"n8n-nodes-base.code","typeVersion":2,"position":[260,100]},
{"parameters":{"url":"={{ $json.url }}","options":{"response":{"response":{"fullResponse":true,"neverError":true,"responseFormat":"text"}},"timeout":10000,"redirect":{"redirect":{}}}},"name":"Gọi thử","type":"n8n-nodes-base.httpRequest","typeVersion":4.5,"position":[520,100],"onError":"continueRegularOutput"},
{"parameters":{"jsCode":"const ds = $('Danh sách website').all();\nreturn $input.all().map((i, k) => ({ json: {\n  url: ds[k].json.url,\n  ma_http: i.json.statusCode || 0,\n  loi: i.json.error ? String(i.json.error.message || i.json.error).slice(0, 200) : '',\n} }));"},"name":"Tóm tắt kết quả","type":"n8n-nodes-base.code","typeVersion":2,"position":[780,100]},
{"parameters":{"conditions":{"options":{"caseSensitive":true,"typeValidation":"loose","version":2},"conditions":[{"id":"d243512d-f257-4c33-b410-f8d0496a9ebf","leftValue":"={{ $json.ma_http }}","rightValue":200,"operator":{"type":"number","operation":"notEquals"}}],"combinator":"and"},"options":{}},"name":"Có lỗi?","type":"n8n-nodes-base.if","typeVersion":2.2,"position":[1040,100]},
{"parameters":{"resource":"row","operation":"insert","dataTableId":{"__rl":true,"mode":"name","value":"website_loi"},"columns":{"mappingMode":"autoMapInputData","value":{},"matchingColumns":[],"schema":[]},"options":{}},"name":"Ghi lỗi vào bảng","type":"n8n-nodes-base.dataTable","typeVersion":1.1,"position":[1300,0]},
{"parameters":{"jsCode":"// Chỉ báo khi một website đổi trạng thái (sống → lỗi hoặc lỗi → sống), không báo lặp mỗi 5 phút.\n// Trạng thái lần trước giữ trong static data của workflow (chỉ lưu khi chạy production, không lưu khi bấm Execute).\nconst nho = $getWorkflowStaticData('global');\nnho.trang_thai = nho.trang_thai || {};\nconst ra = [];\nfor (const i of $input.all()) {\n  const { url, ma_http, loi } = i.json;\n  const song = ma_http === 200;\n  const truoc = nho.trang_thai[url];\n  if (truoc === undefined ? !song : truoc !== song) {\n    ra.push({ json: { url, ma_http, tin_nhan: song ? `✅ ${url} đã sống lại (HTTP 200)` : `🔴 ${url} lỗi: ${ma_http || loi}` } });\n  }\n  nho.trang_thai[url] = song;\n}\nreturn ra;"},"name":"Chỉ khi đổi trạng thái","type":"n8n-nodes-base.code","typeVersion":2,"position":[1040,320]},
{"parameters":{"resource":"message","operation":"sendMessage","chatId":"CHAT_ID_CUA_BAN","text":"={{ String($json.tin_nhan ?? '').replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\\*\\*/g, '').replace(/^[ \\t]*[*-][ \\t]+/gm, '• ') }}","additionalFields":{"appendAttribution":false,"parse_mode":"HTML"}},"name":"Báo Telegram","type":"n8n-nodes-base.telegram","typeVersion":1.2,"position":[1300,320],"credentials":{"telegramApi":{"name":"Telegram bot thử"}}}
],
"connections":{"Mỗi 5 phút":{"main":[[{"node":"Danh sách website","type":"main","index":0}]]},"Chạy thử (webhook)":{"main":[[{"node":"Danh sách website","type":"main","index":0}]]},"Danh sách website":{"main":[[{"node":"Gọi thử","type":"main","index":0}]]},"Gọi thử":{"main":[[{"node":"Tóm tắt kết quả","type":"main","index":0}]]},"Tóm tắt kết quả":{"main":[[{"node":"Có lỗi?","type":"main","index":0},{"node":"Chỉ khi đổi trạng thái","type":"main","index":0}]]},"Có lỗi?":{"main":[[{"node":"Ghi lỗi vào bảng","type":"main","index":0}]]},"Chỉ khi đổi trạng thái":{"main":[[{"node":"Báo Telegram","type":"main","index":0}]]}},
"settings":{"executionOrder":"v1","timezone":"Asia/Ho_Chi_Minh"}}

Template 5: nhắc thời tiết sáng nay, không cần API key

Lúc 6 giờ sáng, HTTP Request gọi Open-Meteo, dịch vụ dự báo thời tiết miễn phí không cần đăng ký, lấy nhiệt độ thấp nhất, cao nhất và khả năng mưa của Hà Nội. Node Code viết thành một câu nhắc. Muốn đổi sang thành phố khác thì sửa latitude và longitude.

bash
$ curl http://localhost:5678/webhook/thoi-tiet
{"ngay":"2026-10-14","tin_nhan":"Hà Nội hôm nay 25–32°C, khả năng mưa 53%. Có thể mưa, cất áo mưa trong cốp xe."}
Canvas template thời tiết sáng nay trong n8n: trigger 6h sáng và webhook chạy thử, node Lấy dự báo Open-Meteo và node Code viết câu nhắc

Sau node Code là node Telegram gửi câu nhắc. Buổi tối mình chạy hai lần: 4,4 giây và 1,9 giây cho cả workflow, riêng phần gọi Open-Meteo mất 0,95 giây và gửi Telegram 0,91 giây.

json
{"name":"5. Thời tiết sáng nay",
"nodes":[
{"parameters":{"rule":{"interval":[{"field":"days","triggerAtHour":6}]}},"name":"6h sáng hằng ngày","type":"n8n-nodes-base.scheduleTrigger","typeVersion":1.2,"position":[0,0]},
{"parameters":{"httpMethod":"GET","path":"thoi-tiet","responseMode":"lastNode","options":{}},"name":"Chạy thử (webhook)","type":"n8n-nodes-base.webhook","typeVersion":2.2,"position":[0,200]},
{"parameters":{"url":"https://api.open-meteo.com/v1/forecast","sendQuery":true,"queryParameters":{"parameters":[{"name":"latitude","value":"21.03"},{"name":"longitude","value":"105.85"},{"name":"daily","value":"temperature_2m_max,temperature_2m_min,precipitation_probability_max"},{"name":"timezone","value":"Asia/Bangkok"},{"name":"forecast_days","value":"1"}]},"options":{}},"name":"Lấy dự báo Open-Meteo","type":"n8n-nodes-base.httpRequest","typeVersion":4.5,"position":[260,100]},
{"parameters":{"jsCode":"const d = $input.first().json.daily;\nconst thap = Math.round(d.temperature_2m_min[0]), cao = Math.round(d.temperature_2m_max[0]), mua = d.precipitation_probability_max[0];\nlet nhac = mua >= 60 ? 'Nhớ mang áo mưa.' : mua >= 30 ? 'Có thể mưa, cất áo mưa trong cốp xe.' : 'Trời khô, không cần áo mưa.';\nif (cao >= 35) nhac += ' Nắng nóng, uống đủ nước.';\nreturn [{ json: { ngay: d.time[0], tin_nhan: `Hà Nội hôm nay ${thap}–${cao}°C, khả năng mưa ${mua}%. ${nhac}` } }];"},"name":"Viết lời nhắc","type":"n8n-nodes-base.code","typeVersion":2,"position":[520,100]},
{"parameters":{"resource":"message","operation":"sendMessage","chatId":"CHAT_ID_CUA_BAN","text":"={{ String($json.tin_nhan ?? '').replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\\*\\*/g, '').replace(/^[ \\t]*[*-][ \\t]+/gm, '• ') }}","additionalFields":{"appendAttribution":false,"parse_mode":"HTML"}},"name":"Gửi Telegram","type":"n8n-nodes-base.telegram","typeVersion":1.2,"position":[780,100],"credentials":{"telegramApi":{"name":"Telegram bot thử"}}}
],
"connections":{"6h sáng hằng ngày":{"main":[[{"node":"Lấy dự báo Open-Meteo","type":"main","index":0}]]},"Chạy thử (webhook)":{"main":[[{"node":"Lấy dự báo Open-Meteo","type":"main","index":0}]]},"Lấy dự báo Open-Meteo":{"main":[[{"node":"Viết lời nhắc","type":"main","index":0}]]},"Viết lời nhắc":{"main":[[{"node":"Gửi Telegram","type":"main","index":0}]]}},
"settings":{"executionOrder":"v1","timezone":"Asia/Ho_Chi_Minh"}}

Template 6: bot Telegram trả lời khách bằng AI chạy trên máy

Template này nhận tin nhắn gửi tới bot bằng node Telegram Trigger, đưa cho gemma4:e4b trả lời tối đa 3 câu tiếng Việt, rồi gửi lại đúng cuộc trò chuyện đó (trả lời thẳng vào tin của khách).

Canvas template bot Telegram trong n8n: Tin nhắn Telegram, AI trả lời nối Ollama Chat Model, Gửi trả lời

Telegram Trigger cần một địa chỉ HTTPS công khai để Telegram gọi tới. Máy mình thuê không có IP public, nên mình dùng Cloudflare Tunnel bản nhanh (không cần tài khoản), có URL sau 5 giây, rồi khai URL đó cho n8n:

bash
$ cloudflared tunnel --no-autoupdate --url http://127.0.0.1:5678
|  https://<tên-ngẫu-nhiên>.trycloudflare.com
$ printf "N8N_WEBHOOK_URL=https://<tên-ngẫu-nhiên>.trycloudflare.com/\nN8N_PROXY_HOPS=1\n" >> .env
$ docker compose up -d

Bấm Publish là n8n tự đăng ký webhook với Telegram, getWebhookInfo trả về đúng URL trên kèm "allowed_updates":["message"]. Lưu ý tunnel mở ra Internet cả trang quản trị n8n chứ không riêng webhook; URL ngẫu nhiên và có mật khẩu chủ, nhưng chạy lâu dài thì nên dùng tên miền riêng như bài tự host n8n.

Mình nhắn thử 3 tin, thời gian tính từ lúc gửi tới lúc bot trả lời theo giờ của chính Telegram:

Tin nhắn

Bot trả lời sau

Node Ollama

Gửi trả lời

/start (20:36)

17 s

15,4 s

0,94 s

Shop mở cửa mấy giờ? (20:52)

16 s

14,7 s

0,86 s

Có giao hàng không? (ngay sau đó)

7 s

5,7 s

0,89 s

Hai tin đầu chậm vì model phải nạp lại vào RAM: Ollama mặc định chỉ giữ model trong RAM 5 phút sau lần dùng cuối, tin thứ ba tới khi model còn nằm sẵn nên chỉ mất 7 giây. Bot cần trả lời nhanh suốt ngày thì đặt OLLAMA_KEEP_ALIVE dài hơn cho dịch vụ Ollama.

Chỗ đáng lo hơn là nội dung. Hỏi "Shop mở cửa mấy giờ?", bot trả lời chắc nịch "từ 8 giờ sáng đến 8 giờ tối", dù prompt đã dặn không biết thì nói không biết và mình không đưa giờ mở cửa nào cả. Trước khi cho khách thật nhắn, bạn phải viết đủ thông tin cửa hàng (giờ mở cửa, phí giao, chính sách đổi trả) vào ô System Message của node AI trả lời, hoặc nối thêm tool tra cứu như bài n8n là gì làm với quán phở.

json
{"name":"6. Bot Telegram trả lời bằng AI",
"nodes":[
{"parameters":{"updates":["message"],"additionalFields":{}},"name":"Tin nhắn Telegram","type":"n8n-nodes-base.telegramTrigger","typeVersion":1.2,"position":[0,0],"credentials":{"telegramApi":{"name":"Telegram bot thử"}}},
{"parameters":{"promptType":"define","text":"={{ $json.message.text }}","messages":{"messageValues":[{"message":"Bạn là trợ lý của một cửa hàng nhỏ ở Việt Nam. Trả lời bằng tiếng Việt, ngắn gọn, tối đa 3 câu. Không biết thì nói không biết."}]}},"name":"AI trả lời","type":"@n8n/n8n-nodes-langchain.chainLlm","typeVersion":1.9,"position":[260,0]},
{"parameters":{"model":"gemma4:e4b","options":{"think":false,"temperature":0.2}},"name":"Ollama Chat Model","type":"@n8n/n8n-nodes-langchain.lmChatOllama","typeVersion":1,"position":[260,220],"credentials":{"ollamaApi":{"name":"Ollama trên máy"}}},
{"parameters":{"resource":"message","operation":"sendMessage","chatId":"={{ $('Tin nhắn Telegram').item.json.message.chat.id }}","text":"={{ String($json.text ?? '').replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\\*\\*/g, '').replace(/^[ \\t]*[*-][ \\t]+/gm, '• ') }}","additionalFields":{"appendAttribution":false,"reply_to_message_id":"={{ $('Tin nhắn Telegram').item.json.message.message_id }}","parse_mode":"HTML"}},"name":"Gửi trả lời","type":"n8n-nodes-base.telegram","typeVersion":1.2,"position":[560,0],"credentials":{"telegramApi":{"name":"Telegram bot thử"}}}
],
"connections":{"Tin nhắn Telegram":{"main":[[{"node":"AI trả lời","type":"main","index":0}]]},"Ollama Chat Model":{"ai_languageModel":[[{"node":"AI trả lời","type":"ai_languageModel","index":0}]]},"AI trả lời":{"main":[[{"node":"Gửi trả lời","type":"main","index":0}]]}},
"settings":{"executionOrder":"v1","timezone":"Asia/Ho_Chi_Minh"}}

Lỗi tôi đã gặp khi nạp và chạy template

Chọn bảng theo ID rồi nạp sang máy khác. Bản đầu tiên của mình chọn bảng theo ID. Nạp sang instance khác, workflow vẫn publish được nhưng chạy thì báo:

text
Data table with ID 'MaBangMayKhac01' could not be found in this project

Cách sửa: trong node Data table, đổi ô Data table sang chế độ By Name và ghi tên bảng. Các file trong bài đã dùng cách này.

Credential Ollama để mặc định localhost. Node Ollama Chat Model báo lỗi sau 13 ms, webhook trả về HTTP 500:

text
fetch failed
{"message":"Error in workflow"}

Bên trong container n8n, localhost là chính container đó, không phải máy chạy Ollama. Đổi URL credential thành http://host.docker.internal:11434 và thêm extra_hosts như ở phần chuẩn bị.

Gửi bản tin của model sang Telegram. Lần đầu node Telegram để Parse Mode trống, bản tin của AI có **…** và gạch đầu dòng *, Telegram từ chối:

text
Bad request - please check your parameters
Bad Request: can't parse entities: Can't find end of the entity starting at byte offset 374
Node Gửi bản tin Telegram báo lỗi Bad request can't parse entities khi chưa đặt Parse Mode, chat_id đã che

Cách sửa trong cả 5 file có gửi tin: đặt Parse Mode là HTML, đổi &, <, > thành &amp;, &lt;, &gt; và bỏ dấu ** ngay trong ô Text. Sau khi sửa, mình chạy lại cả 5 workflow có gửi tin, không còn lỗi.

File JSON thiếu cài đặt On Error. Script xuất file của mình ban đầu chỉ chép tham số node, làm rơi mất dòng "onError":"continueRegularOutput" của node Gọi thử. Nạp lại template 4, gặp tên miền chết là cả workflow dừng:

text
The connection cannot be established, this usually occurs due to an incorrect host (domain) value

File trong bài đã có lại dòng đó. Bạn tự sửa workflow của mình thì vào Settings của node HTTP Request, mục On Error chọn Continue.

Gọi webhook ngay sau khi bấm Publish. Chưa tới một giây sau khi publish mình gọi thử thì nhận 404. Đợi 5 giây gọi lại thì chạy bình thường:

text
{"code":404,"message":"The requested webhook \"GET thu-bang\" is not registered.","hint":"The workflow must be active for a production URL to run successfully. ..."}

Khi nào không nên dùng template sẵn?

  • Việc của bạn có tiền hoặc dữ liệu khách nhạy cảm (tính tiền, chốt đơn, hoàn tiền): template là điểm xuất phát, phải tự thử từng trường hợp lạ trước khi bật. Model 4B trong bài vẫn đổi nghĩa một tin và xếp sai 2 trên 12 chủ đề.

  • Bạn cần n8n workflow có AI trả lời ngay trong vài giây cho khách đang chờ: model chạy bằng CPU mất khoảng 10 giây mỗi câu. Lúc đó nên chạy model trên GPU hoặc dùng API của nhà cung cấp.

  • Bạn chỉ có một hai việc nhỏ mà chưa có máy chủ: n8n lúc rảnh đã chiếm 543 MiB RAM, cộng các container đi kèm của bản cài một dòng là khoảng 0,7 GB. Một nhắc nhở mỗi sáng thì dùng tính năng hẹn giờ của điện thoại còn nhanh hơn.

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

Template n8n lấy ở đâu?

Thư viện chính thức ở n8n.io/workflows, lọc theo ứng dụng và chủ đề. Trên GitHub cũng có nhiều repo gom template; trước khi nạp, mở file JSON xem có URL lạ hoặc header chứa khóa không.

Chạy AI trong workflow có cần GPU không?

Không bắt buộc. Template 2, 3 và 6 trong bài chạy trên máy CPU 16 nhân 32GB, model gemma4:e4b chiếm 1,9 GB RAM, mỗi phản hồi mất khoảng 10 giây, câu đầu tiên lâu hơn vì phải nạp model. GPU giúp nhanh hơn nhiều khi phải xử lý hàng trăm tin mỗi giờ.

Nạp template có lấy mất credential của mình không?

Không. File chỉ chứa tên credential, không chứa khóa hay token bot. Sau khi nạp, bạn chọn hoặc tạo credential của mình. Nếu đặt tên trùng với tên trong file, n8n tự gắn sẵn.

Template cũ có node Cron, Function còn dùng được không?

Trên n8n 2.x vẫn mở và chạy được. Bản thử nghiệm n8n 3 mình cài ngày 08/10/2026 đã xóa các node này, publish workflow kiểu cũ báo Unrecognized node type: n8n-nodes-base.cron. Sáu template trong bài dùng Schedule Trigger và Code nên không bị. Chi tiết có trong bài n8n 3.0 có gì mới.

Đọc tiếp

  • n8n là gì: workflow đầu tiên, tỷ giá mỗi sáng, trợ lý AI tính tiền cho quán phở.

  • Tự host n8n bằng Docker: chọn VPS, khóa cổng 5678, gắn HTTPS.

  • n8n MCP: nhờ Claude Code dựng và chạy workflow cho bạn.

  • Ollama là gì: chọn model AI chạy trên máy riêng.

Muốn có n8n chạy việc thật cho cửa hàng hay công ty mà không tự lo cài đặt, sao lưu, cảnh báo khi workflow chết, AIDev nhận cài n8n tự host trên máy chủ của bạn và bàn giao toàn quyền. Còn nếu chỉ muốn thử 6 template trong bài, AIDev Cloud cho thuê máy theo giờ: máy CPU 16 nhân 32GB mình dùng có giá 3.000 đồng/giờ ngày 14/10/2026.

Chạy ngày 14/10/2026 (buổi chiều, phần Telegram buổi tối từ 20:30 đến 20:55) trên máy CPU Standard (16 nhân Xeon E5-2600 v4, 32GB RAM, Ubuntu 24.04, không GPU) của AIDev Cloud: n8n 2.43.5 cài bằng get-n8n.sh v1.4.0, Docker 29.6.1, Ollama 0.40.4, model gemma4:e4b và qwen3.5:4b, cloudflared 2026.10.0.

Tham vấn chuyên môn

Nguyễn Việt Chung

Nhà sáng lập AIDev và VietPlatform · Thạc sĩ AI MSE

  • Tốt nghiệp thủ khoa xuất sắc Thạc sĩ AI MSE.
  • Đồng sáng lập, CTO E-University, SVOnline: số hóa 10+ đại học, 40.000+ sinh viên.
  • Xây hệ thống AI cho doanh nghiệp tại VietPlatform.
Biên soạn: AIDev Team · Rà soát · Quy trình biên tập