Ajan mantığına giriş
Önkoşul:RAG'e giriş
Kanca
- derste model, bir bilgi tabanından tek bir belge getiriyordu. Peki model, hem bir belge arayıp hem de bir hesaplama yapması gereken bir soruyla karşılaşırsa?
Sezgi
Bir “ajan” (agent), modelin çıktısının bir kısmını “araç çağrısı” olarak yorumlayıp gerçek bir fonksiyon çalıştıran, sonucu tekrar bağlama ekleyen bir sistemdir. Bu, düşün -> araç seç -> çalıştır -> gözlemle döngüsünü, görev bitene kadar tekrarlar — 11. dersteki RAG, tek araçlı (getirme) bir ajanın özel bir HÂlidir.
Mekanizma
Önce iki gerçek araç kuralım. İlki bir hesap makinesi — ama neden ham eval() yerine güvenli bir ayrıştırıcı kullanıyoruz?
Güvenli hesap makinesi: eval() yerine AST
# Bir "ajan" (agent), model çıktısının bir kısmını "araç çağrısı" (tool call) olarak
# yorumlayıp gerçek bir fonksiyon çalıştıran, sonucu tekrar bağlama ekleyen bir sistemdir.
# İlk araç: güvenli bir hesap makinesi. Neden ham eval() kullanmıyoruz?
OPS = {ast.Add: operator.add, ast.Sub: operator.sub, ast.Mult: operator.mul,
ast.Div: operator.truediv, ast.Pow: operator.pow, ast.USub: operator.neg}
def guvenli_hesapla(ifade):
def degerlendir(dugum):
if isinstance(dugum, ast.Constant):
return dugum.value
if isinstance(dugum, ast.BinOp):
return OPS[type(dugum.op)](degerlendir(dugum.left), degerlendir(dugum.right))
if isinstance(dugum, ast.UnaryOp):
return OPS[type(dugum.op)](degerlendir(dugum.operand))
raise ValueError(f"Desteklenmeyen ifade: {ast.dump(dugum)}")
agac = ast.parse(ifade, mode="eval")
return degerlendir(agac.body)
print(f"guvenli_hesapla('30 * 2') = {guvenli_hesapla('30 * 2')}")
# Ham eval() kullansaydık ne olurdu? Model çıktısı (ya da kötü niyetli bir kullanıcı)
# Zararlı bir "ifade" göndererek keyfi kod çalıştırabilirdi:
ZARARLI_GIRDI = '__import__("os").system("echo bu calismamali")'
try:
guvenli_hesapla(ZARARLI_GIRDI)
print("Güvenlik açığı: zararlı kod çalıştı!")
except (ValueError, KeyError, SyntaxError) as e:
print(f"\nZararlı girdi ('{ZARARLI_GIRDI}') güvenli biçimde reddedildi: {type(e).__name__}")
print("Sadece sayı ve aritmetik işlem düğümlerine (BinOp) izin veren bir ayrıştırıcı (AST),")
print("ham eval()'ın açtığı keyfi kod çalıştırma riskini tamamen kapatıyor.")guvenli_hesapla('30 * 2') = 60
Zararlı girdi ('__import__("os").system("echo bu calismamali")') güvenli biçimde reddedildi: ValueError
Sadece sayı ve aritmetik işlem düğümlerine (BinOp) izin veren bir ayrıştırıcı (AST),
ham eval()'ın açtığı keyfi kod çalıştırma riskini tamamen kapatıyor.İkinci araç, 11. dersteki aynı belge getirme motoru:
İkinci araç: belge getirme
# İkinci araç: 11. dersteki aynı TF-IDF getirme motoru.
BELGELER = [
"Academyou AI, yapay zeka eğitimi sunan bir platformdur.",
"Academyou AI ücretsiz derslerini 2026 yılında yayınlamaya başladı.",
"Academyou AI platformunda Türkçe dilinde 150'den fazla ders bulunur.",
"İade politikamıza göre, satın alınan ürünler 30 gün içinde iade edilebilir.",
"Müşteri destek ekibimize hafta içi 09.00-18.00 arasında ulaşabilirsiniz.",
"Şirketimiz 2023 yılında İstanbul'da kuruldu.",
]
def tokenize(s):
return s.lower().replace(".", "").replace(",", "").replace("'", "").split()
def tf(belge):
kelimeler = tokenize(belge)
return {k: v / len(kelimeler) for k, v in Counter(kelimeler).items()}
def idf(belgeler):
N = len(belgeler)
sayim = Counter()
for b in belgeler:
for k in set(tokenize(b)):
sayim[k] += 1
return {k: math.log(N / v) for k, v in sayim.items()}
idf_degerleri = idf(BELGELER)
tum_kelimeler = sorted(set(k for b in BELGELER for k in tokenize(b)))
def tfidf_vektor(belge):
tf_d = tf(belge)
return [tf_d.get(k, 0) * idf_degerleri.get(k, 0) for k in tum_kelimeler]
def kosinus(a, b):
dot = sum(x * y for x, y in zip(a, b))
na, nb = math.sqrt(sum(x*x for x in a)), math.sqrt(sum(x*x for x in b))
return dot / (na * nb + 1e-10)
def belge_ara(sorgu):
sv = tfidf_vektor(sorgu)
benzerlikler = [(i, kosinus(sv, tfidf_vektor(b))) for i, b in enumerate(BELGELER)]
en_iyi = max(benzerlikler, key=lambda x: x[1])
return BELGELER[en_iyi[0]], en_iyi[1]
sonuc, skor = belge_ara("iade süresi")
print(f"\nbelge_ara('iade süresi') = (\"{sonuc}\", {skor:.3f})")
belge_ara('iade süresi') = ("İade politikamıza göre, satın alınan ürünler 30 gün içinde iade edilebilir.", 0.302)Matematik
ReAct döngüsü
Her (araç sonucu), bir sonraki adımın bağlamının parçası olur — 17. dersteki (NLP kategorisi) otoregresif üretimle aynı ilke, şimdi araç sonuçlarıyla genişletilmiş bir bağlamda çalışıyor.
Kod
Şimdi her iki aracı da kullanan tam bir ajan döngüsünü çalıştıralım — model bu ortamda gerçek bir LLM olmadığı için “düşünce” adımları öğretici amaçlı senaryolandırıldı, ama araç çağrılarının sonuçları gerçektir:
İki araçlı bir ajan döngüsü
# Bir ajan döngüsü (ReAct tarzı): düşün -> Araç seç -> Çalıştır -> Gözlemle -> Tekrarla
# -> Son cevap. Model bu ortamda gerçek bir LLM olmadığı için, "Düşünce" adımları
# öğretici amaçlı elle senaryolandırıldı -- ama araç çağrılarının sonuçları gerçektir.
SORU = "İade süresi kaç gün, ve bu sürenin 2 katı kaç gün eder?"
print(f"\nSoru: \"{SORU}\"\n")
print("Adım 1 -- düşünce: Önce iade süresini bulmam lazım.")
print("Adım 1 -- araç çağrısı: belge_ara(\"iade süresi\")")
belge, skor = belge_ara("iade süresi")
print(f"Adım 1 -- gözlem: \"{belge}\" (benzerlik: {skor:.3f})")
print("\nAdım 2 -- düşünce: Belgede '30 gün' yazıyor. Şimdi 30'un 2 katını hesaplamalıyım.")
print("Adım 2 -- araç çağrısı: guvenli_hesapla(\"30 * 2\")")
iki_kati = guvenli_hesapla("30 * 2")
print(f"Adım 2 -- gözlem: {iki_kati}")
print(f"\nSon cevap: İade süresi 30 gün; bunun 2 katı {iki_kati} gün eder.")
print("\nBu döngüde iki araç (getirme + hesaplama) sırayla çağrıldı -- her aracın sonucu,")
print("bir sonraki adımın bağlamının parçası oldu (17. dersteki otoregresif üretimle aynı ilke,")
print("şimdi araç sonuçlarıyla genişletilmiş bir bağlamda).")
Soru: "İade süresi kaç gün, ve bu sürenin 2 katı kaç gün eder?"
Adım 1 -- düşünce: Önce iade süresini bulmam lazım.
Adım 1 -- araç çağrısı: belge_ara("iade süresi")
Adım 1 -- gözlem: "İade politikamıza göre, satın alınan ürünler 30 gün içinde iade edilebilir." (benzerlik: 0.302)
Adım 2 -- düşünce: Belgede '30 gün' yazıyor. Şimdi 30'un 2 katını hesaplamalıyım.
Adım 2 -- araç çağrısı: guvenli_hesapla("30 * 2")
Adım 2 -- gözlem: 60
Son cevap: İade süresi 30 gün; bunun 2 katı 60 gün eder.
Bu döngüde iki araç (getirme + hesaplama) sırayla çağrıldı -- her aracın sonucu,
bir sonraki adımın bağlamının parçası oldu (17. dersteki otoregresif üretimle aynı ilke,
şimdi araç sonuçlarıyla genişletilmiş bir bağlamda).Son olarak, 2. dersteki bağlam penceresi uyarısının ajan döngülerinde nasıl büyüdüğüne bakalım:
Her araç çağrısı, bağlamı büyütür
# 2. dersteki uyarıyı hatırla: her ajan adımı, bağlama yeni token'lar ekler -- uzun bir
# ajan döngüsü, aynı karesel maliyet büyümesi riskini taşır.
adim_token_maliyetleri = [15, 22, 18, 25] # Öğretici amaçlı örnek (her adımın yaklaşık token maliyeti)
kumulatif = 0
print(f"\n{'Adım':<8} {'Bu adımın maliyeti':<20} {'Kümülatif bağlam'}")
for i, m in enumerate(adim_token_maliyetleri, 1):
kumulatif += m
print(f"{i:<8} {m:<20} {kumulatif}")
print(f"\n4 adımlık bir ajan döngüsü, bağlamı {adim_token_maliyetleri[0]}'ten {kumulatif}'e büyüttü --")
print("2. dersteki aynı 'her tur tüm geçmişi taşır' riski, ajan döngülerinde de geçerlidir,")
print("hatta araç sonuçları (belge parçaları, API yanıtları) genelde metinden daha uzundur.")
Adım Bu adımın maliyeti Kümülatif bağlam
1 15 15
2 22 37
3 18 55
4 25 80
4 adımlık bir ajan döngüsü, bağlamı 15'ten 80'e büyüttü --
2. dersteki aynı 'her tur tüm geçmişi taşır' riski, ajan döngülerinde de geçerlidir,
hatta araç sonuçları (belge parçaları, API yanıtları) genelde metinden daha uzundur.Nerede işe yarar
Ajan mantığı, bu kursta öğrendiğin her şeyin (tokenizasyon, bağlam penceresi, RAG, halüsinasyon) bir araya geldiği son noktadır:
- Araç seçimi güvenilir olmalıdır — model yanlış aracı çağırırsa (ya da yanlış argümanla), sonuç yanlış olur; bu ders özellikle güvenli araç tasarımını (ham eval() yerine kısıtlı bir ayrıştırıcı) vurguladı.
- Her araç çağrısı, gerçek dünyada bir etki yaratabilir — bir e-posta gönderen, bir ödeme yapan, bir dosya silen bir araç, dönüşü olmayan sonuçlar doğurabilir; bu yüzden gerçek ajan sistemlerinde, riskli eylemler genelde insan onayı gerektirir.
- Uzun ajan döngüleri, 2. dersteki karesel maliyet büyümesini hızlandırır — her araç sonucu genelde saf metinden uzundur, bu da bağlam penceresini (2. ders) daha hızlı doldurur.
Bu 2 hatayı yaparsın:
- Bir aracın (özellikle kod çalıştıran bir aracın) girdisini doğrudan
eval()gibi bir fonksiyona vermek — bu dersteki güvenli ayrıştırıcı örneği, bunun neden tehlikeli olduğunu gösteriyor. - Ajan döngülerinin sınırsız çalışabileceğini varsaymak — hem maliyet (2. ders) hem de hata birikimi riski nedeniyle, gerçek sistemler ajan döngülerine bir maksimum adım sayısı koyar.
Kendini test et
1. Bu derste hesap makinesi aracı neden ham eval() yerine bir AST (soyut sözdizimi ağacı) ayrıştırıcısıyla kuruldu?
- Sadece hızı artırmak için
- eval(), gelen bir metni doğrudan Python kodu olarak çalıştırır -- bu, model çıktısı (ya da kötü niyetli bir girdi) aracılığıyla keyfi kod çalıştırılmasına izin verir; AST ayrıştırıcısı sadece sayı ve aritmetik işlemlere izin vererek bu riski kapatır (doğru cevap)
- AST her zaman daha hızlı çalışır
- eval() Türkçe karakterleri desteklemez
Neden: arac-1-hesap-makinesi bloğunda, guvenli_hesapla() zararlı bir __import__("os").system(...) girdisini güvenle reddediyor -- ham eval() bunu çalıştırırdı.
2. Bu dersteki ajan döngüsünde, iki araç (belge_ara ve guvenli_hesapla) neden sırayla çağrılıyor, aynı anda değil?
- Rastgele bir sıralama
- İkinci aracın (hesaplama) girdisi, birinci aracın (getirme) sonucuna bağlıdır -- '30'un 2 katı' hesaplanmadan önce, '30 gün' bilgisinin bulunması gerekir; bu, NLP kategorisinin 17. dersindeki otoregresif üretimle aynı 'önceki adım, sonrakinin girdisi olur' ilkesidir (doğru cevap)
- Araçlar her zaman rastgele sırayla çalışır
- İki aracı aynı anda çağırmak teknik olarak imkansızdır
Neden: ajan-dongusu bloğunda Adım 2'nin hesaplaması (30 * 2), Adım 1'in gözleminden (30 gün) gelen bilgiye dayanıyor -- MathBox'taki ReAct formülü bu sıralı bağımlılığı gösteriyor.
3. Ajan döngülerinde 'gerçek dünyada etki yaratan' bir araç çağrısı (örn. e-posta gönderme) neden özellikle dikkat gerektirir?
- Böyle araçlar her zaman yasaktır
- Bu tür eylemler genelde geri alınamaz (irreversible) sonuçlar doğurur -- model yanlış bir kararla bu aracı çağırırsa, sonuç düzeltilemeyebilir; bu yüzden riskli eylemler genelde insan onayı gerektirir (doğru cevap)
- Bu tür araçlar daha yavaş çalışır
- Bu tür araçlar token maliyetini etkilemez
Neden: kullanım bölümünde açıkça belirtildiği gibi, bir e-posta gönderen ya da ödeme yapan bir aracın dönüşü olmayan sonuçları olabilir -- bu da insan onayı gerekliliğinin nedenidir.
Özet
Özet
- Bir ajan, model çıktısını "araç çağrısı" olarak yorumlayıp gerçek bir fonksiyon çalıştıran, sonucu bağlama geri ekleyen bir sistemdir.
- ReAct döngüsü: Düşün -> Araç Seç -> Çalıştır -> Gözlemle -> (tekrarla) -> Son Cevap.
- 11. dersteki RAG, tek araçlı (getirme) bir ajanın özel bir halidir.
- Araç girdilerini asla ham eval() gibi bir fonksiyona verme -- kısıtlı bir ayrıştırıcı (AST) kullanmak, keyfi kod çalıştırma riskini kapatır.
- Uzun ajan döngüleri, 2. dersteki karesel maliyet büyümesini hızlandırır -- gerçek sistemler bir maksimum adım sayısı ve insan onay noktaları içerir.