ders_04 / agent
// Veriyle Konusan Analitik Asistan

Agent:
Self-Correction

Ders 4  ·  Tool calling + kendi hatasini duzelten asistan

01 / Temsil 02 / Text-to-SQL 03 / Schema-RAG 04 / Agent 05 / Guvenlik 06 / Deploy

LLM → Agent

LLM tek basina

  • Sadece SQL metni uretir
  • Calistiramaz
  • Sonucu bilmez
  • Hata alsa haberi olmaz

Agent

  • SQL'i calistirir
  • Sonucu/hatayi gorur
  • Gerekirse duzeltir
  • Sonra cevaplar
Agent = LLM + Arac + Dongu. Bu dersin kalbi.

ReAct Dongusu

Reason — model dusunur: hangi SQL?
Act — execute_sql aracini cagirir
Observe — sonucu / hatayi okur
↻ Tekrar — hata varsa duzeltip yeniden dener
Dusun → Hareket et → Gozlemle → (gerekirse) Duzelt. Cevap hazir olana kadar donguye devam.

Tool Calling Mekanigi

Modele araci tarif et
model "sunu calistir" der
BIZ calistiririz
sonucu geri veririz
TOOLS = [{"type":"function", "function":{
  "name": "execute_sql",
  "description": "DuckDB'de SELECT calistirir, sonucu doner. SQL hazirlayinca cagir.",
  "parameters": {"type":"object",
     "properties":{"sql":{"type":"string"}}, "required":["sql"]}}}]

Aracin Gercek Isi: execute_sql

def execute_sql(sql):
    # Guvenlik: sadece SELECT (Ders 5'te derinlesir)
    if not sql.strip().lower().startswith("select"):
        return "HATA: yalnizca SELECT calistirilir."
    try:
        return _db.sql(sql).df().to_string(index=False)
    except Exception as e:
        return f"SQL HATASI: {e}"   # <-- hatayi MODELE geri veriyoruz
Puf nokta: hatayi exception olarak patlatmiyoruz — metin olarak modele donuyoruz. Model bu hatayi okuyup sorguyu duzeltebilsin diye.

ReAct Dongusu — Kod

def run_agent(question, max_steps=6):
    messages = [{"role":"system", "content": "...SQL'e cevir, execute_sql ile "
                 "calistir. SQL HATASI alirsan duzeltip tekrar dene..." + SCHEMA},
                {"role":"user", "content": question}]
    for _ in range(max_steps):
        msg = chat(messages, tools=TOOLS).choices[0].message
        if not msg.tool_calls:
            return msg.content              # nihai cevap
        messages.append(...)                    # asistan mesaji + tool_calls
        for tc in msg.tool_calls:
            result = execute_sql(json.loads(tc.function.arguments)["sql"])
            messages.append({"role":"tool", ..., "content": result})

Self-Correction — Agent'in Ozu

Gercek senaryo: schema drift — dokuman birth_date kolonu var diyor, ama DB'de yok.

1. Agent semaya guvenir → ORDER BY birth_date
2. SQL HATASI: Binder Error: birth_date not found
3. Agent hatayi okur, tabloyu inceler
4. registered_at ile duzeltip tekrar calistirir
5. Durustce aciklar → "birth_date yok, kayit tarihine gore siraladim"
Asistan kendi hatasini gordu ve duzeltti. "Agent"i LLM'den ayiran sey tam olarak budur.

📦 Sektor Notu + SDK

Elle yazdik — neden?

Dongu net anlasilsin diye. Gercekte "tool runner" / LangGraph bu donguyu otomatik cevirir.

Dongu limiti sart

  • Sonsuz duzeltme = yanan token
  • max_steps ile sinirla
  • Retry sayisi + maliyet takibi
Olcek koprusu: Bu demoda sema kucuk (4 tablo) → agent'a dogrudan veriyoruz. Buyuk semada ikinci bir get_schema araci eklenir: Ders 3'un relevant_schema'sini agent'a baglar (agentic RAG). Yani RAG, olcek gerektirdiginde araca donusur.
Self-correction gercek production kalibi — ama bedava degil. Her adim bir LLM cagrisi.

Ders 4 — Ozet

🔧

Tool

execute_sql — modele "el" verdik.

ReAct

Dusun → calistir → gozlemle → duzelt.

Self-correct

Hatayi gorur, kendi duzeltir.

Sonraki ders: DB'ye SQL calistiran agent tehlikeli olabilir — guvenlik, coklu agent, eval.