Product Management
Đăng nhập
ESC

Nhập từ khóa để tìm kiếm

↑↓ Di chuyển
Enter Mở
ESC Đóng

Bài 3 — Trích xuất trường: từ text lộn xộn ra JSON có cấu trúc

Đã đọc 0/9 mục · còn khoảng 3 phút
Cách chúng tôi ghi nhận

Một mục được tính là đã đọc khi nó nằm giữa màn hình đủ lâu so với độ dài của nó (bảng và sơ đồ tính một nửa), bạn vẫn đang cuộn hoặc bấm phím, và bạn đã thấy tới cuối mục. Lướt nhanh hoặc để tab mở không được tính. Chúng tôi chỉ lưu thời gian đọc từng mục — không lưu gì khác.

Sau OCR, bạn có một khối text hỗn độn. Bước này biến nó thành dữ liệu máy dùng được: một JSON với các trường chuẩn. Đây là trái tim của agent.

Hai trường phái trích xuất

  • Regex/luật (rule-based) — dùng biểu thức chính quy tìm mẫu cố định (mã số thuế 10-13 số, ngày dd/mm/yyyy). Nhanh, rẻ, chính xác tuyệt đối khi mẫu ổn định. Nhưng giòn: nhà cung cấp đổi bố cục là gãy.
  • LLM trích xuất theo schema — mô tả các trường cần lấy, để model đọc hiểu và điền. Linh hoạt với bố cục lạ, nhưng có thể "bịa" (hallucinate) và chậm/tốn hơn.
Chiến lược thắng cuộc trong thực chiến: kết hợp. Dùng regex cho trường có mẫu cứng (MST, ngày, số tiền), dùng LLM cho trường ngữ nghĩa (tên hàng hóa, điều khoản).

Định nghĩa schema trước — luôn luôn

Đừng để model tự do trả về. Ép nó theo một khuôn (JSON Schema):

{
  "so_hoa_don": "string | null",
  "ngay": "YYYY-MM-DD | null",
  "mst_nguoi_ban": "string | null",
  "tien_hang": "number | null",
  "thue_vat": "number | null",
  "tong_tien": "number | null",
  "do_tin_cay": "0..1"
}

Trường null khi không tìm thấy — cấm bịa. Trường do_tin_cay để dùng cho việc phân làn ở bài sau.

Prompt trích xuất mẫu (dùng cho LLM)

Bạn là bộ trích xuất hóa đơn. Chỉ dùng thông tin có trong VĂN BẢN dưới đây.
Nếu không tìm thấy một trường, trả về null — TUYỆT ĐỐI không suy đoán.
Số tiền trả về dạng số, bỏ dấu chấm phân cách nghìn.
Trả về đúng JSON theo schema, không thêm chữ nào ngoài JSON.

SCHEMA: {...}
VĂN BẢN:
"""
<text OCR>
"""

Ba câu lệnh vàng: "chỉ dùng thông tin có trong văn bản", "không tìm thấy → null", "trả về đúng JSON". Thiếu chúng, model sẽ bịa số đẹp.

Trích trường cứng bằng regex (đáng tin hơn LLM cho con số)

import re

def extract_mst(text):
    m = re.search(r"\b(\d{10}(?:-\d{3})?)\b", text)  # 10 hoặc 13 số
    return m.group(1) if m else None

def extract_amounts(text):
    # 12.500.000 hoặc 12,500,000
    return [int(x.replace(".", "").replace(",", ""))
            for x in re.findall(r"\d{1,3}(?:[.,]\d{3})+", text)]

Với con số tiền và MST, regex đáng tin hơn LLM vì không có chỗ cho "sáng tạo".

Khung tư duy: mỗi trường một mức tin cậy

Gắn cho mỗi trường một cờ nguồn gốc:

NguồnĐộ tin cậyXử lý
Regex khớp duy nhấtCaoChấp nhận
LLM + có trong textTrung bìnhĐối chiếu chéo
LLM nhưng text mờThấpGắn cờ người duyệt
Đối chiếu chéo (cross-check): nếu regex và LLM cùng ra một số tiền → rất chắc. Lệch nhau → cờ Vàng.

Các bước triển khai

  • Viết schema JSON cho loại tài liệu.
  • Trích trường cứng bằng regex trước (MST, ngày, số tiền).
  • Trích trường mềm bằng LLM theo schema, ép trả null khi thiếu.
  • Đối chiếu chéo những trường cả hai cùng lấy được.
  • Chuẩn hóa định dạng: ngày về YYYY-MM-DD, tiền về số nguyên đồng.
  • Sinh do_tin_cay tổng hợp từ mức tin cậy từng trường.

Checklist trích xuất

  • [ ] Có schema JSON cố định
  • [ ] Regex phủ hết trường có mẫu cứng
  • [ ] Prompt ép "null khi không thấy"
  • [ ] Có bước đối chiếu chéo regex vs LLM
  • [ ] Ngày và tiền đã chuẩn hóa định dạng

Sai lầm thường gặp

  • Để LLM trả tự do dạng văn xuôi — không parse nổi. Luôn ép JSON schema.
  • Tin LLM tuyệt đối với con số — nó bịa số "hợp lý". Dùng regex cho tiền.
  • Quên chuẩn hóa định dạng — 1.500.000 và 1500000 lẫn lộn phá vỡ mọi phép tính sau.
  • Không lưu vị trí trường — khi cần người duyệt, họ không biết số đó lấy từ đâu trên trang. Lưu tọa độ nếu OCR hỗ trợ.
Đã có JSON, bài sau ta kiểm tra tính đúng đắn và tra soát điều khoản.

Học xong bài này rồi? Tạo tài khoản miễn phí để lưu lại — lần sau vào là biết ngay đang dở ở đâu, và học hết khóa thì có chứng chỉ. Lưu tiến độ của tôi