Takip et

LLM’lere BattleTech Oynamayı Öğretmek (Bölüm 2): C# ile Bir MCP Sunucusu ve Ajanlar İnşa Etmek

LLM’lere (Büyük Dil Modelleri) BattleTech gibi karmaşık strateji oyunlarını öğretmek, yapay zeka alanında heyecan verici bir meydan okumadır. Serin…

LLM’lere BattleTech Oynamayı Öğretmek (Bölüm 2): C# ile Bir MCP Sunucusu ve Ajanlar İnşa Etmek

LLM’lere (Büyük Dil Modelleri) BattleTech gibi karmaşık strateji oyunlarını öğretmek, yapay zeka alanında heyecan verici bir meydan okumadır. Serinin ilk bölümünde temel kavramları ve stratejileri ele almıştık. Bu ikinci bölümde ise, LLM tabanlı ajanlarımızın oyun içinde birbirleriyle ve oyun motoruyla etkileşim kurmasını sağlayacak kritik altyapıyı, yani bir Çoklu Ajan İletişim Protokolü (MCP) sunucusunu ve C# dilinde geliştirilmiş ajanları detaylıca inceleyeceğiz. Bu mimari, ajanların koordineli bir şekilde çalışmasını ve dinamik oyun ortamına adapte olmasını sağlayacak sağlam bir temel sunmaktadır.

Neden Bir MCP Sunucusu ve Çoklu Ajan Mimarisi?

BattleTech gibi dinamik ve kural tabanlı oyunlarda, yapay zeka ajanlarının yalnızca kendi iç mantıklarıyla değil, aynı zamanda oyun motoru ve diğer ajanlarla da etkileşim kurması gerekir. Bu etkileşimi yönetmek için merkezi bir iletişim altyapısı elzemdir.

Geleneksel Yaklaşımların Sınırlılıkları

Tekil, monolitik bir yapay zeka sistemi, oyunun karmaşıklığı arttıkça yönetilmesi zorlaşır. Oyun durumu değişikliklerini takip etmek, birden fazla ajanın kararlarını koordine etmek ve farklı stratejileri aynı anda uygulamak, tek bir büyük kod bloğu içinde verimli değildir. Ayrıca, LLM’lerin doğası gereği dış sistemlerle iletişim kurma ihtiyacı, geleneksel yaklaşımların yetersiz kalmasına neden olur.

Dağıtık Yapının Avantajları

Çoklu ajan sistemleri, her bir ajanın belirli bir rolü üstlendiği ve merkezi bir sunucu üzerinden iletişim kurduğu dağıtık bir yapı sunar. Bu mimari, modülerlik, ölçeklenebilirlik ve hata toleransı gibi önemli avantajlar sağlar. Her ajan, kendi LLM’i veya karar mekanizmasıyla bağımsız olarak çalışabilirken, sunucu tüm ajanlar arasındaki iletişimi ve oyun durumu güncellemelerini yönetir. Bu, özellikle BattleTech gibi birden fazla ‘Mech’in ve pilotun olduğu senaryolarda kritik öneme sahiptir.

BattleTech Bağlamında İhtiyaçlar

BattleTech’te her ‘Mech’ bir ajan olarak düşünülebilir. Bu ajanların konumlarını, hasar durumlarını, mühimmat seviyelerini ve hedeflerini sürekli olarak diğer ajanlarla ve oyun motoruyla paylaşması gerekir. Bir MCP sunucusu, bu bilgilerin güvenli ve düzenli bir şekilde akışını sağlayarak, LLM’lerin daha bilinçli ve koordineli kararlar almasına olanak tanır. Örneğin, bir ‘Mech’ düşman pozisyonunu tespit ettiğinde, bu bilgiyi diğer ‘Mech’lere ileterek ortak bir saldırı planı oluşturulabilir.

MCP Sunucu Tasarımı ve Protokol Detayları

Etkili bir çoklu ajan sistemi için sağlam bir iletişim protokolü ve sunucu tasarımı şarttır. Bu bölüm, sunucunun temel bileşenlerini ve ajanlar arası iletişimi tanımlayan protokolü ele almaktadır.

İletişim Protokolünün Tanımlanması

MCP, ajanların sunucuya ve birbirlerine nasıl mesaj göndereceğini ve alacağını belirleyen bir dizi kuraldır. Temel olarak, bu protokol şunları içermelidir:

  • Mesaj Tipleri: Oyun durumu güncellemesi, komut gönderimi, sorgulama, hata bildirimi.
  • Mesaj Formatı: Verilerin nasıl yapılandırılacağı (örneğin JSON).
  • Kimlik Doğrulama: Ajanların sunucuya güvenli bir şekilde bağlanması.
  • Oturum Yönetimi: Ajanların bağlantılarını takip etme.

Mesaj Formatları ve Veri Serileştirme

Veri serileştirme, ajanlar ve sunucu arasında değiş tokuş edilecek karmaşık oyun durumu nesnelerinin veya komutların metin tabanlı bir formata dönüştürülmesidir. JSON (JavaScript Object Notation), okunabilirliği ve esnekliği nedeniyle bu tür sistemler için ideal bir seçimdir. Örneğin, bir oyun durumu güncellemesi şöyle görünebilir:

{
  "MessageType": "GameStateUpdate",
  "Timestamp": "2023-10-27T10:00:00Z",
  "Payload": {
    "MechId": "Alpha",
    "Position": { "X": 10, "Y": 5 },
    "Health": 85,
    "Target": "Bravo",
    "ActionsAvailable": ["Move", "Fire", "Brace"]
  }
}

Bu format, hem insanlar hem de programlar tarafından kolayca ayrıştırılabilir ve işlenebilir.

Sunucu Rolleri ve Sorumlulukları

MCP sunucusu, sistemin kalbidir ve aşağıdaki temel sorumluluklara sahiptir:

  • Bağlantı Yönetimi: Yeni ajan bağlantılarını kabul etme ve mevcut bağlantıları sürdürme.
  • Mesaj Yönlendirme: Bir ajandan gelen mesajları ilgili diğer ajanlara veya oyun motoruna iletme.
  • Oyun Durumu Senkronizasyonu: Oyunun mevcut durumunu takip etme ve ajanlara düzenli güncellemeler gönderme.
  • Komut İşleme: Ajanlardan gelen komutları doğrulama ve oyun motoruna iletme.
  • Hata Yönetimi: Bağlantı kopmaları veya geçersiz mesajlar gibi durumları ele alma.

C# ile MCP Sunucusu Gerçekleştirimi

C#, .NET ekosisteminin sağladığı güçlü ağ ve asenkron programlama yetenekleri sayesinde bir MCP sunucusu geliştirmek için mükemmel bir seçimdir.

Temel Sunucu Yapısı: Soket Programlama

Bir TCP/IP tabanlı sunucu oluşturmak için C#'ın System.Net.Sockets namespace'i kullanılır. TcpListener sınıfı, gelen bağlantıları dinlemek için idealdir.

using System.Net;
using System.Net.Sockets;
using System.Text;

public class McpServer
{
    private TcpListener _listener;
    private List _connectedClients = new List();

    public McpServer(int port)
    {
        _listener = new TcpListener(IPAddress.Any, port);
    }

    public async Task StartAsync()
    {
        _listener.Start();
        Console.WriteLine("MCP Sunucusu dinlemede...");

        while (true)
        {
            TcpClient client = await _listener.AcceptTcpClientAsync();
            _connectedClients.Add(client);
            Console.WriteLine($"Yeni ajan bağlandı: {client.Client.RemoteEndPoint}");
            _ = HandleClientAsync(client); // Bağlantıyı asenkron olarak işle
        }
    }

    private async Task HandleClientAsync(TcpClient client)
    {
        NetworkStream stream = client.GetStream();
        byte[] buffer = new byte[1024];
        int bytesRead;

        try
        {
            while ((bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length)) != 0)
            {
                string message = Encoding.UTF8.GetString(buffer, 0, bytesRead);
                Console.WriteLine($"Ajan mesajı: {message}");
                // Mesajı işle ve diğer ajanlara yönlendir
                await BroadcastMessageAsync(message, client);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Ajan bağlantısı kesildi veya hata oluştu: {ex.Message}");
        }
        finally
        {
            _connectedClients.Remove(client);
            client.Close();
        }
    }

    private async Task BroadcastMessageAsync(string message, TcpClient sender)
    {
        byte[] data = Encoding.UTF8.GetBytes(message);
        foreach (var client in _connectedClients.ToList()) // ToList() ile koleksiyon kopyası üzerinde döngü
        {
            if (client != sender && client.Connected) // Gönderen hariç diğer bağlı ajanlara gönder
            {
                try
                {
                    await client.GetStream().WriteAsync(data, 0, data.Length);
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"Mesaj gönderme hatası: {ex.Message}");
                }
            }
        }
    }
}

Asenkron İstemci Yönetimi

async ve await anahtar kelimeleri, sunucunun birden fazla istemci bağlantısını aynı anda, bloklamadan işlemesini sağlar. Her yeni bağlantı için ayrı bir HandleClientAsync görevi başlatılır, bu da sunucunun responsif kalmasını garanti eder.

Mesaj İşleme ve Yönlendirme Mantığı

Gelen mesajlar BroadcastMessageAsync metodu aracılığıyla diğer bağlı ajanlara iletilir. Gerçek bir senaryoda, bu mesajlar daha karmaşık bir şekilde ayrıştırılacak (örneğin JSON deserializasyonu) ve belirli hedeflere (örneğin, sadece aynı takımın ajanlarına) veya oyun motoruna yönlendirilecektir. Bu aşamada, oyun kurallarına uygunluk kontrolü ve komutların doğrulanması da yapılabilir.

Güvenilirlik ve Hata Yönetimi

Ağ iletişimi doğası gereği hatalara açıktır. try-catch blokları, bağlantı kopmaları, veri bozulmaları veya geçersiz mesajlar gibi durumları ele almak için kritik öneme sahiptir. Sunucu, bir ajanın bağlantısı koptuğunda bunu algılamalı ve _connectedClients listesinden çıkarmalıdır.

BattleTech Ajanlarının Geliştirilmesi

MCP sunucusuna bağlanacak BattleTech ajanları da C# ile geliştirilebilir. Her ajan, bir 'Mech'i veya pilotu temsil eder ve kendi karar alma mantığına sahiptir.

Ajan Mimarisi ve Durum Yönetimi

Her ajan, kendi iç durumunu (örneğin, 'Mech'in mevcut sağlığı, mühimmatı, pozisyonu) yönetir ve sunucudan gelen güncellemelerle bu durumu senkronize eder. Bir ajan sınıfı, sunucuya bağlanma, mesaj gönderme/alma ve LLM'e girdi hazırlama gibi işlevleri içermelidir.

using System.Net.Sockets;
using System.Text;
using System.Text.Json; // JSON serileştirme için

public class BattleTechAgent
{
    private TcpClient _client;
    private NetworkStream _stream;
    public string AgentId { get; private set; }
    private BattleTechGameState _currentGameState; // Ajanın iç oyun durumu

    public BattleTechAgent(string agentId, string serverIp, int serverPort)
    {
        AgentId = agentId;
        _client = new TcpClient();
        _client.Connect(serverIp, serverPort);
        _stream = _client.GetStream();
        Console.WriteLine($"{AgentId} sunucuya bağlandı.");
        _ = ListenForMessagesAsync();
    }

    private async Task ListenForMessagesAsync()
    {
        byte[] buffer = new byte[1024];
        int bytesRead;

        try
        {
            while ((bytesRead = await _stream.ReadAsync(buffer, 0, buffer.Length)) != 0)
            {
                string message = Encoding.UTF8.GetString(buffer, 0, bytesRead);
                Console.WriteLine($"{AgentId} mesaj aldı: {message}");
                ProcessServerMessage(message);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"{AgentId} bağlantısı kesildi veya hata: {ex.Message}");
        }
        finally
        {
            _client.Close();
        }
    }

    private void ProcessServerMessage(string message)
    {
        // Gelen mesajı JSON olarak ayrıştır ve oyun durumunu güncelle
        // Örneğin: _currentGameState = JsonSerializer.Deserialize(message);
        // Ardından LLM'e gönderilecek girdiyi hazırla
        Console.WriteLine($"Ajan {AgentId} oyun durumunu güncelledi.");
        MakeDecisionAndSendAction();
    }

    public async Task SendMessageAsync(string message)
    {
        byte[] data = Encoding.UTF8.GetBytes(message);
        await _stream.WriteAsync(data, 0, data.Length);
    }

    private async void MakeDecisionAndSendAction()
    {
        // Burada LLM'e oyun durumunu gönderme ve yanıtını alma mantığı olacak
        string llmInput = $"Mevcut oyun durumu: {_currentGameState?.ToString()}. Ne yapmalıyım?";
        // LLM'den yanıtı al (örneğin, "Move to X,Y" veya "Fire at Target")
        string llmOutput = await CallLlmApiAsync(llmInput); // Varsayımsal LLM API çağrısı

        // LLM çıktısını BattleTech komutuna dönüştür
        string actionCommand = ParseLlmOutputToAction(llmOutput);

        // Komutu sunucuya gönder
        await SendMessageAsync(actionCommand);
    }

    private Task CallLlmApiAsync(string input)
    {
        // Gerçek bir LLM API çağrısı burada yapılır (örneğin OpenAI API)
        return Task.FromResult("{\"action\": \"Move\", \"target\": {\"X\": 12, \"Y\": 7}}"); // Örnek çıktı
    }

    private string ParseLlmOutputToAction(string llmOutput)
    {
        // LLM çıktısını ayrıştırıp sunucuya gönderilecek BattleTech komutuna dönüştür
        // Örneğin, JSON parse edip uygun bir komut nesnesi oluşturma
        return llmOutput; // Basitçe LLM çıktısını geri döndürüyoruz
    }
}

// Örnek oyun durumu sınıfı (gerçek uygulamada çok daha detaylı olacaktır)
public class BattleTechGameState
{
    public string MechId { get; set; }
    public Position Position { get; set; }
    public int Health { get; set; }
    public string Target { get; set; }
    public List ActionsAvailable { get; set; }

    public override string ToString()
    {
        return JsonSerializer.Serialize(this);
    }
}

public class Position { public int X { get; set; } public int Y { get; set; } }

Sunucu ile İletişim Kurulumu

Ajanlar, TcpClient kullanarak MCP sunucusuna bağlanır. Bağlantı kurulduktan sonra, NetworkStream üzerinden asenkron olarak mesaj gönderip alırlar. Her ajan, kendi ListenForMessagesAsync görevini başlatarak sunucudan gelen güncellemeleri sürekli dinler.

Oyun Durumu Parselleme ve Karar Alma Öncesi İşlemler

Sunucudan gelen mesajlar, ajanın iç oyun durumunu güncellemek için ayrıştırılır. Bu, genellikle JSON deserializasyonu ile yapılır. Güncellenen oyun durumu, LLM'e gönderilmeden önce belirli bir formata dönüştürülür. Bu format, LLM'in oyunun mevcut durumunu ve olası eylemleri anlamasına yardımcı olacak şekilde tasarlanmalıdır.

LLM Entegrasyonu ve Karar Alma Mekanizmaları

Bu sistemin kalbinde, LLM'lerin BattleTech'in karmaşık kuralları ve stratejileri dahilinde karar alma yeteneği yatar.

LLM'e Giriş Olarak Oyun Durumu

LLM'ler metin tabanlı girdilerle çalıştığı için, oyunun mevcut durumu (harita bilgisi, 'Mech'lerin konumu, hasar durumları, hedefler vb.) doğal dil veya yapılandırılmış metin (örneğin, JSON içinde açıklayıcı metin) olarak LLM'e sunulmalıdır. İyi tasarlanmış bir prompt (istem), LLM'in durumu doğru bir şekilde yorumlaması ve bağlamı anlaması için kritik öneme sahiptir.

Örnek Prompt Yapısı:

Oyun Durumu:
- Kendi Mech'im (Alpha): Konum (10,5), Sağlık %85, Mühimmat: LRM-10 (10/10), Medium Laser (Sınırsız).
- Düşman Mech'i (Bravo): Konum (12,7), Sağlık %60, Görüldü.
- Arazi: Benim Mech'im bir tepenin arkasında kısmi siperde.
- Hedef: Bravo'yu yok et.
- Mevcut Tur: 3.
- Kullanılabilir Eylemler: [Hareket Et, Ateş Et, Siper Al]

Mevcut duruma göre en iyi stratejik hamle nedir? Yanıtını JSON formatında ver: {"action": "EylemTipi", "target": "HedefBilgisi", "details": "EkAçıklama"}.

LLM Çıktısının Yorumlanması ve Eyleme Dönüştürülmesi

LLM'den gelen yanıt da metin tabanlı olacaktır. Bu yanıtın, oyun motorunun anlayabileceği belirli bir BattleTech komutuna dönüştürülmesi gerekir. JSON formatında bir çıktı istemek, bu ayrıştırma sürecini kolaylaştırır. Örneğin, LLM "Move to (12,7) and fire LRM-10 at Bravo" şeklinde bir yanıt verebilir. Bu, ajanın kodunda parse edilerek uygun sunucu mesajlarına dönüştürülür.

Stratejik Düşünme ve Taktiksel Uygulama

LLM'ler, geniş veri setleri üzerinde eğitildikleri için karmaşık stratejileri ve taktikleri "öğrenme" potansiyeline sahiptir. Prompt mühendisliği ile, LLM'e sadece anlık bir karar değil, aynı zamanda uzun vadeli bir stratejinin parçası olan taktiksel bir hamle yapması talimatı verilebilir. Örneğin, "Düşmanın zayıf tarafına geçmek için hareket et" gibi bir talimat, LLM'in birden fazla turu kapsayan bir plan yapmasına olanak tanır.

Sunucu ve Ajanların Test Edilmesi ve Optimizasyonu

Herhangi bir yazılım sistemi gibi, MCP sunucusu ve ajanları da güvenilirlik ve performans sağlamak için kapsamlı test ve optimizasyona ihtiyaç duyar.

Birim ve Entegrasyon Testleri

Birim testleri, sunucunun ve ajanların her bir bileşeninin (örneğin, mesaj serileştirme/deserileştirme, bağlantı yönetimi) beklendiği gibi çalıştığından emin olmak için yazılmalıdır. Entegrasyon testleri ise, sunucu ve ajanların bir araya geldiğinde doğru bir şekilde iletişim kurduğunu ve oyun mantığını işlediğini doğrular. Sanal ajanlar veya simülatörler kullanılarak çoklu ajan senaryoları test edilebilir.

Performans ve Ölçeklenebilirlik

BattleTech gibi gerçek zamanlıya yakın oyunlarda, iletişim gecikmesi kritik olabilir. Sunucunun ve ajanların mesajları ne kadar hızlı işlediği, oyun deneyimini doğrudan etkiler. Performans testleri, sunucunun belirli bir ajan sayısıyla ve mesaj yüküyle başa çıkıp çıkamadığını ölçmelidir. Asenkron programlama ve verimli veri yapıları kullanmak, ölçeklenebilirliği artırır.

Hata Ayıklama ve Geliştirme İpuçları

Dağıtık sistemlerde hata ayıklama zorlayıcı olabilir. Kapsamlı loglama, ajanlar ve sunucu arasındaki mesaj akışını izlemek için hayati öneme sahiptir. Özel hata ayıklama araçları veya görselleştiriciler, ajanların durumunu ve etkileşimlerini anlamak için kullanılabilir. Ayrıca, LLM'den gelen yanıtları analiz etmek ve prompt'ları sürekli olarak iyileştirmek, ajanların karar alma kalitesini artıracaktır.

Sonuç

Bu makalede, LLM'lere BattleTech gibi karmaşık strateji oyunlarını öğretme serimizin ikinci bölümünde, C# ile bir Çoklu Ajan İletişim Protokolü (MCP) sunucusu ve ajanları nasıl inşa edeceğimizi detaylı bir şekilde ele aldık. Geliştirdiğimiz bu dağıtık mimari, LLM tabanlı ajanların oyun ortamıyla etkileşim kurmasını, stratejik kararlar almasını ve BattleTech'in dinamik dünyasında başarılı olmasını sağlayacak temel altyapıyı sunmaktadır. Bu sağlam temel üzerine inşa edeceğimiz gelecek çalışmalar, yapay zeka ve oyun entegrasyonu alanında yeni ufuklar açmaya devam edecektir. Bir sonraki bölümde, bu ajanları BattleTech oyun motoruyla nasıl entegre edeceğimizi ve LLM'lerin oyun içi performansı optimize etmek için nasıl eğitileceğini inceleyeceğiz.

SSS (Sık Sorulan Sorular)

S1: Neden C# tercih edildi?

C#, .NET ekosisteminin sağladığı güçlü ağ programlama yetenekleri (TcpListener, TcpClient), asenkron programlama desteği (async/await) ve genel performans avantajları nedeniyle bu tür dağıtık sistemler için mükemmel bir seçimdir. Ayrıca, geniş kütüphane desteği ve geliştirici dostu yapısı, hızlı prototipleme ve sağlam uygulamalar geliştirmeyi kolaylaştırır.

S2: MCP sunucusu ne tür mesajları işler?

MCP sunucusu genellikle oyun durumu güncellemeleri (örneğin, 'Mech' pozisyonları, hasar raporları), ajanlardan gelen komutlar (örneğin, "hareket et", "ateş et"), sorgulamalar (örneğin, "hedefteki düşman bilgisi") ve sistem mesajları (örneğin, "ajan bağlandı", "hata") gibi çeşitli mesaj tiplerini işler. Bu mesajlar genellikle JSON gibi yapılandırılmış bir formatta gönderilir.

S3: LLM'ler oyun durumunu nasıl anlar?

LLM'ler, oyun durumunu metin tabanlı girdiler (prompt'lar) aracılığıyla anlar. Bu prompt'lar, oyunun mevcut durumunu, ajanların konumlarını, düşman bilgilerini, arazi özelliklerini ve mevcut hedefleri doğal dil veya yapılandırılmış metin formatında açıklar. İyi tasarlanmış prompt'lar, LLM'in bağlamı doğru bir şekilde kavramasını ve stratejik kararlar almasını sağlar.

S4: Bu sistem başka oyunlara uyarlanabilir mi?

Evet, bu çoklu ajan ve MCP sunucu mimarisi, prensipte BattleTech dışındaki diğer strateji veya simülasyon oyunlarına da uyarlanabilir. Temel iletişim protokolü ve ajan yapısı benzer kalırken, oyun motoruyla entegrasyon katmanı ve LLM'e gönderilen prompt'ların içeriği oyunun kurallarına ve dinamiklerine göre özelleştirilmesi gerekir.

S5: Performans sorunları nasıl ele alınır?

Performans sorunlarını ele almak için birkaç strateji kullanılabilir: asenkron programlama (async/await) kullanarak sunucunun bloklanmadan birden fazla istemciyi işlemesini sağlamak, verimli veri serileştirme/deserileştirme yöntemleri kullanmak (örneğin, System.Text.Json), ağ trafiğini optimize etmek için mesaj boyutlarını minimize etmek ve sunucuyu daha güçlü donanım üzerinde çalıştırmak. Ayrıca, LLM çağrılarının gecikmesini azaltmak için önbellekleme veya yerel, daha küçük modeller kullanma gibi stratejiler de düşünülebilir.

Yorumlar
İçeriği beğendiniz mi? Bir tartışma başlatın veya görüşlerinizi paylaşın.
Yorum Yaz

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

Gönder

E-posta Bülteni
Yazılım Topluluğuna Katılın
En son güncellemeleri, yaratıcı ipuçlarını ve özel kaynakları doğrudan e-posta kutunuza alın. Tasarım ve inovasyonun geleceğini birlikte keşfedelim.
Exit mobile version