2026-06-24
Yapılandırılmış ve SQL RAG
Kurumsal bilginin çoğu belgelerde değil, veritabanlarında ve tablolarda yaşar; ve dense passage retrieval, cevabı hesaplanması gereken bir soruyu cevaplayamaz. Retrieval-Augmented Generation üzerine sıfırdan bir serinin 18. bölümü: RAG ile text-to-SQL (şemayı getir, SQL üret, çalıştır, cevapla), tablo getirme ve ölçeklenme gerçeği, ve query başına metin araması ile SQL arasında yönlendirme.
Ne öğreneceksin
On yedi bölümdür bilgiyi metin gibi ele aldık: belgeler pasajlara bölündü (chunk edildi), gömüldü (embed edildi), benzerlikle getirildi ve bir model tarafından okundu. Bu işe yaradı, çünkü sorduğumuz soruların cevapları zaten pasajların içinde oturuyordu, bulunmayı bekliyordu. Bu bölüm, öyle çalışmayan bilgiyle yüzleşiyor: bir kurumun gerçekte bildiğinin çoğunu tutan satırlar, sütunlar ve tablolar. Tüm seriyi taşıyan dense retrieval sezgisinin yapılandırılmış veride neden sessizce çöktüğünü ve yerine neyin geçtiğini öğreneceksin: RAG ile text-to-SQL, yani pasajlar yerine ilgili şemayı (schema) getirdiğin, ona dayanan bir SQL query’si ürettiğin, o query’yi veritabanına karşı çalıştırdığın ve sonuçtan cevap verdiğin yöntem. Tüm veritabanını yapıştırmak yerine neden bir şema alt kümesi getirmen gerektiğini (tablolar büyüdükçe tablo üzerinde akıl yürütme bozulur ve gerçek şemalar herhangi bir prompt bütçesini fersah fersah aşar) ve son olarak bir query’yi SQL yoluna mı yoksa belge yoluna mı yönlendireceğini öğreneceksin; bu da doğrudan 15. bölümdeki karmaşıklık sınıflandırıcısına bağlanıyor.
Ön koşullar
Bu bölüm serinin geri kalanından biraz ayrı duruyor, çünkü serinin başka yerde değinmediği bir veri türüyle ilgili; ama yine de birkaç önceki parçaya yaslanıyor. İlk RAG’ini İnşa Et (6. bölüm) lazım, çünkü karşılaştıracağımız belge yolu tam olarak o retrieve-augment-generate döngüsü. Retrieval’ı Daha Akıllı Hale Getirmek (8. bölüm) lazım, çünkü daha büyük bir şeyin ilgili alt kümesini getirme fikri, şema getirmenin tam olarak ne olduğu. Uyarlanabilir RAG (15. bölüm) lazım, çünkü bu bölümün sonundaki yönlendirici, bir dal daha eklenmiş aynı karmaşıklık sınıflandırıcısı. Ve Üretimde RAG’deki (12. bölüm) üretim disiplini, uyarılar için kullandığımız mercek; çünkü üretilen SQL’i canlı bir veritabanına karşı çalıştırmak, tam olarak o bölümün seni dikkatli ele almayı öğrettiği türden sonuç doğuran bir eylem. Temel SQL bilgisi yeterli; eşlik eden kod, bir oturuşta okuyabileceğin stdlib sqlite3.
Dense retrieval burada neden işe yaramıyor
Tüm bölümü tetikleyen rahatsız edici gerçekle başlayalım. “Geçen çeyrekte gönderilmiş siparişlerden toplam gelirimiz ne kadardı?” diye sor; cevabı tutan hiçbir pasaj yok. Sayı, biri onu hesaplayana kadar metin olarak var olmuyor. Örtük biçimde, bir orders tablosundaki ve bir products tablosundaki binlerce satıra yayılmış halde yaşıyor ve onu üretmenin tek yolu o tabloları join etmek, çeyrekteki gönderilmiş siparişlere filtrelemek, fiyatı miktarla çarpmak ve toplamak. Bu bölümden önceki her bölümün motoru olan dense passage retrieval, query’yle anlamca benzer metni bulur. Bunda çok iyidir ama bu sorunun ihtiyaç duyduğu şeyi, yani bir satır kümesi üzerinde aritmetiği, yapmaktan tamamen acizdir. Corpus’ta en ilgili görünen chunk’ı getirebilirsin ve yine de kimsenin yazmadığı bir sayıyı içermez.
Bu, elle savuşturabileceğin bir uç durum değil. Bir kurumun bildiğinin çoğu yapılandırılmış: işlemler, envanter, kullanıcı kayıtları, sensör logları, finansallar, işi yürüten ilişkisel omurga. Kurduğumuz belge merkezli seri, politikalar, kılavuzlar, ticket’lar ve düzyazı için doğru araç. Veritabanı için yanlış araç ve orada ona uzanmak belirli, tanıdık bir başarısızlık üretir: modele metin olarak belirsizce ilgili birkaç satır tutuşturulur ve model, makul görünen ama yanlış bir sayıyı tahmin eder. Çözüm daha iyi bir embedder değil. Sorunun bir retrieval problemi olduğunu varsaymayı bırakıp aslında bir query problemi olduğunu kabul etmek.
Yani hamle, “retrieval”in ürettiği şeyi değiştirmek. Okunacak pasajlar getirmek yerine, bir modelin doğru bir query yazması için yeterli şemayı (schema) getiriyoruz, o query’yi SQL olarak üretiyoruz, çalıştırıyoruz ve gerçek sonuç satırlarından cevap veriyoruz. Retrieval hâlâ işini yapıyor (koca bir uzayı ilgili parçaya daraltıyor) ama artık ilgili parça metin değil tablo tanımları ve cevap okumaktan değil çalıştırmadan geliyor.
RAG ile Text-to-SQL
İşte döngü; serinin geri kalanıyla aynı beş kelimelik omurgaya sahip, yalnızca iki kelimesi değişmiş. Belge pipeline’ı embed et, getir, dayanaklandır, üret idi. Yapılandırılmış pipeline ise şemayı getir, SQL üret, çalıştır, cevapla. Bir kez baştan sona yürü, şekli netleşir.
İlginç kısım, birinci adımda ne getirdiğin; çünkü bu, tablo isimlerinden fazlası. Bir şema-getirme sistemi tipik olarak birkaç tür bağlam çeker ve her biri yerini hak eder:
- Şema embedding’leri. Her tabloya (ve çoğu zaman her sütuna) kısa, getirilebilir bir açıklama verilir: adı, sütunları ve bir satırın ne anlama geldiğine dair tek cümlelik bir açıklama. O kartları embed edersin ve bir soru geldiğinde en yakın birkaçını getirirsin. Bu yine sıradan dense retrieval, sadece belgelere değil şemaya yöneltilmiş.
- Sütun açıklamaları.
tieradlı bir sütun, bir şey onun'free','pro'ya da'enterprise'tuttuğunu söylemeden bir model için hiçbir anlam taşımaz. Gerçek sütun dokümantasyonu, şifreli bir şemayı bir modelin doğru sorgulayabileceği bir şemaya dönüştüren şeydir. - Örnek satırlar. Tablo başına bir avuç örnek satır, modele gerçek değer biçimlerini gösterir:
status’un'Shipped'ya da'SHIP'değil, tam olarak'shipped'string’i olduğunu, tarihlerin ISO string’leri olduğunu. Bu tek ekleme, geniş bir string-uyuşmazlığı hata sınıfını önler. - Bir alan sözlüğü (domain glossary). Sessiz kahraman bu. Kullanıcılar “revenue”, “active users”, “churn” gibi sütun olarak görünmeyen iş kelimeleri sorar. Sözlük, her iş terimini onu kodlayan sütunlara ve hesaplamaya eşler: “revenue”, var olmayan bir
revenuesütunu değil, siparişler üzerinden toplanmışprice * quantity’dir. Sözlük olmadan model sütun uydurur; sözlükle model senin kastettiğin query’yi yazar. - Few-shot SQL örnekleri. Kendi veritabanından birkaç (soru, SQL) çifti, modele kendi kurallarını öğretir: nasıl join yaptığını, nasıl adlandırdığını, kendi lehçenin tuhaflıklarını. Bunlar da getirilir; şu anki soruya en benzeyen geçmiş örnekler.
Getirilen o bağlamı bir araya getirirsin, bir modelden SQL yazmasını istersin ve sonra, en can alıcı kısım, onu çalıştırırsın. Çalıştırma, belge pipeline’ında hiçbir karşılığı olmayan adımdır ve cevabı güvenilir kılan da odur: veritabanı sayıyı tam olarak hesaplar, modelin hiç tahmin etmesine gerek kalmaz. Sonuç satırları geri döner ve son bir üretim adımı onları bir cevaba dönüştürür. Eşlik eden dosya bu döngünün tamamını stdlib Python’da yürütüyor: sql_rag.py küçük bir SQLite veritabanı kurar, ilgili şema kartlarını anahtar kelime örtüşmesiyle getirir, kural tabanlı bir stub ile SQL üretir (demo için LLM gerekmez), gerçek SQLite’a karşı çalıştırır ve satırlardan cevap verir. “What was our total revenue from shipped orders?” üzerinde çalıştırmak, orders ve products kartlarını getirir, SUM(p.price * o.quantity) join’ini üretir, çalıştırır ve 436.0 yazdırır; query onu hesaplayana kadar veride hiçbir yerde var olmayan bir sayı.
Demonun neyi mock’ladığına ve neyin gerçek olduğuna dair bir söz, çünkü ders tam olarak bu ayrımda. Şema getirme, embedding yerine anahtar kelime örtüşmesi ve SQL üretimi, bir model çağrısı yerine kural tabanlı bir stub; ikisi de dosyanın yalnızca standart kütüphaneyle çalışması için. Ama kontrol akışı tam olarak üretimdeki ile aynı ve çalıştırma adımı gerçekten gerçek: üretilen SQL, gerçek bir SQLite veritabanına karşı çalışır ve gerçek satırlar döndürür. Aktarılan kısım tam olarak bu. Anahtar kelime skorlayıcısını bir embedder’la, stub’ı bir modelle değiştir; aynı omurgaya sahip, çalışan bir text-to-SQL RAG sistemin olur.
Şemayı yapıştırmak yerine neden getiriyorsun
Akla gelen itiraz şu: neden şemayı hiç getiresin ki? Modern modellerin büyük bağlam pencereleri var. Neden tüm veritabanı şemasını her prompt’a yapıştırıp modelin ihtiyacı olanı seçmesine izin vermiyorsun? İki sebep var ve ikisi de ölçekle ilgili.
Birincisi, kurumsal şemaların devasa olması. Gerçek bir üretim veritabanı, demodaki üç düzgün tablo değildir. Yüzlerce ya da binlerce tablodur, çoğunun onlarca sütunu vardır, artı view’lar, foreign key’ler ve herhangi birini kullanılabilir kılan sütun dokümantasyonu ile örnek satırlar. Bir prompt’a serileştirildiğinde, tek bir örnek bile yazmadan büyük bir şema on binlerce ya da yüz binlerce token’a ulaşır. Onu bütün olarak yapıştırmak her istekte pahalıdır (12. bölümdeki input-token maliyeti, tekrar tekrar ödenir) ve sık sık hiç sığmaz.
İkinci sebep daha ince ve daha önemli: tablo üzerinde akıl yürütme, sen bağlam sınırına ulaşmadan çok önce, tablo büyüdükçe bozulur. Bu, ölçülmüş ve tekrar tekrar doğrulanmış bir bulgu. Modeller, tablo büyüdükçe tablo soru-cevaplamada tutarlı bir doğruluk düşüşü gösteriyor ve bu düşüş nominal bağlam penceresinin içinde başlıyor; yani darboğaz ham kapasite değil, akıl yürütme ve dikkat. Model teknik olarak yüz bin token’lık bir şemayı tutabilir ve yine de sorunun gerçekten ilgilendiği bir avuç tablo üzerinde olduğundan daha kötü akıl yürütür. Eski tablo-QA benchmark’ları, tam olarak modellerin güçlü olduğu yer olduğu için küçük tablolara (genelde birkaç bin token’ın altında) yaslanıyordu; gerçek kurumların sahip olduğu daha büyük, dağınık tablolara doğru it, doğruluk düşüyor. Bu, 7. bölümde belgelerle karşılaştığın aynı lost-in-the-middle dinamiği, şimdi bir şema kılığında. İlgili kümenin ötesindeki daha fazla bağlam yardımcı olmaz, aktif olarak zarar verir.
Bu iki gerçeği yan yana koy, sonuç zorunlu hale gelir: tüm şemayı yapıştıramazsın ve yapabilsen bile yapmamalısın. Yani RAG’in her zaman yaptığını yaparsın. İlgili alt kümeyi, bu sorunun ihtiyaç duyduğu birkaç tabloyu ve sütunu getirir ve modele yalnızca onları verirsin. Bu, şema bağlama (schema linking) (bazen şema getirme (schema retrieval) de denir) ve büyük veritabanları için asıl belirleyici adım: text-to-SQL doğruluğu, doğru tabloların prompt’a girip girmediğine son derece duyarlı. Retrieval-augmented şema bağlama, yani SQL üretmeden önce ilgili şema alt kümesini getirmek, güncel sistemlerin text-to-SQL’i devasa veritabanlarına ölçeklendirme biçimi tam olarak bu. Serinin sezgisi geçerliliğini koruyor: önce samanlığı daralt, sonra iğneler üzerinde akıl yürüt.
💡 Deneyimden
Çıkmasına yardım ettiğim ilk text-to-SQL sistemi demoda harika görünüyordu ve gerçek veri ambarıyla karşılaştığı an çöktü. Demoda özenle seçilmiş yaklaşık bir düzine tablo bağlamıştık, model temiz SQL yazıyordu ve herkes memnundu. Üretimde yaklaşık dokuz yüz tablo vardı ve bunların çoğunun, kimsenin bitirmediği üç migration’dan kalma neredeyse birebir aynı isimleri vardı:
orders,orders_v2veorders_archivegibi. Modele tüm katalog tutuşturulunca, kendinden emin biçimde sürekli yanlış olanı join etmeye devam etti. Query parse edildi, çalıştırıldı, bir sayı döndürdü ve o sayı sessizce iki yıldır hiç yazılmamış bir tablodan çekilmişti. Hiçbir şey hata vermedi. Çözüm daha akıllı bir prompt değildi; hangiorderstablosunun canlı olduğunu söyleyen gerçek, tablo başına açıklamalarla ve modelin birinin boş olduğunu görebilmesi için örnek satırlarla ciddiyetle yapılmış bir şema getirme oldu. Kataloğu boca etmek yerine küçük, iyi tanımlanmış bir alt küme getirdiğimiz an, doğruluk sıçradı ve bayat tablodan gelen cevaplar durdu. Aklımda kalan ders: yapılandırılmış veride yanlış cevapların çoğu, “SQL yazamayan” bir modelin kılığına girmiş şema bağlama başarısızlıklarıdır. Genelde yazabilir. Sadece ona yanlış tablolar tutuşturulmuştur.
Tek bir veritabanının ötesinde tablo getirme
Text-to-SQL, bilinen bir şemaya sahip, sorgulanabilir tek bir veritabanı varsayar. Yapılandırılmış bilgi, ortak bir şeması ve önünde bir SQL motoru olmayan bir tablo yığını (spreadsheet’ler, CSV’ler, çıkarılmış HTML tabloları) olduğunda ilişkili bir sorun ortaya çıkar. Burada ilk iş tablo getirme (table retrieval): bir soru verildiğinde, muhtemelen binlercesi arasından cevabı içerme olasılığı en yüksek tabloyu (ya da birkaç tabloyu) bulmak. Her tablonun kompakt bir temsilini (başlığı, sütun adları ve bir örnek satır kümesi) embed edersin ve en yakınını getirirsin; aynı dense-retrieval hamlesi, pasajlar ya da şema kartları yerine tablolara yöneltilmiş.
Doğru tabloya sahip olduğunda, bir önceki bölümdeki ölçeklenme gerçeğiyle en saf haliyle karşılaşırsın. Getirilen bir tablo büyük olabilir ve tüm satırlarını prompt’a boca etmek doğrudan bozulma eğrisine çarpar. O yüzden olgun kalıp, tabloyu hiç okumamak, onu sorgulamaktır: getirilen tabloyu küçük bir bellek-içi veritabanına (ya da bir dataframe’e) yükle, ona karşı kod ya da SQL üret, çalıştır ve sonuçtan cevap ver. Tablo-getirme adımı samanlığı bulur; üret-ve-çalıştır adımı, modelin kafasında yapmakta kötü olduğu akıl yürütmeyi yapar. Ne olursa olsun, tüm bölümü yöneten ilke tekrarlanır: ilgili yapıyı getir, sonra cevabı okumak yerine hesapla.
Yönlendirme: metin araması mı, SQL mi
Artık iki tür pipeline’ımız var: 6’dan 17’ye kadar olan bölümlerin belge yolu ve buradaki SQL yolu; ve gerçek soruları karşılayan bir sistemin her query’yi doğru olana göndermesi gerekiyor. Bu, 15. bölümdeki aynı yönlendirme sorunu ve aynı mekanizmayı yeniden kullanıyor: query’den ucuz sinyaller okuyan ve bir yol seçen küçük, hızlı bir sınıflandırıcı. 15. bölüm karmaşıklığa göre yönlendiriyordu (none, single, multi); burada bir yönlendirme ekseni daha ekliyoruz, yapı, ve onu koyacağın doğal yer aynı sınıflandırıcı.
Sinyal güvenilir, çünkü iki soru türü farklı ses çıkarıyor. Toplamsal ve sayısal sorular (aggregational and numeric questions) SQL’e yönlenir: “how many”, “count”, “total”, “sum”, “average”, “top”, “most”, “per region”, “revenue”; bir kayıt kümesi üzerinde hesaplanmış bir miktar isteyen her şey. Bunlar tam olarak hiçbir pasajın cevaplayamadığı sorular, bu bölümün açılışındakiler. Geri kalan her şey, “what is our refund policy?”, “how do I fix error E-4042?” gibi açıkla-ve-tarif-et soruları, gerçekten bir pasajın cevabı tuttuğu belge yoluna yönlenir. Sınıflandırıcı, tıpkı 15. bölümün karşılaştırma kelimelerine kilitlendiği gibi, o toplamsallık kelimelerine kilitlenir.
Eşlik eden dosyadaki route fonksiyonu tam olarak bu çatal: herhangi bir toplamsallık sinyali taşıyan bir query SQL döngüsüne gider, geri kalan her şey belge yoluna düşer (orada bir stub olarak mock’lanmış, çünkü gerçeğini zaten kurmuştun). Bilerek 15. bölümün classify_complexity’siyle aynı şekilde tasarlandı, çünkü mesele tam olarak bu: yapılandırılmış yönlendirme ayrı, cıvatalanmış bir sistem değil, zaten sahip olduğun yönlendiricideki bir dal daha. Bir üretim sisteminde iki eksen de birlikte yaşar. Önce sorunun türüne karar ver (yapılandırılmış mı, yapılandırılmamış mı), sonra her türün içinde, ne kadar mekanizmaya ihtiyacı olduğuna (15. bölümün karmaşıklık yönlendirmesi) karar ver. İki karar, tam olarak 15. bölümde kaynak yönlendirme ile karmaşıklık yönlendirmenin yaptığı gibi bir araya gelir.
Dürüst uyarı, 15. bölümün her sınıflandırıcı için dile getirdiğiyle aynı: bu bir başarısızlık yüzeyi ve tehlikeli yön sessiz olanı. Belge yoluna yanlış yönlendirilmiş sayısal bir soru, makul bir pasaj getirir ve modelin bir sayı tahmin etmesine izin verir; bu da kendinden emin, yanlış, dayanaksız bir rakam üretir, tam olarak bu bölümün varlık sebebi olan başarısızlık. O yüzden yapılandırılmış yönlendiriciyi ayarlarken, sınırdaki sayısal soruları SQL’e göndermeye yatkın hale getir; orada yanlış bir query en azından gürültülü biçimde başarısız olma eğilimindedir (bir SQL hatası, boş bir sonuç), düzyazıdan sessizce bir sayı uydurmak yerine.
Kendin dene
Tüm döngü, tek bir dosyayı düzenleyerek hissedebileceğin kadar küçük. sql_rag.py dosyasını al (yalnızca stdlib sqlite3, model ya da ağ gerekmez) ve çalıştır. Üç yapılandırılmış demo sorusunun sql’e yönlendiğini, iki tablolu bir şema alt kümesi getirdiğini, gerçek SQL ürettiğini, çalıştırdığını ve cevap verdiğini göreceksin (1 kurumsal müşteri, 436.0 toplam gönderilmiş gelir, 1 iade edilmiş sipariş); politika sorusu ise belge yoluna yönlenir ve veritabanına hiç dokunmaz. Alt satır all SQL answers match the seeded data: True yazdırır. Şimdi git, bilerek boz; sezgi tam olarak orada yaşıyor.
Önce bir şema-bağlama başarısızlığını izle. retrieve_schema fonksiyonu, anahtar kelime örtüşmesine göre en üstteki 2 tabloyu tutuyor. k=2’yi k=1 yap ve yeniden çalıştır. Gelir sorusu artık yalnızca orders’ı getiriyor, price’ı tutan products tablosu prompt’a hiç girmiyor ve generate_sql, tahmin etmek yerine doğru biçimde geri çekiliyor, “I could not turn that into a query over the known schema.” yazdırıyor. Bu doğru başarısızlık: query’nin iki tabloya ihtiyacı vardı ve yalnızca bir tane aldı, o yüzden uydurmak yerine reddetti. Üretim dersi tek cümlede bu: yapılandırılmış veride çok az şema getirmek, daha küçük bir cevap değil, yanlış (ya da yok) bir cevaptır.
İkincisi, sözlüğün verdiği sözü boz. Gelir SQL’i var oluyor, çünkü şema kartları ve sözlük, gelirin price * quantity’den hesaplandığını söylüyor. SCHEMA_CARDS’ı aç ve products kartından “Revenue is computed from price here times order quantity.” cümlesini sil. Yeniden çalıştır: “revenue” artık products kartında bir anahtar kelime olmadığından, products tablosu gelir sorusu için artık getirilmeyebilir ve query geri çekilir. Bu, sözlüğün ekmeğini hak ettiğinin görünür kılınmış hali. Getirilebilir bir yere yazılmamış iş sözlüğü, modelin senin sütunlarına eşleyemediği sözlüktür.
Üçüncüsü, yeni bir soru türü ekle. Stub’ın henüz ele almadığı bir toplamsallık seç, mesela “how many orders are still pending?”, ve neler olduğunu izle: sql’e yönlenir (“how many” içerdiği için), bir şema alt kümesi getirir, ama generate_sql’in eşleşen bir niyeti yoktur, o yüzden tahmin etmek yerine temizce geri çekilir. Şimdi generate_sql’e “pending”i tanıyan küçük bir dal ekle ve SELECT COUNT(*) FROM orders WHERE status = 'pending'; üretsin, 1 diye cevap verdiğini izle. Az önce gerçek bir text-to-SQL sistemini dürüst yoldan genişlettin: seferde bir tane iyi tanımlanmış niyet, her biri gerçekten getirdiğin şemaya dayanaklı.
⚠️ Sık yapılan hatalar
- Hesaplanmış bir soruda dense retrieval’a uzanmak. “Total revenue”, “how many”, “average per region”: bunların cevabı hiçbir pasajda oturmuyor, o yüzden en yakın chunk’ı getirip modelin okumasına izin vermek akıcı, uydurma bir sayı üretir. Cevap kayıtlar üzerinde hesaplanması gerekiyorsa, belge yoluna değil SQL yoluna aittir.
- Tüm şemayı prompt’a yapıştırmak. Gerçek şemalar yüzlerce tablo ve on binlerce token’dır; sığsalar bile, tablo kümesi büyüdükçe bağlam sınırına ulaşmadan çok önce tablo üzerinde akıl yürütme bozulur. İlgili şema alt kümesini getir (schema linking); kataloğu boca etme.
- Açıklama, örnek satır ya da sözlük olmadan tablo isimleri getirmek. Çıplak bir şema, modelin sütun uydurmasına, değer biçimlerini karıştırmasına (‘shipped’ ile ‘Shipped’) ve neredeyse birebir aynı üç tablodan hangisinin canlı olduğunu tahmin etmesine izin verir. Sütun açıklamaları, örnek satırlar ve bir alan sözlüğü, şema getirmeyi doğru SQL’e dönüştüren şeydir; yapılandırılmış veride yanlış cevapların çoğu, üretim başarısızlığı değil şema-bağlama başarısızlığıdır.
- Üretilen SQL’i geniş yetkilerle çalıştırmak. Bu, 12. bölümün en-az-yetki kuralı, şimdi yük taşıyor: bir modelin canlı veritabanına karşı SQL yazması ve çalıştırması güçlü, sonuç doğuran bir eylem. Üretilen query’leri salt-okunur bir bağlantıdan geçir, asla yazabilen ya da drop edebilen bir bağlantıdan değil; ve modelin SQL’ini doğrulanana kadar güvenilmez say.
- Sayısal bir soruyu belge yoluna yanlış yönlendirmek. Tehlikeli yön, düzyazıdan sessizce bir sayı uydurur. Yapılandırılmış yönlendiriciyi, sınırdaki toplamsallık sorularını SQL’e göndermeye yatkın hale getir; orada yanlış bir query, sessizce bir rakam uydurmak yerine gürültülü biçimde başarısız olma eğilimindedir (bir hata ya da boş sonuç).
Özet çıkarımlar
- Dense passage retrieval hesaplanmış bir soruyu cevaplayamaz. Kurumsal bilginin çoğu veritabanlarında ve tablolarda yaşar ve “total revenue” gibi bir sayı, bir query onu hesaplayana kadar metin olarak hiçbir yerde var olmaz. En yakın pasajı getirmek uydurma bir sayı üretir; çözüm daha iyi bir embedder değil, bir query’dir.
- RAG ile text-to-SQL, serinin omurgasındaki iki kelimeyi değiştirir: embed et, getir, dayanaklandır, üret yerine şemayı getir, SQL üret, çalıştır, cevapla. Veritabanı aritmetiği tam olarak yapar, model onu hiç tahmin etmek zorunda kalmaz.
- Getirdiğin şey tablo isimlerinden fazlası: şema embedding’leri, sütun açıklamaları, örnek satırlar, bir alan sözlüğü (“revenue” gibi iş kelimelerini onları kodlayan sütunlara ve hesaplamaya eşleyen) ve few-shot SQL örnekleri. Sözlük ve örnek satırlar, uydurulmuş-sütun ve yanlış-biçim hatalarının çoğunu önler.
- Tüm şemayı yapıştırmak yerine bir şema alt kümesi getirirsin, iki sebepten: kurumsal şemalar prompt bütçesi için çok büyüktür ve tablo kümesi büyüdükçe, bağlam penceresinin çok içindeyken bile tablo üzerinde akıl yürütme bozulur. Şema bağlama (ilgili tabloları getirmek), ölçekte text-to-SQL için belirleyici adımdır.
- Tablo getirme (table retrieval), fikri şemasız bir tablo yığınına genelleştirir: doğru tabloyu dense retrieval ile bul, sonra satırlarını prompt’a okumak yerine onu sorgula (kod ya da SQL yükle ve çalıştır).
- Yönlendirme, toplamsal ve sayısal soruları SQL yoluna, geri kalan her şeyi belge yoluna gönderir; 15. bölümdeki sınıflandırıcıyı bir dal daha ekleyerek yeniden kullanır. Sınırdaki sayısal soruları SQL’e yatkın hale getir, çünkü belgelere doğru yanlış yönlendirme bir sayı uydurarak sessizce başarısız olur.
Referanslar
- Xinyu Liu, Shuyu Shen, Boyan Li, Peixian Ma, Runzhi Jiang, Yuxin Zhang, Ju Fan, Guoliang Li, Nan Tang ve Yuyu Luo. “A Survey of Text-to-SQL in the Era of LLMs: Where are we, and where are we going?” 2024. arXiv:2408.05109. LLM tabanlı text-to-SQL’in tüm yaşam döngüsünü kapsayan geniş bir derleme: çeviri modelleri (ve bu bölümün schema linking dediği şema-eşleme ve belirsizlik zorlukları), eğitim verisi, değerlendirme ve hata analizi. Buradaki text-to-SQL çerçevelemesinin omurga referansı.
- Jinyang Li, Binyuan Hui, Ge Qu, Jiaxi Yang, Binhua Li, Bowen Li, Bailin Wang, Bowen Qin, Ruiying Geng, Nan Huo ve diğerleri. “Can LLM Already Serve as A Database Interface? A BIg Bench for Large-Scale Database Grounded Text-to-SQLs (BIRD).” NeurIPS 2023. arXiv:2305.03111. BIRD’ü tanıtıyor: 95 büyük gerçek dünya veritabanı üzerinde (37 alanda 33,4 GB) 12.751 soru-SQL çifti; özellikle daha önceki benchmark’ların (Spider, WikiSQL) az satırlı küçük şemalar kullanıp gerçek dünya zorluğunu gizlemesi yüzünden kurulmuş. Gerçek veritabanlarının şema getirmeyi ve değer/içerik anlayışını zorunlu kılacak kadar büyük olduğunun kanıtı.
- Jeffrey Eben, Aitzaz Ahmad ve Stephen Lau. “RASL: Retrieval Augmented Schema Linking for Massive Database Text-to-SQL.” 2025. arXiv:2507.23104. Bu bölümün merkezi fikrinin işlenmiş bir örneği: tüm kataloğu prompt’a yapıştırmak yerine, text-to-SQL’in devasa veritabanlarına ölçeklenmesi için SQL üretmeden önce ilgili şema alt kümesini getirmek.
- Soyeong Jeong, Jinheon Baek, Sukmin Cho, Sung Ju Hwang ve Jong C. Park. “Adaptive-RAG: Learning to Adapt Retrieval-Augmented Large Language Models through Question Complexity.” NAACL 2024. arXiv:2403.14403. 15. bölümün arkasındaki makale; query başına sınıflandırıcısı, bu bölümün yapılandırılmış-karşı-yapılandırılmamış bir dalla genişlettiği yönlendirici.
Sözlük
- Yapılandırılmış RAG (Structured RAG): yapılandırılmış veri (veritabanları ve tablolar) üzerinde retrieval-augmented generation; burada cevap, getirilen bir pasajdan okunmak yerine bir query tarafından hesaplanır.
- Text-to-SQL: doğal dildeki bir soruyu, bir veritabanına karşı çalıştırıldığında cevabı üreten bir SQL query’sine çevirmek.
- Şema getirme / şema bağlama (schema retrieval / schema linking): SQL üretmeden önce bir veritabanının şemasının ilgili alt kümesini (bir sorunun ihtiyaç duyduğu tabloları ve sütunları) getirmek; böylece model tüm katalog yerine küçük, ilgili bir şema üzerinde akıl yürütür.
- Şema kartı (schema card): bir tablonun kısa, getirilebilir açıklaması: adı, sütunları, bir satırın ne anlama geldiğine dair tek cümlelik açıklama ve çoğu zaman sütun açıklamaları ile örnek satırlar; şema bağlamada embed edip getirdiğin birim.
- Alan sözlüğü (domain glossary): iş sözlüğünden (revenue, churn, active user) şemada onu kodlayan sütunlara ve hesaplamaya bir eşleme; böylece model var olmayan sütunlar uydurmaz.
- Few-shot SQL örnekleri (few-shot SQL exemplars): kendi veritabanından, şu anki soruya benzerliğe göre getirilen örnek (soru, SQL) çiftleri; modele kendi kurallarını ve lehçeni öğretir.
- Çalıştırma (execution): üretilen SQL’i canlı veritabanına karşı çalıştırmak ve sonuç satırlarını okumak; belge pipeline’ında hiçbir karşılığı olmayan ve cevabı tahmin edilmiş yerine kesin kılan adım.
- Tablo getirme (table retrieval): birçok şemasız tablo (spreadsheet’ler, CSV’ler, çıkarılmış tablolar) verildiğinde, cevabı içerme olasılığı en yüksek tabloyu bulmak, sonra tüm satırlarını okumak yerine onu sorgulamak.
- Yapılandırılmış yönlendirme (structured routing): bir sorunun toplamsal/sayısal mı (SQL yoluna yönlendir) yoksa tanımlayıcı mı (belge yoluna yönlendir) olduğuna, 15. bölümdeki karmaşıklık yönlendiricisiyle aynı küçük sınıflandırıcıyı kullanarak karar vermek.
Sırada, 19. Bölüm. Bu, serinin planlanan kapanışıydı. On sekiz bölüm boyunca RAG’i temel ilkelerden inşa ettin: neden var olduğunu, embedding’lerin anlamı geometriye nasıl çevirdiğini, nasıl getirip yeniden sıraladığını (rerank ettiğini), dayanaklandırdığını ve ürettiğini, onu nasıl ölçtüğünü, üretimde nasıl çalıştırdığını ve şimdi de belgeler yerine veritabanlarında yaşayan yapılandırılmış bilgiye nasıl ulaşacağını. Ana hat hiç değişmedi: ilgili şeyi getir, sonra üzerinde akıl yürüt ve karmaşıklığı yalnızca kanıt gerektirdiğinde ekle. İlgili şey ister bir pasaj ister bir şema olsun, disiplin aynı. Ama serinin sürekli tarif edip bir kez bile çalıştırmadığı bir hamle var: modelin kendi retrieval döngüsünü kendisinin sürmesine, neyi getireceğine ve ne zaman durulacağına kendisinin karar vermesine izin vermek. 19. Bölüm, Bir RAG Agent’ı İnşa Etmek, seriyi tekrar ele alıyor ve nihayet çalıştırıyor. Herhangi bir parçayı yeniden ziyaret etmek ya da tüm haritayı bir arada görmek için RAG from First Principles hub’ına geri dön. Şimdi git, hepsini gerçek bir corpus’a ve gerçek bir veritabanına doğrult ve bir şey uydurmayan bir şey inşa et.