Salah satu tantangan terbesar dalam menggunakan LLM adalah mendapatkan output yang terstruktur dari teks yang tidak terstruktur. Bayangkan kamu memiliki log mentah seperti: Jane booked a table for 4 at 7:30pm tomorrow at Bistro Verde. Kamu ingin mengekstraknya menjadi JSON dengan field name, party_size, time, restaurant, dan date. Menulis regex atau parser manual untuk setiap format bisa sangat melelahkan dan rapuh. Setiap perubahan format sedikit saja bisa membuat regex yang sudah dibuat dengan susah payah menjadi tidak berfungsi.
Domain-Specific Language (DSL) menawarkan solusi elegan. Alih-alih memaksa LLM menghasilkan JSON langsung, kamu mendefinisikan struktur data dengan DSL, kemudian meminta LLM mengisinya. Artikel ini membahas konsep penggunaan DSL dengan LLM untuk menghasilkan structured output yang andal dan mudah dipelihara. Konsep ini sangat relevan untuk data pipeline, ETL, dan sistem ekstraksi informasi otomatis.
Sumber: Slangify Tutorial
LLM terkadang menghasilkan JSON yang tidak valid: missing comma, tipe data salah, atau field yang tidak lengkap. JSON schema yang kompleks juga memakan banyak token di context window, mengurangi ruang untuk instruksi bisnis. Terlebih lagi, model yang lebih kecil seringkali kesulitan menghasilkan JSON bersarang yang valid, terutama jika strukturnya dalam.
DSL menyederhanakan representasi. Dengan grammar yang ringkas, model bisa memahami struktur yang diinginkan tanpa boilerplate JSON yang panjang. Hasilnya kemudian diparse dan divalidasi menggunakan grammar parser yang sudah terdefinisi dengan baik. Grammar parser jauh lebih ketat dan andal daripada parsing JSON mentah, karena bisa memberikan error spesifik tentang bagian mana yang tidak sesuai dengan aturan.
Mulailah dengan mendefinisikan grammar yang menggambarkan struktur data yang kamu inginkan. Contoh untuk reservasi restoran:
grammar Reservation {
token name { \w+ }
token party_size{ \d+ }
token time { \d+ ':' \d+ [am|pm] }
token restaurant{ \w+ [\w+]* }
token date { \w+ }
rule TOP {
<name> booked a table for <party_size> at <time> <date> at <restaurant>
}
}Grammar ini menggunakan notasi yang mirip dengan Raku Grammar atau parser combinator. Intinya adalah mendefinisikan token dan rule yang kemudian digunakan untuk memparse output LLM. Hasil parsing otomatis menjadi struktur data tree yang bisa dikonversi ke object atau JSON. Keuntungan utama adalah grammar bisa dievolusi tanpa mengubah prompt ke LLM secara drastis.
Setelah grammar siap, gunakan library seperti LLM::Functions atau wrapper sejenis untuk mengirim prompt ke LLM dengan petunjuk struktur:
from slangify import Schema, LLM
schema = Schema.from_grammar('''
name: str
party_size: int
time: str
restaurant: str
date: str
''')
llm = LLM(provider='openai', model='gpt-4.1-mini')
result = llm.extract(
text='Jane booked a table for 4 at 7:30pm tomorrow at Bistro Verde',
schema=schema
)
print(result.to_json())Prompt yang dikirim ke LLM secara internal disusun dengan contoh input-output dan deskripsi grammar. LLM tidak menghasilkan JSON mentah, melainkan string yang sesuai dengan grammar yang kemudian diparse oleh engine DSL. Pendekatan ini mengurangi beban kognitif model karena model tidak perlu memahami aturan JSON, melainkan hanya perlu mengisi slot-slot yang sudah didefinisikan.
Output dari LLM tidak selalu sempurna. Gunakan langkah validasi untuk memastikan semua field terisi dan tipe data sesuai:
def validate_reservation(raw):
errors = []
if not raw.get('name'):
errors.append('name is required')
if raw.get('party_size', 0) < 1:
errors.append('party_size must be positive')
return errors if errors else None
validated = schema.validate(result)
if validated.errors:
# Retry dengan prompt yang lebih spesifik
result = llm.extract(text, schema=schema, feedback=validated.errors)
Jika validasi gagal, kamu bisa mengirim feedback ke LLM dan meminta retry. Pola ini dikenal sebagai self-correction loop dan sangat efektif untuk meningkatkan akurasi ekstraksi informasi. Pada beberapa kasus, menambahkan contoh koreksi di prompt bisa meningkatkan success rate secara signifikan. Selain itu, validasi memberikan visibility ke sistem monitoring tentang bagian mana dari pipeline yang paling sering gagal.
Di production, DSL + LLM bisa menjadi bagian dari pipeline ETL atau event processing. Contoh: sistem menerima email booking, mengirimkan body email ke LLM dengan schema reservasi, dan menyimpan hasil ke database:
async def process_booking_email(email_body):
schema = ReservationSchema()
extraction = await llm.extract(email_body, schema)
if extraction.is_valid:
await db.reservations.insert(extraction.to_dict())
return {'status': 'success', 'id': extraction.id}
else:
await queue_failed.insert({'body': email_body, 'errors': extraction.errors})
return {'status': 'failed', 'reason': extraction.errors}
Dengan arsitektur ini, kamu mendapatkan keunggulan kombinasi: fleksibilitas pemahaman bahasa alami dari LLM dan keandalan struktur data dari grammar parser. Tidak perlu lagi menulis regex ratusan baris untuk setiap format input baru. Perubahan format hanya memerlukan penyesuaian grammar, yang jauh lebih maintainable dan bisa di-review oleh tim.
Beberapa praktik terbaik untuk menggunakan DSL dengan LLM secara produksi:
Gunakan model yang cukup kecil seperti GPT-4.1-mini untuk ekstraksi sederhana. Tidak selalu butuh model terbesar. Model kecil biasanya lebih cepat dan lebih murah, dengan akurasi yang cukup untuk task ekstraksi yang terstruktur.
Tambahkan few-shot examples di prompt untuk format yang jarang muncul. Contoh khusus membantu model memahami edge case. Variasi contoh yang baik mencakup format tanggal yang berbeda, nama restoran dengan spesial karakter, dan party size yang tidak standar.
Implementasi circuit breaker: jika LLM gagal 3 kali berturut-turut, fallback ke manual review atau heuristik rule-based. Ini mencegah sistem terus-menerus menghabiskan token untuk input yang secara inheren ambigu atau tidak valid.
Monitoring: catat latency ekstraksi, error rate, dan distribusi field yang sering missing. Data ini membantu iterasi grammar dan prompt. Dashboard sederhana bisa memberikan insight cepat tentang kesehatan pipeline ekstraksi.
Penggunaan DSL dengan LLM adalah pola desain yang powerful untuk structured extraction. Ini menggabungkan kekuatan pemahaman bahasa alami dari LLM dengan keandalan parsing dari grammar yang terdefinisi secara formal. Untuk data pipeline yang menangani input heterogen, pendekatan ini jauh lebih maintainable daripada regex atau JSON schema manual. Grammar-based parsing juga memberikan error message yang lebih baik, memudahkan debugging, dan memungkinkan evolusi schema tanpa mengubah core logic secara signifikan.
Eksplorasi lebih lanjut bisa dilakukan melalui tutorial Slangify di librasteve.github.io. Repositori proyek tersedia di GitHub. Untuk implementasi di bahasa lain, konsep grammar-based extraction bisa diadaptasi menggunakan library seperti Lark atau ANTLR.
Dapatkan feedback, users, dan eksposur dari komunitas kreator, developer, dan entrepreneur digital Indonesia.
Submit Produk → Pelajari Dulu