Lima tahun lalu, mengekstrak data terstruktur dari faktur membutuhkan pipeline deep learning: tahap OCR, model yang memahami tata letak (LayoutLM, Donut) yang di-fine-tune menggunakan ribuan dokumen berlabel manual, serta beban pemeliharaan setiap kali pemasok mengubah templatnya. Pada 2026, seluruh pipeline tersebut disederhanakan menjadi satu panggilan API LLM dengan kemampuan visual: gambar masuk, JSON yang divalidasi terhadap skema keluar — tanpa data pelatihan, tanpa model yang dihosting, dan tata letak baru ditangani secara zero-shot. Panduan dari Kunavo — gateway independen yang kompatibel dengan OpenAI untuk model visual yang digunakan dalam pola ini — menunjukkan pola kerja lengkap, biaya per faktur yang dihitung berdasarkan tarif yang kami publikasikan sendiri, dan cara menjaga akurasi agar memenuhi standar produksi.
Perbandingan pendekatan ekstraksi data faktur: aturan, pembelajaran mesin, pembelajaran mendalam, LLM
Empat generasi teknik telah digunakan untuk mengekstrak data terstruktur dari faktur. Teknik-teknik ini layak dibandingkan secara berdampingan, karena pertimbangan yang menentukan pilihan di antara semuanya selama dua dekade — akurasi yang diperoleh dengan mengandalkan data berlabel — kini tidak lagi berlaku.
| Pendekatan | Cara kerjanya | Biaya penyiapan | Menangani tata letak vendor baru |
|---|---|---|---|
| Template / aturan (1990-an–) | OCR, lalu zona koordinat dan regex per vendor (“total adalah angka di sebelah kanan ‘TOTAL’”) | Berjam-jam per vendor, selamanya | Tidak — memerlukan template baru |
| Pembelajaran mesin klasik (2010-an) | OCR, lalu fitur yang direkayasa secara manual (posisi, ukuran font, kata-kata di sekitarnya) dimasukkan ke CRF atau SVM yang memberi tag pada setiap token | Rekayasa fitur + beberapa ribu label | Sebagian — kinerjanya menurun pada tata letak yang belum pernah dilihat |
| Pembelajaran mendalam (2020–) | Transformer yang memahami tata letak (LayoutLM, Donut, DocTR) disesuaikan untuk membaca teks, posisi, dan piksel secara bersama-sama | 3.000–50.000 faktur berlabel + layanan inferensi menggunakan GPU | Sering kali tidak — biasanya memerlukan pelabelan ulang dan pelatihan ulang |
| LLM visi (2024–) | Satu panggilan API: gambar faktur ditambah skema JSON, dengan output terstruktur yang dibatasi oleh skema tersebut | Tidak ada — sebuah skema dan prompt; $0,00248–$0,00497 per faktur | Ya, zero-shot |
Tiga pendekatan pertama memiliki satu kesamaan: akurasi diperoleh dengan data berlabel. Setiap template vendor, setiap fitur CRF, setiap fine-tuning LayoutLM adalah proyek anotasi. LLM visi sudah membayar biaya tersebut selama prapelatihan, sehingga biaya marginal untuk tata letak baru menjadi nol. Itulah seluruh pergeserannya — bukan karena metode lama berhenti bekerja, melainkan karena hal yang menghabiskan anggaran mereka menjadi gratis.
Fine-tuning pembelajaran mendalam vs LLM visi, secara mendetail
| Model tata letak yang di-fine-tune (2021) | LLM visi (2026) | |
|---|---|---|
| Data pelatihan | 3.000–50.000 faktur berlabel | Tidak ada (zero-shot) — beberapa contoh membantu menangani kasus tepi |
| Tata letak vendor baru | Sering memerlukan pelabelan ulang + pelatihan ulang | Ditangani secara zero-shot |
| Infrastruktur | Penyajian GPU + tahap OCR | Satu panggilan HTTPS |
| Format output | Tag token → decoding khusus | JSON yang dibatasi skema |
| Biaya per faktur | Waktu engineering mendominasi | $0,00248–$0,00497 |
Ekstraktor yang di-fine-tune masih dapat unggul pada satu tata letak bervolume tinggi yang tetap, tetapi untuk ekor panjang faktur dunia nyata — vendor, bahasa, dan kualitas pemindaian yang berbeda — LLM visi zero-shot lebih akurat dalam praktik dan jauh lebih murah untuk dikelola. Lebih banyak pola untuk kelas beban kerja ini tersedia dalam kasus penggunaan ekstraksi data.
Pola lengkap: gambar → JSON yang divalidasi skema
Semua hal di bawah ini berjalan melalui endpoint yang kompatibel dengan OpenAI milik Kunavo — arahkan base_url ke https://api.kunavo.com/v1 dan kode yang sama dapat memanggil Claude atau GPT dengan mengubah satu string:
from openai import OpenAI
import base64, json
client = OpenAI(
base_url="https://api.kunavo.com/v1",
api_key="sk-kn-...",
)
SCHEMA = {
"name": "invoice",
"schema": {
"type": "object",
"properties": {
"vendor_name": {"type": "string"},
"vendor_tax_id": {"type": ["string", "null"]},
"invoice_number": {"type": "string"},
"invoice_date": {"type": "string", "description": "ISO 8601"},
"due_date": {"type": ["string", "null"]},
"currency": {"type": "string", "description": "ISO 4217"},
"line_items": {
"type": "array",
"items": {
"type": "object",
"properties": {
"description": {"type": "string"},
"quantity": {"type": "number"},
"unit_price": {"type": "number"},
"amount": {"type": "number"},
},
"required": ["description", "amount"],
},
},
"subtotal": {"type": ["number", "null"]},
"tax": {"type": ["number", "null"]},
"total": {"type": "number"},
},
"required": ["vendor_name", "invoice_number", "invoice_date",
"currency", "line_items", "total"],
},
}
def extract(path: str) -> dict:
image_b64 = base64.b64encode(open(path, "rb").read()).decode()
resp = client.chat.completions.create(
model="claude-haiku-4-5", # the cheapest capable model for clean invoices
response_format={"type": "json_schema", "json_schema": SCHEMA},
messages=[
{"role": "system", "content":
"Extract the invoice into the schema. Copy values exactly as "
"printed; use null when a field is absent. Never invent data."},
{"role": "user", "content": [
{"type": "image_url",
"image_url": {"url": f"data:image/png;base64,{image_b64}"}},
]},
],
)
return json.loads(resp.choices[0].message.content)
inv = extract("invoice_0231.png")
# Cheap arithmetic guardrail: reject when the line items don't add up.
delta = abs(sum(li["amount"] for li in inv["line_items"])
+ (inv.get("tax") or 0) - inv["total"])
if delta > 0.02:
raise ValueError(f"line items disagree with total by {delta:.2f}")
print(inv["vendor_name"], inv["total"], inv["currency"])Tiga detail melakukan sebagian besar pekerjaan: skema JSON di response_format (pada Claude, model tidak dapat menghasilkan hal lain — lihat catatan tentang GPT dalam referensi yang ditautkan di bawah), aturan system prompt “salin nilai persis; null jika tidak ada; jangan pernah mengarang” (menghilangkan ID pajak hasil halusinasi), dan pagar pengaman aritmetika — item baris + pajak harus sama dengan total, atau dokumen dialihkan ke model yang lebih kuat atau manusia. Lihat referensi penyelesaian chat untuk mengetahui apa yang dipaksakan oleh response_format pada setiap keluarga model.
Skema yang sama, sebagai model Pydantic bertipe
Dict skema JSON mentah cocok untuk satu endpoint dan merepotkan untuk sepuluh endpoint. Dalam produksi, sebagian besar tim mendefinisikan skema sekali sebagai model Pydantic dan memperoleh constraint serta objek yang telah diuraikan darinya, sehingga ekstraktor dan bagian kode lainnya tidak pernah dapat berbeda pendapat tentang bentuknya:
from pydantic import BaseModel, Field
from typing import Literal
from openai import OpenAI
client = OpenAI(base_url="https://api.kunavo.com/v1", api_key=KEY)
class LineItem(BaseModel):
description: str
quantity: float | None = None
unit_price: float | None = None
amount: float
class Invoice(BaseModel):
vendor_name: str
vendor_tax_id: str | None = None
invoice_number: str
invoice_date: str = Field(description="ISO 8601")
currency: str = Field(description="ISO 4217")
line_items: list[LineItem]
tax: float | None = None
total: float
# A confidence field the model fills in itself is a cheap, surprisingly
# reliable router: low self-reported confidence correlates well with the
# documents a human should see.
confidence: Literal["high", "medium", "low"]
resp = client.chat.completions.create(
model="claude-haiku-4-5",
response_format={
"type": "json_schema",
"json_schema": {"name": "invoice", "schema": Invoice.model_json_schema()},
},
messages=[...],
)
invoice = Invoice.model_validate_json(resp.choices[0].message.content)Ada dua hal yang layak disalin di sini. Field yang bertipe float | None alih-alih float memberi model cara yang sah untuk mengatakan “tidak ada” — tanpanya, baris pajak yang hilang sangat mendorong model untuk mengarang nilai nol. Dan field confidence yang dilaporkan sendiri hanya memerlukan tiga token output dan ternyata sangat baik untuk melakukan routing; field ini tidak terkalibrasi, tetapi “low” adalah sinyal yang andal bahwa manusia harus memeriksanya.
Routing dua tingkat: yang sebenarnya berjalan di produksi
Menggunakan satu model untuk setiap dokumen adalah bentuk yang keliru. Faktur cetak yang bersih — mayoritas yang sangat besar — ditangani oleh model visi termurah yang tersedia; ekor sulit (tulisan tangan, pemindaian buruk, tata letak tidak biasa) adalah tempat model yang lebih kuat sepadan dengan tarifnya. Lakukan eskalasi berdasarkan kegagalan validasi, bukan tebakan:
CHEAP, STRONG = "claude-haiku-4-5", "claude-sonnet-5"
def valid(inv: dict) -> bool:
"""Arithmetic is the guardrail no confidence score replaces."""
items = sum(li["amount"] for li in inv["line_items"])
return abs(items + (inv.get("tax") or 0) - inv["total"]) <= 0.02
def extract_routed(path: str) -> tuple[dict, str]:
inv = extract(path, model=CHEAP)
if valid(inv) and inv.get("confidence") != "low":
return inv, CHEAP
# Escalate: same prompt, same schema, stronger model. Only the failures
# pay the higher rate, which is what keeps the blended cost near the
# cheap tier's.
inv = extract(path, model=STRONG)
if not valid(inv):
raise NeedsHumanReview(path, inv)
return inv, STRONG
# Blended cost at a 90/10 split, per 10,000 invoices:
# 9,000 x $0.00248 + 1,000 x $0.00497
# = $27.29Pemeriksaan aritmetika melakukan pekerjaan yang sebenarnya: ini adalah satu-satunya sinyal yang independen dari penilaian model terhadap dirinya sendiri. Dokumen yang jumlah item barisnya sama dengan total yang dinyatakan hampir tidak pernah salah dengan cara yang penting; dokumen yang gagal layak diproses oleh model yang lebih kuat atau manusia, apa pun yang diklaim oleh field confidence.
Biaya per faktur, berdasarkan model
Faktur satu halaman ≈ 1.800 token input (dikirim sebagai gambar) + ~350 token output berupa JSON:
| Model | Per faktur | Per 10.000 faktur | Gunakan untuk |
|---|---|---|---|
claude-haiku-4-5 | $0,00248 | $24,80 | Default: faktur cetak bersih dan proses massal termurah |
claude-sonnet-5 | $0,00497 | $49,70 | Tingkat eskalasi: pemindaian, tulisan tangan, kegagalan |
Tarif diambil langsung dari halaman harga (sekitar 30% lebih rendah daripada harga daftar penyedia), dan permintaan yang gagal tidak ditagihkan. Dengan routing dua tingkat — semuanya melalui Haiku, kegagalan pemeriksaan aritmetika dieskalasikan ke Sonnet — 10.000 faktur per bulan biasanya berbiaya di bawah $27,29.
Akurasi: daftar periksa untuk membawa Anda ke produksi
- Utamakan skema. Tandai field yang benar-benar wajib sebagai
required, izinkannulldi tempat lain — memaksa adanya nilai berarti memaksa halusinasi. - Kirim gambar, bukan teks OCR. Tata letak membawa makna (kolom, kotak total); model visi membacanya secara langsung. Hanya gunakan teks sebagai fallback untuk PDF digital asli jika Anda dapat mengekstrak lapisan teks yang bersih.
- Validasi aritmetika dalam kode. Item baris + pajak = total menangkap sebagian besar kesalahan ekstraksi secara gratis.
- Lakukan eskalasi, jangan mengulangi secara membabi buta. Kegagalan dikirim ke Sonnet dengan kesalahan validasi disertakan dalam prompt; kegagalan yang terus berulang dikirim ke antrean manusia.
- Gunakan few-shot untuk kasus tepi yang sebenarnya. Dua atau tiga contoh tata letak terburuk Anda (nota kredit, multi-mata uang) dalam system prompt lebih efektif daripada tuning instruksi sebanyak apa pun.
Di luar faktur
Pola dengan skema yang sama mencakup kuitansi, pesanan pembelian, nota pengiriman, formulir bea cukai, dan rekening koran — ganti skemanya, pertahankan pagar pengamannya. Jelajahi kasus penggunaan ekstraksi data terstruktur yang lebih luas untuk pola yang berdekatan dengan RAG, atau panduan optimasi biaya untuk strategi routing saat volume meningkat. Satu kunci Kunavo mencakup setiap tingkat model yang digunakan di sini — daftar gratis dan buat kunci untuk menjalankan cuplikan ini apa adanya.
Pertanyaan umum
Apakah saya memerlukan model pembelajaran mendalam untuk mengekstrak data dari faktur?
Tidak lagi. Bagi sebagian besar tim, alur pemrosesan klasik — OCR, lalu model tata letak seperti LayoutLM yang disetel lebih lanjut menggunakan ribuan faktur berlabel — telah digantikan oleh satu panggilan ke LLM dengan kemampuan penglihatan: kirim gambar faktur beserta skema JSON, lalu terima data terstruktur yang telah divalidasi. Tidak ada set data pelatihan yang perlu dilabeli atau model yang perlu dihosting, dan perubahan tata letak yang sebelumnya membuat model hasil penyetelan gagal kini ditangani secara zero-shot.
Bagaimana perbandingan ekstraksi data faktur dengan pembelajaran mesin dan penggunaan LLM?
Ekstraktor pembelajaran mesin klasik (CRF atau SVM yang memproses keluaran OCR beserta fitur posisi dan jenis huruf yang dirancang secara manual) dan penerusnya yang menggunakan pembelajaran mendalam (LayoutLM, Donut) sama-sama memperoleh akurasi dengan mengandalkan data berlabel — ribuan faktur beranotasi untuk setiap penerapan, yang harus dilabeli ulang saat tata letak berubah. LLM dengan kemampuan penglihatan telah menanggung biaya itu selama prapelatihan, sehingga dapat membaca tata letak pemasok yang belum pernah dilihatnya secara zero-shot dan mengembalikan JSON yang dibatasi oleh skema melalui satu panggilan API. Pembelajaran mesin masih unggul untuk satu tata letak tetap dengan volume sangat tinggi ketika biaya inferensi mendominasi; untuk beragam faktur nyata yang jarang ditemui, LLM lebih akurat dalam praktik dan memiliki total biaya kepemilikan yang jauh lebih rendah.
Bisakah saya tetap menggunakan LayoutLM atau Donut untuk ekstraksi data faktur?
Ya, dan keduanya tetap masuk akal jika Anda memproses jutaan dokumen dengan satu tata letak yang stabil dan dapat mengamortisasi biaya pelabelan serta penyajian model melalui GPU. Yang berubah adalah pilihan standar: untuk proyek baru, LLM dengan kemampuan penglihatan mencapai akurasi yang siap digunakan dalam produksi dalam satu sore tanpa set data pelatihan, dan biaya per dokumennya cukup rendah sehingga penyetelan lebih lanjut jarang memberikan manfaat ekonomis yang sepadan. Jalan tengah yang umum adalah menjalankan LLM terlebih dahulu dan baru melakukan penyetelan lebih lanjut kemudian, dengan menggunakan keluaran LLM yang telah diterima sebagai korpus berlabel.
Berapa biaya ekstraksi data faktur per dokumen?
Faktur satu halaman memerlukan sekitar 1.800 token masukan (sebagai gambar) ditambah ~350 token keluaran JSON. Di Kunavo, biayanya sekitar $0,00248 per faktur dengan claude-haiku-4-5 dan $0,00497 dengan claude-sonnet-5 — artinya, bahkan dengan kualitas Sonnet, seribu faktur hanya membutuhkan biaya beberapa dolar. Permintaan yang gagal tidak dikenakan biaya.
Model mana yang sebaiknya saya gunakan untuk ekstraksi data faktur?
Mulailah dengan claude-haiku-4-5: model ini menangani faktur cetak yang jelas hampir sempurna dengan harga terendah. Alihkan hanya kasus yang gagal — tulisan tangan, hasil pemindaian beresolusi rendah, tata letak yang tidak lazim, atau dokumen yang gagal dalam pemeriksaan aritmetika Anda — ke claude-sonnet-5. Perutean dua tingkat ini biasanya mempertahankan 90%+ volume pada tingkat yang murah.
Bagaimana cara memastikan keluarannya berupa JSON yang valid?
Gunakan keluaran terstruktur: sertakan response_format dengan skema JSON agar model Claude dibatasi untuk menghasilkan struktur yang persis sesuai — tanpa pemrosesan lanjutan menggunakan regex. Tambahkan pengaman berbiaya rendah pada tingkat aplikasi: periksa apakah jumlah nilai item faktur ditambah pajak sama dengan total, lalu teruskan ketidaksesuaian ke model yang lebih kuat atau antrean peninjauan manusia.
Bisakah saya mengekstrak data dari faktur PDF, bukan hanya gambar?
Ya — render setiap halaman PDF menjadi PNG (misalnya dengan pdf2image) dan kirim seperti dijelaskan di atas. Untuk PDF yang dibuat secara digital, Anda juga dapat mengekstrak lapisan teks dan mengirimkannya sebagai teks biasa, yang lebih murah; tetap gunakan metode pengiriman gambar untuk hasil pemindaian.
Seberapa akurat ekstraksi data faktur dengan LLM?
Pada faktur cetak yang jelas, ekstraksi berbasis penglihatan yang dibatasi oleh skema dan dilengkapi pengaman aritmetika secara rutin mencapai akurasi tingkat kolom sebesar 98%+ — dan, berbeda dengan model hasil penyetelan, akurasinya tetap terjaga pada tata letak yang belum pernah dilihatnya. Ukur kinerjanya pada dokumen Anda sendiri: 100 faktur berlabel sudah membentuk set evaluasi yang andal.
Apakah data faktur saya digunakan untuk pelatihan model?
Tidak — permintaan melalui Kunavo diteruskan ke penyedia model berdasarkan ketentuan penggunaan API (bukan ketentuan aplikasi konsumen) dan tidak digunakan untuk melatih model. Lihat dokumentasi penagihan dan data untuk rincian retensi data.