AI Agents

Fonksiyon Çağrılarını Ustalaşmak: Eyleme Geçen Ajanlar Oluşturma

Büyük Dil Modelleri (LLM'ler) güçlü doğal dil işleyicileridir, ancak doğaları gereği kapalı sistemlerdir. Hava durumunu kontrol edemez, bir veritabanına sorgu gönderemez veya e-posta gönderemez. Sadece eğitim verilerine dayanarak bir sonraki token'ı tahmin edebilirler. Statik bilgi ile dinamik eylem arasındaki boşluğu kapatmak için geliştiriciler fonksiyon çağrılarını kullanır. Bu teknik, bir LLM'in bir araç kullanma kararı "halüsinasyon" etmesine ve uygulamanızın ayrıştırıp çalıştırabileceği yapılandırılmış bir JSON çıktısı üretmesine olanak tanır. Doğru tasarlandığında, fonksiyon çağrıları bir sohbet botunu gerçek dünya ile etkileşime girebilen otonom bir ajana dönüştürür.

Bir Fonksiyon Çağrısının Anatomisi

Fonksiyon çağrısı sihir değildir; kısıtlı bir çözümlendirme (decoding) sürecidir. Model, kullanılabilir fonksiyonların ve şemalarının bir listesiyle istemlenir (prompt). Serbest biçimli metin üretmek yerine, model fonksiyon adını ve argümanlarını içeren belirli bir JSON yapısı üretir. Kodunuz daha sonra bu JSON'u yakalar, şemaya göre doğrular ve ilgili Python metodunu veya API çağrısını çalıştırır.

Buradaki kritik bileşen JSON Şeması'dır. Belirsiz olabilecek standart API dokümantasyonunun aksine, fonksiyon çağrıları katı ve açık tanımlar gerektirir. Modelin tam olarak hangi veri tiplerinin beklendiğini, hangi alanların isteğe bağlı olduğunu ve hangi enum'ların (sabit listelerin) izin verildiğini bilmesi gerekir. Şemanız belirsizse, model varsayımlarda bulunacak ve bu da çalışma zamanı hatalarına yol açacaktır.

Python'da Pratik Uygulama

Aşağıda, genel bir LLM arayüzü kullanılarak basitleştirilmiş bir örnek bulunmaktadır. Önce aracın nasıl tanımlandığını, ardından modelin onu seçmesi için nasıl istemlendiğini (prompt) fark edin.

import json
from typing import Callable, Dict, Any

# 1. Fonksiyon mantığını tanımla
def get_weather(city: str) -> str:
    """Hava durumu verisi getirmeyi simüle eder."""
    # Gerçek bir uygulamada bu, harici bir API'yi çağırırdı
    return f"{city} şehrindeki hava durumu güneşli ve 72F."

# 2. LLM için şemayı tanımla
weather_tool = {
    "name": "get_weather",
    "description": "Verilen şehir için güncel hava durumunu getirir.",
    "parameters": {
        "type": "object",
        "properties": {
            "city": {
                "type": "string",
                "description": "Şehrin adı."
            }
        },
        "required": ["city"]
    }
}

# 3. LLM Çıktısı (Simüle Edilmiş)
# Gerçek bir senaryoda, istemi (prompt) ve araç tanımlarını API'ye gönderirdiniz.
llm_response = """
{
    "tool_name": "get_weather",
    "arguments": {
        "city": "San Francisco"
    }
}
"""

# 4. Ayrıştır ve Çalıştır
def dispatch_call(response_json: str) -> Any:
    data = json.loads(response_json)
    tool_name = data["tool_name"]
    args = data["arguments"]
    
    # Fonksiyon adlarını gerçek metotlara eşle
    tool_map: Dict[str, Callable] = {
        "get_weather": get_weather
    }
    
    if tool_name in tool_map:
        return tool_map[tool_name](**args)
    else:
        raise ValueError(f"Bilinmeyen araç: {tool_name}")

result = dispatch_call(llm_response)
print(result)

Belirsizlik ve Hataları Yönetme

Fonksiyon çağrılarında en yaygın tuzaklardan biri şemanın aşırı mühendislik yapılması'dır. Çok fazla parametre açığa çıkarırsanız, model hangilerini dolduracağı konusunda kararsız kalır. En iyi uygulama, bireysel fonksiyonların atomik (tek görevli) tutulmasını önerir. Karmaşık verilere ihtiyacınız varsa, 50 isteğe bağlı alanı olan genel bir "sorgu" fonksiyonu yerine, o kullanım senaryosu için özel bir fonksiyon oluşturun.

Ayrıca, JSON ayrıştırma hatalarını yönetmeniz gerekir. En sağlam modeller bile zaman zaman bozuk JSON çıktısı üretebilir, özellikle büyük bağlamlarla uğraşırken. JSON ayrıştırma mantığınızı her zaman bir try-catch bloğu içinde sarmalayın. Ayrıştırma başarısız olursa, ajanı çökertmeyin. Bunun yerine, hata mesajını LLM'e geri gönderin ve "Önceki çıktınız geçersiz JSON idi. Lütfen tekrar deneyin." gibi bir istem (prompt) ekleyin. Bu öz-düzeltme döngüsü güvenilirliği önemli ölçüde artırır.

Güvenlik Düşünceleri

Fonksiyon çağrıları önemli bir güvenlik yüzeyi ortaya çıkarır. LLM, arka ucunuzun (backend) çalıştırdığı kod argümanları üretmektedir. Keyfi çalıştırmaya izin verirseniz, bir istem enjeksiyonu (prompt injection) saldırısı felaket sonuçlar doğurabilir. Örneğin, bir kullanıcı modeli, kötü niyetli yüklerle delete_database veya send_email gibi bir fonksiyonu çağırmaya kandırabilir.

Bunu azaltmak için bir beyaz liste (whitelist) sistemi uygulayın. LLM'in, katı doğrulama olmadan büyük bir havuzdan dinamik olarak fonksiyon seçmesine asla izin vermeyin. Ayrıca, yüksek riskli eylemler için insan-döngüde (human-in-the-loop) onay adımları ekleyin. Veri değiştiren veya para harcayan bir fonksiyonu çalıştırmadan önce, ajanı duraklatın ve açık kullanıcı onayı isteyin.

Sonuç

Fonksiyon çağrıları, modern yapay zeka ajanlarının omurgasıdır. Doğal dil niyeti ile programatik çalıştırma arasında yapılandırılmış bir arayüz sağlar. Hassas şemalar tasarlayarak, sağlam hata yönetimi uygulayarak ve güvenliği önceliklendirerek, sadece sohbet eden değil, gerçekten operasyonel ajanlar oluşturabilirsiniz. Basit salt-okunur araçlarla küçük başlayın, deseni ustalaşın ve ajanınızın yeteneklerini kademeli olarak genişletin. Yapay zekanın geleceği sadece konuşmakla ilgili değil; eyleme geçmekle ilgili.

Share: