tiandao1707/qwen3.5-0.8b-vi-ticket-triage-lora
LoRA — phân loại ticket CSKH tiếng Việt → JSON triage
Adapter LoRA cho Qwen/Qwen3.5-0.8B, huấn luyện cho một việc: đọc một ticket chăm sóc khách hàng tiếng Việt và trả về đúng một object JSON 4 khoá (intent, urgency, product, sentiment).
Đây là bài nộp Lab 21 (AICB-P2T3 · Ngày 21 — Fine-tuning & An Toàn) của Lê Quang Đức · 2A202601767. Toàn bộ code, dữ liệu, artefact đo đạc và báo cáo: 👉 https://github.com/leduc1707/K3-Track03-Lab21-2A202601767-LeQuangDuc
⚠ Đọc trước khi dùng: adapter này KHÔNG đạt cổng chất lượng
Lab yêu cầu chứng minh bản fine-tune thắng được chính base model đã được prompt tử tế. Nó không thắng:
Phán quyết: FAILED (target Δ −0.135). Với bài toán này, viết một prompt tốt cho base model vẫn hơn — và không tốn giây huấn luyện nào.
Adapter được publish để tái lập được kết quả đã báo cáo, không phải để dùng thật.
Nó mua được gì
- `format` 0.000 → 1.000. Với đúng một câu prompt
"Phân loại ticket sau.", base model trả về văn xuôi (0.000); adapter trả JSON đủ 4 khoá 50/50 lần. Hợp đồng đầu ra đã chuyển từ prompt vào trọng số — prompt ngắn hơn 31 lần (21 ký tự so với 658). - Nhanh nhất trong ba: 7746 ms/mẫu, nhanh hơn base-có-prompt-tốt 12%, nhanh hơn base-prompt-ngắn 2,3 lần.
- Không quên thảm hoạ:
regression0.556 → 0.644 (+0.089), tức năng lực phổ thông còn tăng.
Nó hỏng ở đâu — mẫu hỏng rất cụ thể
Adapter bịa ra giá trị enum không tồn tại: thong_tinh, thong_tich, tich_tuc, tich_tinh, thuc_tinh, tieu_dien. Không cái nào nằm trong không gian nhãn, nhưng cái nào cũng là mảnh ghép của nhãn thật (hoi_thong_tin, tich_cuc, tieu_cuc) — nó học được hình dáng của bộ từ vựng nhãn chứ chưa học được chính bộ từ vựng.
Hai lỗi kèm theo: lẫn trường (điền urgency: trung_tinh, vốn là giá trị của sentiment) và cắt cụt tên sản phẩm (balo laptop → laptop).
Nếu dùng thật, bắt buộc phải validate output theo enum và từ chối giá trị lạ.
Nguyên nhân: ngân sách huấn luyện, và một bất ngờ
Adapter chỉ được train 15 optimizer step (≈30 ví dụ) vì máy chạy lab không có GPU (Intel i5-1135G7, 8 GB RAM, chạy CPU bf16 — mỗi step ~133 giây).
Giả thuyết đầu tiên là "thiếu dữ liệu". Nó sai: một adapter r=64 train trên đúng 30 ví dụ đó, đúng 15 bước đó đạt target 0.520 — vượt cả prompt tối ưu. Thứ thiếu là sức chứa của adapter, không phải số ví dụ.
Nhưng r=64 cũng không dùng được: regression của nó tụt xuống 0.067 (Δ −0.489) — quên thảm hoạ gần như sạch. Hai cấu hình, hai kiểu trượt khác nhau, không cấu hình nào ship được. Chi tiết ở mục 5 và phụ lục B4 của báo cáo.
Cấu hình huấn luyện
Dùng thế nào
from peft import PeftModel
from transformers import AutoModelForCausalLM, AutoTokenizer
BASE = "Qwen/Qwen3.5-0.8B"
tok = AutoTokenizer.from_pretrained(BASE)
model = AutoModelForCausalLM.from_pretrained(BASE, dtype="auto")
model = PeftModel.from_pretrained(model, "tiandao1707/qwen3.5-0.8b-vi-ticket-triage-lora")
model.eval()
msgs = [
{"role": "system", "content": "Phân loại ticket sau."}, # prompt lúc train — phải giữ nguyên
{"role": "user", "content": "Shop ơi, đơn DH556677 mua bàn phím cơ đã 5 ngày chưa giao, mình cần gấp."},
]
text = tok.apply_chat_template(msgs, tokenize=False, add_generation_prompt=True, enable_thinking=False)
out = model.generate(**tok(text, return_tensors="pt"), max_new_tokens=160, do_sample=False)
print(tok.decode(out[0][len(tok(text)["input_ids"]):], skip_special_tokens=True))System prompt phải đúng là `"Phân loại ticket sau."` — adapter được train với đúng chuỗi đó ở vai system và ticket trần ở vai user. Đổi prompt lúc chạy so với lúc train là lỗi đã từng làm mọi adapter của lab này ăn 0.000 trong khi loss vẫn đẹp.
Không gian nhãn
intent ∈ doi_tra | van_chuyen | hoan_tien | san_pham_loi | hoi_thong_tin
urgency ∈ cao | trung_binh | thap
sentiment ∈ tieu_cuc | trung_tinh | tich_cuc
product = tên sản phẩm xuất hiện nguyên văn trong ticketGiới hạn
- Dữ liệu huấn luyện là corpus tổng hợp (sinh xác định bởi
scripts/make_seed_data.py), không phải ticket thật. Cách hành văn thật của khách hàng đa dạng hơn nhiều. - Chỉ tiếng Việt, chỉ miền thương mại điện tử.
- Đánh giá trên 50 mẫu — mọi khoảng cách nhỏ hơn ~0.05 nên coi là nhiễu.
- Không kiểm tra an toàn, thiên kiến, hay dữ liệu cá nhân. Ticket thật thường chứa tên, số điện thoại, địa chỉ.
