Đừng trích PDF nếu chưa chấm từng field

Đừng trích PDF nếu chưa chấm từng field

Playbook cho team builder biến PDF thành JSON: không bắt đầu từ model, mà từ schema, bộ test nhiễu và cách chấm lỗi theo từng field.

9 giờ sáng, Linh — tech lead của một team SaaS ở Sài Gòn — nhận một yêu cầu nghe rất quen: “Em làm giúp cái AI đọc PDF research paper rồi trả JSON nhé. Miễn đúng là được.”

Ba tiếng sau, demo chạy ngon. Upload PDF, model trả ra title, authors, dataset, metric, repo link. Cả phòng gật gù như vừa uống được ly cold brew tỉnh người.

Đến chiều, product manager hỏi một câu làm ly cà phê đổ ngang: “Nếu nó lấy nhầm validation metric thành test metric thì sao?”

Im lặng.

Đây là chỗ nhiều team xây hệ thống AI bị trượt: họ nghĩ bài toán là trích xuất PDF sang JSON. Nhưng với production, bài toán thật là biết field nào đúng, field nào sai, sai theo kiểu gì, và có nên cho nó đi tiếp hay không.

Sơ đồ minh họa cho bài Đừng trích PDF nếu chưa chấm từng field

Sơ đồ tóm tắt ý chính của bài viết.

Mục tiêu thật: JSON chỉ là ly mang ra bàn

Nếu bạn đang build pipeline đọc PDF, invoice, report, hồ sơ pháp lý, research paper hay tài liệu scan, đừng bắt đầu bằng câu: “Dùng model nào?”

Hãy bắt đầu bằng câu khó chịu hơn:

Field nào mà sai một chút cũng gây hậu quả lớn?

schema-guided extraction — trích xuất theo schema định trước — nghĩa là bạn không để model kể chuyện tự do, mà bắt nó trả về cấu trúc cụ thể: title, authors, datasets, test_metrics, limitations, repo_url, v.v.

Nhưng schema mới là nửa đầu. Nửa sau là field-level evaluation — chấm đúng sai theo từng field. Thay vì nói “document này pass”, bạn biết rõ: title đúng, authors thiếu một người, metric lấy nhầm split, repo link hallucination.

Nói thẳng ra thì: pipeline trích xuất tài liệu không đáng tin vì nó trả JSON đẹp; nó đáng tin khi bạn biết JSON đó hỏng ở đâu.

Câu chuyện của Linh: demo thắng, production thua

Linh thử ba hướng.

Cách 1: Một model lớn làm hết.
PDF vào, JSON ra. Nhanh để demo, ít glue code. Nhưng khi tài liệu có bảng, footnote, caption, link bị xuống dòng, model bắt đầu “pha theo cảm hứng”. Với research paper, lỗi hay gặp là lấy metric trên validation set rồi tưởng đó là test result.

Cách 2: OCR trước, LLM sau.
Dùng OCR lấy text, rồi LLM parse. Dễ debug hơn vì có text trung gian. Nhưng mất layout. Nếu name nằm cạnh ảnh, hoặc metric nằm trong bảng nhiều cột, text phẳng có thể làm mất quan hệ không gian.

Cách 3: Tách vai theo năng lực.
Model nhẹ hơn xử lý phần nhìn và vị trí, model mạnh hơn xử lý suy luận không gian hoặc logic. Kiểu này giống case digitize yearbook: một model multimodal trích xuất ảnh, tên, tọa độ; model khác ghép tên với khuôn mặt dựa trên layout. Nguồn AWS có nêu một pipeline chạy trên 336 trang scan và tạo 3.122 liên kết tên-khuôn mặt, với phần lớn kết quả có confidence cao. Điểm đáng học không phải con số, mà là quyết định kiến trúc: không bắt một model làm cả quầy pha.

Ví dụ cụ thể: nếu bạn xử lý báo cáo nghiên cứu, có thể để một bước chuyên đọc layout lấy bảng và bounding boxes — tọa độ vùng trên trang — rồi bước sau mới quyết định metric nào thuộc model đề xuất, metric nào là baseline.

Framework 4 quyết định trước khi triển khai

Trước khi batch 10.000 PDF, Linh viết lại playbook cho team. Mình thấy framework này đáng giữ vì nó ép builder ra quyết định, không chỉ đổi model theo trend.

1. Chọn schema như chọn menu, đừng ghi “đồ uống bất kỳ”

Schema phải đủ chặt để kiểm tra, nhưng không quá tham khiến model đoán bừa.

Ví dụ schema tối thiểu cho research paper:

{
  "title": "string",
  "authors": ["string"],
  "datasets": ["string"],
  "test_metrics": [
    {
      "name": "string",
      "value": "number|string",
      "split": "test|validation|unknown",
      "higher_is_better": "boolean|null"
    }
  ],
  "code_release": {
    "available": "boolean",
    "url": "string|null"
  },
  "limitations": ["string"]
}

Điểm quan trọng: field split buộc model nói rõ metric thuộc test hay validation. Nếu không có field này, bạn chỉ nhận một con số đẹp và tự ru ngủ.

2. Tạo bộ test có “mồi nhử”

Đừng chỉ test bằng PDF sạch. Hãy tạo corpus nhỏ nhưng hiểm:

Đây là phần nhiều team bỏ qua vì thấy mất công. Nhưng nếu không có mồi nhử, bạn chỉ đang thử model trên tài liệu biết điều.

3. Chấm từng field, không chấm cảm giác

Một bảng chấm đơn giản đủ giúp team bớt cãi nhau:

| Field | Cách chấm | Khi nào fail nặng |
|---|---|---|
| title | exact hoặc gần đúng | Lấy nhầm title section |
| authors | set match | Thiếu author chính |
| test_metrics | match name + value + split | Nhầm validation thành test |
| code_release.url | URL thật xuất hiện trong tài liệu | Bịa link |
| limitations | semantic match — khớp nghĩa | Biến future work thành limitation |

semantic match ở đây là so khớp theo nghĩa, không bắt câu chữ giống hệt. Ví dụ “requires large GPU memory” và “high memory footprint” có thể tính là cùng ý.

4. Chọn runtime theo nút cổ chai thật

Nếu chạy thử trên Colab hoặc GPU nhỏ, bạn sẽ đụng bài toán bộ nhớ. quantization — nén trọng số model để giảm VRAM — như 4-bit NF4 có thể giúp model vừa vào GPU hạn chế, đổi lại có rủi ro giảm độ chính xác ở vài trường hợp.

Quyết định ở đây không phải “có quantize không”, mà là:

Với tài liệu scan có layout phức tạp, hướng hai model có thể kinh tế hơn so với một model lớn làm tất cả. Với tài liệu text-native sạch, pipeline nhẹ hơn có thể đủ.

Làm trong một buổi: bản triển khai gọn cho team builder

Nếu Linh chỉ có một buổi chiều để biến demo thành thứ có thể bàn tiếp với product, đây là checklist mình sẽ dùng.

Bước 1 — Khóa schema v0.1
Chọn 8-12 field quan trọng nhất. Mỗi field phải có kiểu dữ liệu, ví dụ pass/fail, và hậu quả nếu sai.

Bước 2 — Chuẩn bị 20 tài liệu test có chủ đích
Không cần nhiều ngay từ đầu. Cần đa dạng lỗi: bảng, footnote, missing value, link mập mờ, layout nhiều cột. Nếu chưa có dữ liệu thật, tạo synthetic PDF nhưng phải cài nhiễu giống đời thật.

Bước 3 — Lưu raw evidence
Mỗi field nên kèm bằng chứng: page number, đoạn text, bounding box nếu có. Đừng chỉ lưu kết quả cuối.

{
  "field": "code_release.url",
  "value": null,
  "evidence": {
    "page": 8,
    "quote": "Code will be released upon acceptance."
  },
  "confidence": 0.74
}

Bước 4 — Chạy evaluator riêng
Evaluator không nên là cùng prompt extraction rồi tự khen mình. Ít nhất hãy có script rule-based cho field dễ kiểm tra như URL, number, boolean. Field khó thì dùng reviewer model hoặc human spot-check.

Bước 5 — Đặt ngưỡng hành động
Ví dụ minh họa: giả sử team bạn xử lý 2.000 báo cáo mỗi tháng. Field title sai thì cho sửa sau; field test_metrics sai thì chặn xuất bản; field repo_url không có evidence thì buộc review. Đây là policy sản phẩm, không phải chuyện model.

Ba bẫy khiến pipeline nhìn ổn nhưng khó vận hành

Bẫy một: gom mọi lỗi thành accuracy chung.
Accuracy tổng che mất lỗi chí mạng. Một pipeline đúng 90% nhưng toàn sai ở metric chính vẫn không dùng được.

Bẫy hai: không phân biệt “không thấy” và “không có”.
null vì tài liệu không có khác với null vì model đọc sót. Schema nên có missing_reason: not_present, not_detected, ambiguous.

Bẫy ba: business logic nằm rải rác.
Bài toán này giống BI dùng semantic view — lớp định nghĩa nghiệp vụ chung ở data layer — để tránh mỗi dashboard hiểu metric một kiểu. Với extraction cũng vậy: định nghĩa “test metric hợp lệ” phải nằm trong evaluator/policy chung, không nằm lẫn trong từng prompt.

Sau bài này, bạn nên đổi cách nghĩ gì?

Đừng hỏi “model nào đọc PDF tốt nhất?” quá sớm.

Hãy hỏi: mình có biết cách bắt lỗi từng field trước khi tin output không?

Một pipeline PDF-to-JSON tử tế cần schema, mồi nhử, evidence, evaluator và policy xử lý lỗi. Model chỉ là máy pha. Ly đẹp không đảm bảo cà phê ngon; phải nếm từng shot trước khi đem mời cả công ty.

---
Bụi Wire — nghiện đọc release notes lúc 2 giờ sáng

Nguồn tham khảo