Đừng xử lý mọi PDF bằng một đường ống
Playbook cho team builder: tách on-demand và batch, version prompt theo từng loại tài liệu, rồi route bằng SLA thay vì cảm tính.
Bụi Wire9 giờ 12 sáng, An — tech lead của một team bảo hiểm ở Sài Gòn — nhận được tin nhắn rất quen: “Có cách nào trích xuất dữ liệu từ 20.000 hồ sơ scan trước thứ Sáu không em?”
9 giờ 15, một tin khác bay tới: “À mà hồ sơ khách VIP thì phải trả kết quả trong vài giây nha.”
Đây là lúc nhiều team bắt đầu vẽ một pipeline thật hoành tráng: OCR, LLM, parser, database, dashboard. Nhìn như một bức phác thảo sạch sẽ trên Figma. Nhưng khi đem vào production, nét cọ đầu tiên đã lệch: không phải tài liệu nào cũng cần cùng tốc độ, cùng chi phí, cùng model, cùng prompt.
Luận điểm của mình hôm nay khá đơn giản: với intelligent document processing, quyết định quan trọng không phải “dùng model nào?”, mà là tài liệu nào đi đường nóng, tài liệu nào đi đường nguội, và ai được phép đổi prompt/model mà không đập lại cả hệ thống.

Sơ đồ tóm tắt ý chính của bài viết.
Câu chuyện của An: một backlog, hai nhịp xử lý
Team của An có ba nhóm tài liệu:
- Hồ sơ bồi thường mới: nhân viên cần kết quả gần như ngay để gọi lại khách.
- Hợp đồng cũ scan từ nhiều năm trước: có thể xử lý qua đêm.
- Mẫu biểu thay đổi theo đối tác: mỗi loại cần prompt khác nhau, schema khác nhau.
Nếu đẩy tất cả qua on-demand inference — gọi model theo từng request để lấy kết quả nhanh — chi phí và rate limit dễ trở thành bức tường. Nếu gom tất cả qua batch inference — xử lý bất đồng bộ theo lô để tối ưu chi phí — nghiệp vụ cần phản hồi nhanh sẽ bị nghẽn.
Nói thẳng ra thì: on-demand và batch không phải hai lựa chọn thay thế nhau; chúng là hai làn đường trong cùng một hệ thống.
Một thiết kế đáng dùng thường có ba lớp:
- Ingestion layer: nhận file, lưu object, ghi metadata.
- Routing layer: quyết định tài liệu đi on-demand hay batch.
- Extraction layer: gọi model với prompt/version phù hợp, rồi validate kết quả.
Lớp routing mới là phần nhiều team bỏ qua. Họ chăm chăm chọn model như chọn bảng màu, nhưng quên rằng tranh có vùng cần tô kỹ, vùng chỉ cần lớp nền đủ ổn.
Khung quyết định: route theo SLA, volume, độ rủi ro
Để tránh tranh luận cảm tính, An chốt một bảng quyết định rất khô nhưng hữu ích:
| Tiêu chí | Chọn on-demand | Chọn batch |
|---|---|---|
| Thời gian phản hồi | Cần trong vài giây hoặc vài phút | Có thể chờ hàng giờ hoặc qua đêm |
| Khối lượng | Ít, phát sinh từng hồ sơ | Nhiều, gom theo lô |
| Chi phí | Chấp nhận cao hơn để đổi lấy tốc độ | Ưu tiên tối ưu chi phí |
| Trải nghiệm người dùng | Có người đang chờ kết quả | Không ai cần xem ngay |
| Rủi ro nghiệp vụ | Cần kiểm tra nhanh để ra quyết định | Chủ yếu làm sạch backlog hoặc analytics |
Ví dụ cụ thể: một claim mới vừa được upload từ app khách hàng nên đi on-demand. Nhưng 50.000 hợp đồng scan cũ để chuẩn hóa dữ liệu CRM thì nên đi batch. Cùng là PDF, nhưng “nhu cầu thời gian” khác nhau hoàn toàn.
Điểm đổi cách nghĩ nằm ở đây: đừng gắn pipeline vào loại file; hãy gắn pipeline vào intent của request.
Một request nên mang theo metadata kiểu này:
{
"document_id": "claim-2026-001",
"document_type": "insurance_claim",
"priority": "high",
"sla": "interactive",
"prompt_id": "claim_extract_v3",
"prompt_version": "3.2",
"model_profile": "accurate_default"
}
Từ đó router có thể quyết định:
def choose_pipeline(request):
if request["sla"] == "interactive" or request["priority"] == "high":
return "on_demand"
return "batch"
Đoạn code này cố tình đơn giản. Trong hệ thống thật, bạn sẽ thêm quota, kích thước file, trạng thái OCR, loại khách hàng, và chính sách retry. Nhưng phác thảo ban đầu phải rõ: route trước, gọi model sau.
Playbook một buổi chiều cho team builder
Nếu team bạn đang có backlog PDF và muốn dựng bản thử có giá trị, đừng bắt đầu bằng dashboard. Bắt đầu bằng một lát cắt nhỏ đủ kiểm chứng architecture.
1. Chọn 3 loại tài liệu, mỗi loại 20 file
Đừng lấy toàn file đẹp. Hãy cố tình chọn:
- file scan nghiêng,
- file có bảng,
- file có chữ ký hoặc stamp,
- file text PDF sạch,
- file nhiều layout khác nhau.
OCR là nhận dạng chữ từ ảnh scan. Nhưng một PDF “searchable” chỉ có nghĩa là có text layer để tìm kiếm; không có nghĩa text đó đủ sạch để LLM trích xuất đúng. Đây là bẫy rất hay gặp: Ctrl+F thấy ra chữ, team tưởng dữ liệu đã sẵn sàng.
2. Viết schema trước khi viết prompt
Đừng bảo model “trích xuất thông tin quan trọng”. Hãy ép output thành JSON rõ ràng:
{
"policy_number": "string|null",
"customer_name": "string|null",
"effective_date": "YYYY-MM-DD|null",
"claim_amount": "number|null",
"missing_fields": ["string"],
"confidence_note": "string"
}
Schema validation là kiểm tra kết quả có đúng cấu trúc mong muốn không. Nếu model trả claim_amount bằng “khoảng hơn mười triệu”, validator phải bắt lại, không để lọt vào database như dữ liệu chuẩn.
3. Tách prompt thành config có version
Prompt versioning là quản lý prompt như một artifact có phiên bản, thay vì sửa tay trong code. Với document processing, đây là dây an toàn.
Ví dụ:
prompt_id: claim_extract
version: 3.2
document_type: insurance_claim
model_profile: accurate_default
output_schema: claim_v1
notes: "Handle handwritten stamps as optional evidence"
Khi mẫu hợp đồng của đối tác A đổi layout, bạn không nên redeploy cả service. Bạn chỉ nên đổi prompt_id hoặc prompt_version ở metadata request.
4. Dựng hai đường chạy tối thiểu
Đường on-demand:
- User upload file.
- Service chạy OCR nếu cần.
- Gọi model ngay với prompt/version tương ứng.
- Validate JSON.
- Trả kết quả hoặc yêu cầu review.
Đường batch:
- Gom manifest danh sách file.
- Gắn từng file với
prompt_id,prompt_version,model_profile. - Submit batch job bất đồng bộ.
- Nhận output về object storage.
- Validate, ghi kết quả, đẩy lỗi sang hàng review.
Idempotency là khả năng chạy lại cùng một job mà không tạo dữ liệu trùng hoặc ghi đè sai. Với batch, đây không phải chi tiết phụ. Nếu job fail giữa chừng, bạn cần biết file nào đã xong, file nào cần chạy lại.
5. Đặt hàng lỗi ngay từ đầu
Dead-letter queue là nơi chứa request lỗi để xử lý sau, thay vì làm sập cả pipeline. Tài liệu xấu, OCR fail, model trả JSON hỏng, schema mismatch — tất cả nên có mã lỗi riêng.
Một log tối thiểu nên có:
{
"document_id": "claim-2026-001",
"pipeline": "on_demand",
"prompt_version": "3.2",
"model_profile": "accurate_default",
"ocr_status": "success",
"validation_status": "failed",
"error_code": "INVALID_DATE_FORMAT"
}
Không có log kiểu này, bạn sẽ debug bằng cảm giác. Và cảm giác thì không scale.
Pitfall: tối ưu model khi lỗi nằm ở lớp nền
An ban đầu cũng nghĩ phải đổi model mạnh hơn. Nhưng sau một vòng soi lỗi, team phát hiện nhiều output sai vì OCR đọc nhầm số hợp đồng, hoặc prompt không nói rõ field nào được phép null.
Đây là điểm liên quan tới fine-tuning và hyperparameter tuning. Fine-tuning — tinh chỉnh model bằng dữ liệu riêng — có thể hữu ích khi task thật sự đặc thù. Nhưng nếu text layer bẩn, schema lỏng, prompt không version, routing mù mờ, thì fine-tuning giống như phủ một lớp màu đắt tiền lên nền giấy còn ướt.
Trước khi nghĩ tới model riêng, hãy kiểm tra bốn câu hỏi:
- OCR có đủ tốt cho loại tài liệu này chưa?
- Field cần trích xuất đã có schema rõ chưa?
- Prompt có version và test set riêng chưa?
- Lỗi đến từ model reasoning hay từ input nhiễu?
Nếu chưa trả lời được, khoan đốt compute.
Quyết định sau cùng: control plane quan trọng hơn pipeline đẹp
Sau hai tuần, team của An không có một pipeline duy nhất. Họ có một control plane — lớp điều khiển quyết định route, prompt, model, schema, retry, logging.
Đây mới là phần đáng copy:
- Pipeline chỉ thực thi.
- Control plane quyết định tài liệu đi đâu.
- Prompt/model là config có version.
- Validation là cổng bắt buộc, không phải việc “làm sau”.
- Human review chỉ nhận case có lý do rõ ràng, không nhận một đống lỗi vô danh.
Sau bài này, nếu bạn đang xây hệ thống trích xuất dữ liệu từ PDF, mình muốn bạn đổi một câu hỏi:
Thay vì hỏi “dùng model nào để đọc hết đống tài liệu này?”, hãy hỏi “mỗi loại request đáng đi làn nào, với prompt/version nào, và lỗi sẽ quay về đâu?”
Xong khung đó rồi hãy chọn service, model, hay vendor. Bức tranh production không thắng nhờ một nét cọ đẹp; nó thắng vì lớp nền không làm màu phía trên nứt toác.
---
Bụi Wire — nghiện đọc release notes lúc 2 giờ sáng
Nguồn tham khảo
- Extract Data with On-demand and Batch Pipelines Dynamically | Artificial Intelligence
- The art and science of hyperparameter optimization on Amazon Nova Forge | Artificial Intelligence
- How to Make a PDF Searchable: Methods and Limits
- Fundamental’s Large Tabular Model NEXUS is now available on Amazon SageMaker JumpStart | Artificial Intelligence
- Scale Robot Reinforcement Learning with NVIDIA Isaac Lab on Amazon SageMaker AI | Artificial Intelligence