Bỏ qua tới nội dung
Kiên

VNTRIP Assistant — bản pilot lõi AI vận hành, biết chuyển người thay vì đoán

Bản thử nghiệm làm trong tháng 10/2026, chưa chạy production: chín kênh đầu vào chuẩn hoá về một dạng sự kiện, bộ phân loại ý định nhiều tầng chuyển mỗi lượt cho đúng một trong 10 agent nghiệp vụ, và guardrail đẩy mọi thứ rủi ro sang người thật thay vì để model đoán.

Thời gian
10/2026 — pilot, chưa lên production
Vai trò
Xây service lõi của bản pilot

Công nghệ

  • NestJS 10
  • Fastify
  • TypeScript
  • PostgreSQL + pgvector
  • Redis
  • n8n
  • Socket.IO
  • BGE-M3 trên llama.cpp

Trạng thái: bản pilot / prototype làm trong tháng 10/2026. Mới chạy ở local, chưa lên production. Mọi thứ bên dưới mô tả đúng những gì code đang làm, và phần nào mới chỉ thiết kế thì ghi rõ là thiết kế.

Vấn đề

Tin nhắn vận hành ở VNTRIP đến từ rất nhiều kênh, và lỗi đắt nhất không phải là trả lời sai — mà là tin nhắn không ai nhận. Một trợ lý đoán bừa còn tệ hơn không có trợ lý, nên lõi phải được xây quanh việc biết khi nào không trả lời.

Đầu vào: chín kênh, một sự kiện, xử lý đúng một lần

Chín kênh — Telegram, email qua IMAP, Zalo OA (khách hàng và nội bộ), Chatwoot (kể cả Zalo cá nhân), tổng đài (cuộc gọi nhỡ và ghi âm), chat TMS, Copilot và Mattermost — đi qua các workflow n8n chuẩn hoá về một dạng sự kiện.

Phía backend nhận sự kiện theo kiểu idempotent: claim sự kiện, rồi INSERT … ON CONFLICT DO NOTHING cùng FOR UPDATE SKIP LOCKED để hai worker không bao giờ xử lý trùng một sự kiện, tối đa 3 lần thử, rồi complete. Kênh nào gửi lại webhook cũng không đẻ ra ticket thứ hai.

Định tuyến: phân loại nhiều tầng, đúng một agent mỗi lượt

Ý định được phân loại theo tầng, rẻ trước đắt sau, và một tầng chỉ được trả lời khi vượt ngưỡng tự tin của nó:

Tầng Là gì Ngưỡng
Luật 17 ý định, 135 cụm từ trên văn bản đã bỏ dấu, luật thực thể cho mã đơn và PNR 0.85
kNN ví dụ đã gán nhãn gần nhất — mới lên kế hoạch 0.85
LLM nhỏ model rẻ cho những gì luật không xếp được 0.7
LLM mạnh phương án cuối 0.5

Đầu ra là đúng một agent cho mỗi lượt, và điều đó được ép bằng kiểu dữ liệu chứ không phải quy ước — không có đường code nào chia một lượt cho hai agent.

Agent dưới thang tự chủ

Có 10 agent nghiệp vụ. Vé máy bay, khách sạn và knowledge đã chạy trong pilot; hậu booking, tài chính, doanh nghiệp, điều phối, chất lượng, chủ động và sourcing mới ở mức thiết kế.

Mỗi hành động nằm trên một bậc tự chủ: T0 đọc, T1 ghi nội bộ, T2 gửi ra ngoài, T3 đụng tới tiền hoặc chỗ. Pilot chỉ thực thi T0 và T1. Mọi thứ ở T2 hay T3 luôn chuyển cho người thật.

Guardrail

  • Che dữ liệu cá nhân qua PII vault ở mọi lần gọi LLM, embedding và rerank — thông tin cá nhân được thay thế trước khi bất kỳ model nào nhìn thấy văn bản.
  • Sáu chủ đề hạn chế — visa, xuất nhập cảnh, pháp lý, bồi thường, số tiền hoàn và hoá đơn VAT — chuyển ngay cho người thật.
  • Gắn cờ các lần thử prompt injection.
  • Câu trả lời từ knowledge base phải trích nguồn từng câu, có kiểm tra khẳng định chưa được xác minh; không bám được nguồn thì từ chối trả lời. Cách làm nằm ở bài viết về RAG.

Ticket, SLA và realtime

Máy trạng thái ticket với 9 trạng thái, 31 bước chuyển và 19 loại ticket. SLA chạy trên engine giờ hành chính theo lịch nghỉ lễ Việt Nam — 8 đồng hồ, một scanner 30 giây dùng SKIP LOCKED, cảnh báo tới Telegram và Mattermost gửi qua outbox.

Sự kiện realtime qua Socket.IO chỉ phát sau khi commit, nên màn hình không bao giờ hiện một trạng thái mà database đã rollback. Mọi tương tác được giữ trong log chỉ ghi thêm, đã che dữ liệu cá nhân.

Con số

Khoảng 50 nghìn dòng TypeScript, khoảng 5,4 nghìn dòng SQL viết tay, và 1.182 unit test.

Trong lần chạy pilot ở local với LLM tắt hẳn, nhánh knowledge trả lời 99 câu hỏi từ knowledge base có trích nguồn, p50 khoảng 1,9–2,4 giây, và thành thật trả "không có nguồn" cho 33 câu khác — đúng hành vi mà cả thiết kế được dựng lên để bảo vệ.