Model QLoRA adapter (r=16) hasil fine-tuning Qwen2.5-Coder-3B-Instruct untuk menerjemahkan pertanyaan bisnis Bahasa Indonesia menjadi SQL.
Proyek eksperimen. Model dilatih khusus untuk satu skema e-commerce 5 tabel (customers, orders, order_items, products, payments). Bisa dipakai di database lain hanya jika skemanya persis sama. Untuk skema berbeda, perlu fine-tuning ulang dengan data baru.
Hasil
3-way comparison pada 365 contoh eval_dev (nilai yang belum pernah dilihat model):
Sistem
Exec Acc
Valid SQL
Error dominan
Base (Qwen2.5-Coder-3B, zero-shot)
0.27%
3.0%
invalid_sql (354)
gpt-4o-mini (zero-shot)
48.5%
100%
wrong_join (99)
Model ini
97.26%
100%
other (10)
Final pada eval_test (365 held-out, tidak pernah disentuh selama pengembangan):
Metrik
Nilai
Execution Acc
91.78%
Valid SQL
100%
Gap vs dev
5.48pp (generalisasi baik)
Skema Database
Model dilatih dan hanya bekerja untuk skema 5 tabel berikut. Prompt harus selalu menyertakan DDL ini:
Tabel
Kolom
customers
id, name, city
orders
id, customer_id, created_at, status
order_items
id, order_id, product_id, qty, price
products
id, name, category, price
payments
id, order_id, amount, paid_at, method
Query yang didukung: SELECT, JOIN (max 4 tabel), WHERE, GROUP BY, ORDER BY, SUM/COUNT/AVG, HAVING, filter tanggal (strftime, >= AND <), LIMIT.
Inference (self-contained, tanpa dependensi proyek)
python
1import re
23# Salin skema database anda ke sini4SCHEMA_TEXT ="""
5customers(id, name, city)
6orders(id, customer_id, created_at, status)
7order_items(id, order_id, product_id, qty, price)
8products(id, name, category, price)
9payments(id, order_id, amount, paid_at, method)
10"""1112pertanyaan ="berapa total penjualan kategori elektronik bulan Januari 2025?"1314# System prompt harus persis seperti saat training (src/prompts.py::get_system_prompt)15system =(16"Anda adalah asisten SQL yang menerjemahkan pertanyaan bisnis "17"Bahasa Indonesia menjadi query SQLite.\n\n"18f"Skema database:\n{SCHEMA_TEXT}\n\n"19"Aturan:\n"20"- Gunakan tabel dan kolom sesuai skema di atas.\n"21"- Tulis reasoning singkat dalam tag <think>...</think>:\n"22" Tabel: (tabel yang dipakai)\n"23" Join: (kondisi join)\n"24" Filter: (kondisi WHERE)\n"25" Agregasi: (fungsi agregasi, atau '-' jika tidak ada)\n"26"- Setelah </think>, tulis SQL tanpa markdown fence.\n"27"- Hanya SELECT, tanpa INSERT/UPDATE/DELETE."28)29messages =[30{"role":"system","content": system},31{"role":"user","content": pertanyaan},32]3334prompt = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)35inputs = tokenizer(prompt, return_tensors="pt").to(model.device)3637outputs = model.generate(**inputs, max_new_tokens=512, do_sample=False)38response = tokenizer.decode(outputs[0][inputs["input_ids"].shape[1]:], skip_special_tokens=True)3940# Ekstrak SQL setelah </think>41m = re.search(r"</think>\s*(.*)", response, re.DOTALL | re.IGNORECASE)42sql = m.group(1).strip()if m else response.strip()43# Bersihkan markdown fence jika ada44sql = re.sub(r"```(?:sql)?\s*","", sql, flags=re.IGNORECASE).replace("```","").strip()4546print(sql)47# SELECT SUM(oi.qty * oi.price) FROM order_items oi48# JOIN products p ON oi.product_id = p.id49# JOIN orders o ON oi.order_id = o.id50# WHERE p.category = 'elektronik'51# AND strftime('%Y-%m', o.created_at) = '2025-01'
Train dan eval menggunakan nilai berbeda (pool A vs pool B: kategori, bulan, kota) untuk menguji generalisasi, bukan hafalan. Hasil dev 97.26%, test held-out 91.78%.
Batasan
Skema spesifik. Hanya untuk 5 tabel di atas. Skema berbeda perlu fine-tuning ulang.
Query SELECT saja - tidak mendukung INSERT/UPDATE/DELETE
Bahasa Indonesia dengan kosakata bisnis, tidak diuji pada bahasa lain
Maksimum ~768 token input
Lisensi
Apache 2.0 - bebas dipakai, dimodifikasi, didistribusikan.