Phân loại chi phí là gắn mỗi giao dịch vào một danh mục kế toán: Chi phí văn phòng, Marketing, Lương, Thuê mặt bằng... Làm tay thì nhàm và thiếu nhất quán; đây là việc LLM làm rất tốt — nếu bạn ràng buộc đúng.
Kiến trúc lai: rule trước, LLM sau
Đừng dùng LLM cho mọi dòng. Nhiều giao dịch lặp lại có thể phân loại bằng luật rẻ và chắc:
Bước 1: Rule khớp mẫu -> "Grab", "Be" => Đi lại; "VNPT","Viettel" => Viễn thông
Bước 2: Bộ nhớ đã học -> đối tác này kỳ trước gắn nhãn gì?
Bước 3: LLM phân loại -> phần còn lại, chọn trong danh mục cố định
Danh mục là tập đóng
LLM phải chọn trong danh sách cố định (chart of accounts), không được tự nghĩ ra nhãn mới — nếu không, báo cáo sẽ loạn.
CATEGORIES = [
"Chi phí văn phòng", "Marketing & Quảng cáo", "Lương & Phúc lợi",
"Thuê mặt bằng", "Đi lại & Công tác", "Viễn thông & Internet",
"Nguyên vật liệu", "Thuế & Phí", "Khác"
]
def classify(txn, llm):
prompt = f"""Phân loại giao dịch sau vào ĐÚNG MỘT danh mục.
Giao dịch: {txn['description']} | {txn['amount']} VND | ĐT: {txn['counterparty']}
Danh mục hợp lệ (chỉ chọn 1, không tạo mới): {CATEGORIES}
Nếu không chắc, chọn 'Khác' và giải thích.
Trả JSON: {{"category": "...", "confidence": 0..1, "reason": "..."}}"""
res = llm.json(prompt)
assert res["category"] in CATEGORIES # chốt chặn
return res
Học từ phản hồi (feedback loop)
Khi kế toán sửa nhãn của agent, hãy lưu lại thành luật ưu tiên cho lần sau:
def remember_correction(counterparty, correct_cat):
memory[normalize(counterparty)] = correct_cat
# lần sau, nếu counterparty đã có trong memory -> dùng luôn, bỏ qua LLM
Sau vài kỳ, phần lớn giao dịch được phân loại bằng bộ nhớ, LLM chỉ xử lý cái mới — vừa rẻ vừa nhất quán.
Ví dụ cụ thể
"GRAB *TRIP 06" | -85.000 → rule khớp "GRAB" → Đi lại & Công tác, khỏi cần LLM.
"TT DV THIET KE BANNER FB" | -2.000.000 → không rule nào khớp → LLM đọc "thiết kế banner FB" → Marketing & Quảng cáo, confidence 0.88.
Ngưỡng tin cậy và cờ soát
if res["confidence"] < 0.7:
txn["category"] = res["category"]
txn["flag_review"] = True # gắn nhãn nhưng đánh dấu cần kế toán soát
Mẹo thực chiến: chọn ngưỡng dựa trên hậu quả sai. Với danh mục ảnh hưởng thuế (ví dụ phân biệt "Chi phí được trừ" và "không được trừ"), hãy đặt ngưỡng cao hơn và soát kỹ hơn, vì phân loại sai ở đây có thể dẫn tới rủi ro khi quyết toán thuế. Với danh mục nội bộ thuần túy (chỉ phục vụ báo cáo quản trị), ngưỡng có thể thấp hơn.
Xử lý giao dịch mơ hồ
Một số mô tả sao kê cực kỳ tối nghĩa như "TT TIEN 06" hay "CK NHANH". Đừng ép LLM đoán bằng mọi giá. Hãy cấu hình để những dòng này mặc định về "Khác" kèm cờ review, và nếu có thể, làm giàu dữ liệu bằng ngữ cảnh khác: mã đối tác, số tài khoản người nhận, lịch sử giao dịch cùng đối tác đó. Ngữ cảnh càng giàu, LLM phân loại càng chính xác — thà đầu tư vào chất lượng input còn hơn kỳ vọng LLM "thần thánh" từ một chuỗi mô tả rỗng nghĩa.
Checklist phân loại
- [ ] Danh mục là tập đóng, có assert chốt chặn?
- [ ] Có tầng rule/bộ nhớ trước LLM?
- [ ] LLM luôn trả kèm confidence và reason?
- [ ] Dòng tin cậy thấp bị gắn cờ review?
- [ ] Có lưu chỉnh sửa của người để học?
Sai lầm thường gặp
- Cho LLM tự bịa danh mục: tạo ra "Chi phí lặt vặt", "Misc 2"... báo cáo hỗn loạn. Ép tập đóng + assert.
- Dùng LLM cho cả giao dịch lặp: đốt token vô ích. Rule/bộ nhớ xử phần lặp.
- Không lưu phản hồi: agent lặp lại cùng lỗi mỗi kỳ. Xây feedback loop.
- Tin 100% mọi nhãn LLM: phân loại sai làm lệch báo cáo thuế. Gắn cờ khi confidence thấp.