yazılar
İlk Text-to-SQL Asistanı — ve İlk Halüsinasyonu
Sunum slaytları →Seri: Doğal Dille Veritabanına Soru Sormak — Sıfırdan Text-to-SQL Asistanı. Önceki yazı: Token ve Embedding
Eğitim slaytları → Ders 2 — İlk SQL
İlk yazıda modelin metni nasıl sayıya çevirdiğini gördük. Şimdi işin eğlenceli kısmına geçiyoruz: bir dil modeline veritabanımızın yapısını anlatıp, doğal dilden SQL ürettireceğiz. “En çok satan 3 ürünü göster” yaz, model sana SELECT ... ORDER BY ... LIMIT 3 versin.
Ama bu yazının asıl dersi ikinci yarıda: model bazen kendinden emin bir şekilde yanlış üretir. Buna halüsinasyon diyoruz ve neden olduğunu anlamak, güvenilir bir asistan kurmanın ilk şartı.
Şemayı Modele Anlatmak
Model bizim veritabanımızı bilmiyor — hangi tablolar var, hangi kolonlar var, hiçbir fikri yok. O yüzden ona şemayı (tabloların ve kolonların tanımını) metin olarak veriyoruz. Buna “context” (bağlam) diyoruz.
Örnek veritabanımız küçük ve deterministik: bir e-ticaret senaryosu — customers, products, orders, order_items tabloları.
SCHEMA = """
Tablolar:
- customers(id, name, city, registered_at)
- products(id, name, category, price)
- orders(id, customer_id, order_date)
- order_items(id, order_id, product_id, quantity)
"""
Modele verdiğimiz talimat (prompt) basit: “Sen bir SQL uzmanısın. Aşağıdaki şemaya göre kullanıcının sorusunu sadece DuckDB SQL sorgusuna çevir, açıklama yazma.”
from openai import OpenAI
client = OpenAI(api_key=API_KEY, base_url="https://api.deepseek.com")
def generate_sql(question, schema=SCHEMA):
prompt = f"""Sen bir SQL uzmanısın. Şu şemaya göre soruyu SQL'e çevir.
Sadece SQL yaz, açıklama ekleme.
ŞEMA:
{schema}
SORU: {question}
SQL:"""
resp = client.chat.completions.create(
model="deepseek-chat",
messages=[{"role": "user", "content": prompt}],
temperature=0.0, # kararlı, aynı soruya aynı cevap
)
return clean_sql(resp.choices[0].message.content)
temperature=0.0 önemli: modeli olabildiğince kararlı yapıyor, yani aynı soruya hep aynı SQL’i üretiyor. Yaratıcılık istemiyoruz; doğruluk istiyoruz.
Çalıştırıp DuckDB’de deneyelim:
import duckdb
db = duckdb.connect("store.duckdb", read_only=True)
sql = generate_sql("En çok satan 3 ürünü toplam adetleriyle göster.")
print(sql)
print(db.sql(sql).df())
Sonuç:
name toplam_adet
Kablosuz Kulaklık 10
Kahve Makinesi 7
Su Şişesi 5
İşte bu — hiç SQL yazmadan, sadece Türkçe soruyla veritabanından cevap aldık. Birkaç soru daha:
- “İstanbul’da kaç müşteri var?” →
4 - “Her şehirde kaç müşteri var?” → şehir şehir dağılım
- “En pahalı 3 ürün hangisi?” → doğru sıralama
Model şaşırtıcı derecede iyi. Peki nerede tökezliyor?
Ve İlk Halüsinasyon
Şimdi modele, şemada olmayan bir şey soralım:
sql = generate_sql("Ürünlerin tedarikçi firmasını ve iletişim bilgisini göster.")
print(sql)
Model gayet emin bir şekilde şunu üretir:
SELECT p.name, s.company_name, s.contact_info
FROM products p
JOIN suppliers s ON p.supplier_id = s.id;
Sorun şu: suppliers diye bir tablo yok. Şemamızda tedarikçi bilgisi hiç geçmiyor. Model, “tedarikçi firması” ifadesini duyunca “eh, o zaman bir suppliers tablosu vardır herhalde” diye uydurdu. Çalıştırınca DuckDB haklı olarak isyan ediyor:
Catalog Error: Table with name suppliers does not exist!
İşte buna halüsinasyon diyoruz: modelin, elinde olmayan bilgiyi varmış gibi, gayet kendinden emin üretmesi.
Neden Halüsinasyon Olur?
Dil modeli özünde bir “sıradaki en olası kelime” tahmin makinesidir. Eğitim verisinde binlerce e-ticaret şeması görmüştür ve o şemalarda “products” ile “suppliers” sık sık yan yana geçer. Bu yüzden model için suppliers tablosu istatistiksel olarak çok makul bir tahmindir — bizim veritabanımızda öyle bir tablo olup olmadığını kontrol edemez, çünkü sadece metin üretir, veritabanına bakmaz.
Bir detay daha: model çoğu zaman eksik bir kolonu sessizce görmezden gelir (örneğin “doğum tarihi” sorunca o kolonu atlar), ama eksik bir tabloyu cesurca uydurur. Halüsinasyonu güvenilir şekilde görmek istiyorsak, ona olmayan bir tablo sordurmak en net yol.
Bundan Nasıl Kurtulacağız?
Bu, kaçınılması gereken bir “hata” değil — dil modelinin doğasında olan bir durum. Çözüm modeli suçlamak değil, ona doğru bilgiyi doğru anda vermek ve ürettiğini kontrol etmek. Önümüzdeki iki yazının konusu tam olarak bu:
- Ders 3 (RAG): Şemayı olduğu gibi tıkıştırmak yerine, soruyla ilgili tabloları akıllıca seçip vereceğiz. Doğru bağlam, daha az halüsinasyon.
- Ders 4 (Agent): Modele SQL’i çalıştırma yeteneği vereceğiz; hata alırsa (mesela “suppliers yok” gibi) hatayı okuyup kendini düzeltecek.
Şimdilik akılda kalması gereken tek cümle: model metin üretir, gerçeği bilmez. Güven ama doğrula.
Seri:
- Token ve Embedding
- İlk SQL ve Halüsinasyon (bu yazı)
- RAG Aslında Ne? Doğru Tabloyu Bulmak
- Agent: Tool Calling ve Self-Correction
- Güvenlik, Multi-Agent ve Eval
- Deploy: API, Docker ve AWS