AI Ajanlarında Sonsuz Döngü Bariyeri: LangGraph ve Plan-and-Solve Mimarisi

AI Ajanlarında Sonsuz Döngü Bariyeri: LangGraph ve Plan-and-Solve Mimarisi
AI Ajanlarında Sonsuz Döngü Bariyeri: LangGraph ve Plan-and-Solve Mimarisi
Bizi Google'da tercih edilen kaynak yapın!

Büyük dil modellerini (LLM) kurumsal yazılım mimarilerine entegre ederken karşılaşılan en büyük operasyonel risk, otonom ajanların üretim ortamında (production) beklenmeyen uç durumlar karşısında döngüsel mantık hatalarına düşmesidir. Ajanın kendi kararlarını dinamik olarak ürettiği geleneksel ReAct (Reasoning and Acting) modelleri, API yanıtlarındaki anomaliler veya araç (tool) çıktılarındaki şema uyumsuzlukları nedeniyle while True sarmalına kilitlenebilir. Bu durum, dakikalar içinde binlerce dolarlık API bütçesini tüketerek altyapıyı işlevsiz hale getirir.

Bu rehberde, ajan otonomisini tamamen yok etmeden kontrol edilebilir bir yürütme katmanı sunan Plan-and-Solve (DAG) mimarisini, LangGraph kütüphanesinin stateful (durum korumalı) tasarım kalıplarını ve üretim ortamında loop bariyeri kurma stratejilerini derinlemesine inceliyoruz.

1. ReAct Mimarisinin Üretim Ortamındaki Yapısal Kırılganlıkları

Geleneksel otonom ajan tasarımları, LLM’in tek bir sistem promptu ve araç setiyle donatılarak sırasıyla düşünme, eylem planlama ve aracı tetikleme adımlarını tek başına yürütmesine dayanır. Bu serbest akış, basit prototiplerde esneklik sağlasa da ölçeklenebilir sistemlerde şu üç temel noktada çöker:

  • Sonsuz Araç Çağrısı Döngüsü (Tool-Looping): LLM, çağırdığı bir veritabanı sorgusundan veya API’den beklediği şemada veri alamadığında, bu hatayı mantıksal olarak düzeltmek yerine aynı aracı benzer hatalı parametrelerle üst üste tetikleme eğilimi gösterir. Bu durum kod düzeyinde bir kesme noktası yoksa sonsuza kadar devam edebilir.
  • Geometrik Context Büyümesi ve Maliyet Krizleri: Ajan her iterasyonda geçmiş tüm konuşma geçmişini, LLM düşüncelerini ve araç çıktılarının ham metinlerini kendi hafızasına (context window) ekler. Girdi payload boyutu geometrik olarak katlanır. Bu aşamada ham kodları ve log serilerini temizlemek için AppBilgi Yapay Zeka Prompt Sıkıştırıcı gibi token optimizasyon mekanizmalarından faydalanarak context penceresini korumak operasyonel maliyeti doğrudan düşürür. Aksi halde tek bir basit işlem yüz binlerce token’lık bir maliyet faturasına dönüşür.
  • İş Mantığı (Business Logic) Uyumsuzluğu: Kurumsal uygulamalar deterministik kurallara ihtiyaç duyar. Örneğin, bir finans uygulamasında veri çekme işlemi bitmeden analiz aşamasına geçilmemelidir. ReAct mimarisinde ise bu süreç tamamen LLM’in bir sonraki token tahmin olasılığına bırakıldığından, adımların sırası kararsız hale gelir.

2. Plan-and-Solve Mimarisi ve Deterministik DAG Yönetimi

Plan-and-Solve paradigması, ajanın hareket alanını tamamen kısıtlamaz ancak onu mühendislik tarafında sınırları çizilmiş bir plana sadık kalmaya zorlar. Sistem mimarisi iki ana katmandan oluşur:

A. Planlama Aşaması (The Planner): Sistem girdi aldığında, gelişmiş bir akıl yürütme modeli (örneğin GPT-4o veya Claude 3.5 Sonnet) tetiklenir. Bu modelin tek görevi, problemi çözmek için gereken tüm adımları içeren ve birbirine bağımlılıkları belirlenmiş bir Yönlendirilmiş Döngüsüz Grafik (DAG) oluşturmaktır. Çıktı, kesinlikle serbest metin değil, yazılım katmanının ayrıştırabileceği yapılandırılmış bir JSON şemasıdır.

B. Yürütme ve Yeniden Planlama Aşaması (The Executor & Re-planner): Ajan, DAG içindeki görevleri sırayla icra eder. Eğer bir görev başarıyla tamamlanırsa, durum nesnesi güncellenir ve bir sonraki adıma geçilir. Eğer bir adımda hata alınırsa veya gelen veri mevcut planın yönünü değiştirmeyi gerektirirse, ajan tüm süreci sıfırlamaz. Yeniden planlayıcı (re-planner) düğüm devreye girerek o ana kadar tamamlanmış adımları ve mevcut durumu analiz eder; sadece kalan adımlar için güncellenmiş yeni bir mini DAG planı hazırlar.

Bu tasarımda döngüsel akışlar, LLM’in anlık kararlarına değil, grafik mimarisinde önceden tanımlanmış deterministik koşullu kenarlara (conditional edges) bağlanır.

3. LangGraph Stateful Bellek Mimarisi ve Reducer Mekanizmaları

LangGraph, ajan tabanlı iş akışlarını düğümler (fonksiyonlar) ve kenarlar (yönlendirmeler) olarak modelleyen alt seviye bir orkestrasyon kütüphanesidir. Geleneksel zincirleme yapılardan en büyük farkı, grafın kalbinde yaşayan merkezi bir State (Durum) nesnesidir. Graf içerisindeki her düğüm bu state yapısından okuma yapar ve mutasyon çıktılarını yine buraya yazar.

Sonsuz döngüleri programatik olarak engellemenin yolu, bu state şeması üzerinde Reducer fonksiyonları kullanmaktır. Varsayılan olarak LangGraph’ta bir düğüm çıktı ürettiğinde, state nesnesindeki mevcut anahtarın değerini tamamen ezer (override). Ancak durum yapısında Annotated[List, operator.add] veya özel bir birleştirme fonksiyonu tanımlanırsa, yeni gelen veriler geçmişi yok etmeden mevcut duruma eklenir.

Bu durum yönetimi sayesinde, ajanın attığı her adım, harcadığı token miktarı ve araç çağrılarının geçmişi merkezi veri tabanında birikir. Böylece koşullu kenarlara eklenecek basit bir kod kontrolü (if execution_counter > max_retries), LLM ne kadar ısrar ederse etsin ajanın çalışmasını kod seviyesinde durdurabilir.

4. Uçtan Uca LangGraph ve Plan-and-Solve Uygulama Kodu

Aşağıdaki Python kodu, üretim ortamında kullanılabilecek, sonsuz döngü bariyerlerine ve dinamik yeniden planlama yeteneğine sahip örnek bir LangGraph mimarisini implement etmektedir:

import operator
from typing import List, Tuple, TypedDict, Annotated
from langgraph.graph import StateGraph, END

# 1. Grafın Paylaştığı Merkezi Durum (Shared State) Şeması
class PlanExecuteState(TypedDict):
    input: str                                     # Kullanıcının ana isteği
    plan: List[str]                                # Güncel görev listesi (DAG adımları)
    past_steps: Annotated[List[Tuple[str, str]], operator.add] # Tamamlanan adımların geçmişi
    current_step_index: int                        # Mevcut görev sırasını tutan sayaç
    loop_counter: int                              # Güvenlik için toplam iterasyon sayacı
    response: str                                  # Kullanıcıya dönecek nihai yanıt

# 2. İşlevsel Düğümlerin (Nodes) Kodlanması
def planner_node(state: PlanExecuteState):
    """Kullanıcı isteğini analiz edip doğrusal görev planı çıkaran düğüm."""
    # Üretim ortamında burada LLM structured_output moduyla çağrılır.
    # Gerçekçi bir senaryo için dinamik bir görev listesi simüle ediyoruz:
    return {
        "plan": ["Uzak API Kaynağını Sorgula", "Gelen Veriyi Temizle", "Rapor Çıktısı Hazırla"],
        "current_step_index": 0,
        "loop_counter": 0
    }

def executor_node(state: PlanExecuteState):
    """Mevcut plandaki ilgili adımı icra eden yürütücü düğüm."""
    current_idx = state["current_step_index"]
    current_task = state["plan"][current_idx]
    
    # Gerçek sistemlerde burası ilgili Python aracını veya alt ajanı tetikler.
    # Örnek araç yürütme çıktısı simülasyonu:
    task_result = f"[{current_task}] adımı başarıyla icra edildi."
    
    # State güncellenirken reducer sayesinde past_steps listesine ekleme yapılır.
    return {
        "past_steps": [(current_task, task_result)],
        "current_step_index": current_idx + 1,
        "loop_counter": state["loop_counter"] + 1
    }

def replanner_node(state: PlanExecuteState):
    """Her adımdan sonra gidişatı inceleyen ve planı valide eden düğüm."""
    # Eğer alt araçlardan biri hata dönmüş olsaydı, burada plana yeni adımlar eklenebilirdi.
    # Bu senaryoda planda bir değişiklik yapmadan mevcut planı koruyoruz.
    return {"plan": state["plan"]}

# 3. Yönlendirme ve Güvenlik Bariyeri (Conditional Edge Mantığı)
def should_continue(state: PlanExecuteState):
    """Grafın ilerleyişini denetleyen deterministik kontrol mekanizması."""
    
    # Bariyer 1: Plandaki tüm adımlar başarıyla tamamlandı mı?
    if state["current_step_index"] >= len(state["plan"]):
        return "finalize"
    
    # Bariyer 2: Mutlak Altyapı Koruması (Hard Loop Limit)
    # LLM veya araçlar hataya düşüp kısır döngü yaratsa bile grafı zorla kapatır.
    if state["loop_counter"] >= 8:
        return "finalize"
        
    return "continue"

def finalizer_node(state: PlanExecuteState):
    """Süreç bittiğinde state geçmişini derleyip nihai raporu üreten düğüm."""
    summary = f"İşlem başarıyla sonlandırıldı. Toplam {state['loop_counter']} operasyonel adım tüketildi."
    return {"response": summary}

# 4. StateGraph Yapılandırması
workflow = StateGraph(PlanExecuteState)

# Düğümlerin Grafa Tanımlanması
workflow.add_node("planner", planner_node)
workflow.add_node("executor", executor_node)
workflow.add_node("replanner", replanner_node)
workflow.add_node("finalizer", finalizer_node)

# Graf Akış Çizgilerinin İlişkilendirilmesi
workflow.set_entry_point("planner")
workflow.add_edge("planner", "executor")
workflow.add_edge("executor", "replanner")

# Koşullu Yönlendirme Kenarının Enjeksiyonu
workflow.add_conditional_edges(
    "replanner",
    should_continue,
    {
        "continue": "executor",
        "finalize": "finalizer"
    }
)

workflow.add_edge("finalizer", END)

# Grafın Çalıştırılabilir Uygulama Olarak Derlenmesi
app = workflow.compile()

5. Kurumsal Altyapı Gereksinimleri: Kalıcılık ve İnsan Denetimi

Kod katmanına eklenen döngü sayaçları tek başına yeterli değildir. Büyük ölçekli sistemlerin kesintisiz çalışması ve insan operatörlerle senkronize olabilmesi için şu iki mimari bileşenin entegre edilmesi kritik önem taşır:

  • Kalıcılık Katmanı (Checkpointer Entegrasyonu): LangGraph, graf mimarisindeki her düğüm geçişinde tüm state nesnesinin anlık görüntüsünü (snapshot) veri tabanına kaydeder. Geliştirme aşamasında bellek içi MemorySaver yeterliyken, üretim ortamında PostgresSaver veya Redis tabanlı sistemler kullanılır. Bu sayede, ajan üçüncü adımda bir ağ kesintisi veya rate-limit hatasıyla çökerse, tüm operasyonu baştan başlatıp bütçe harcamak yerine, en son geçerli snapshot verisini veri tabanından okuyarak kaldığı düğümden güvenle devam eder.
  • İnsan Denetimi (Human-in-the-Loop ve Kesme Noktaları): Kritik kararların (örneğin yüksek bütçeli bir reklam kampanyası başlatmak, veritabanı silmek veya ham bütçe transferi yapmak) alınacağı düğümlerden hemen önce grafa bir kesme noktası (interrupt_before) eklenerek akış durdurulur. Graf bu düğüme geldiğinde yürütmeyi tamamen durdurur, kaynakları serbest bırakır ve durumu dondurarak beklemeye alır. Dışarıdaki bir insan operatör panelden onay (approve) veya ret (reject) komutu gönderene kadar durum askıda kalır. Wi-Fi veya sunucu kesintilerinde veri kaybını önler.

Plan-and-Solve mimarisi ve stateful grafik yönetimi bir arada kullanıldığında, büyük dil modellerinin esnek yaratıcılığı ile geleneksel yazılım mühendisliğinin kararlı, güvenli ve tahmin edilebilir yapısı ideal bir dengede buluşmuş olur.

💡 Yapay Zekayı Kendi Haline Bırakırsak Ne Olur?

Yapay zekayı kendi haline bıraktığımızda, bazen inatçı bir çocuk gibi aynı hatayı takıntılı bir şekilde tekrarlayıp durabilir. Bu yeni nesil planlama ve haritalama sistemleri, yapay zekaya adeta bir emniyet kemeri takıyor. Onun kendi kendini tüketmesini engelliyor ve daha mantıklı adımlarla ilerlemesini sağlıyor.

Ancak unutmamak gerekir ki, yapay zekanın önüne koyduğumuz sınırlar sadece birer “yangın söndürücüdür”. Yapay zekanın takılmasını engellemek, onun o problemi kesin olarak çözdüğü anlamına gelmez; sadece bizim cüzdanımızı korur ve sistemin çökmesini önler. Bu yüzden gelecekte, yapay zekanın tıkandığı yerde “Bir insana soralım” diyebilen, insanla yapay zekayı ortak çalışan sistemler çok daha kıymetli olacak.