- Son dönemde yapay zeka ajanlarının benimsenmesi artarken, Go dili tabanlı hibrit yığınların kullanımı da yükselişte
- Ajanlar uzun çalışma süresi, yüksek maliyet ve sık görülen giriş/çıkış beklemesi gibi özelliklere sahip
- Go; hafif goroutine'ler, merkezi iptal mekanizması, kanal tabanlı mesajlaşma gibi yüksek performanslı bir eşzamanlılık modeli sunar
- Standart kütüphanesi geniştir ve profilleme aracı
pprof ile bellek ve thread sızıntılarını izlemek kolaydır
- Ancak Go'nun makine öğrenimi ekosisteminin zayıf olması, zirve performansının çok etkileyici olmaması ve diğer dillere kıyasla daha sınırlı üçüncü taraf desteği gibi kısıtları da vardır
Ajan nedir?
- Ajan, tekrar eden bir döngü içinde çalışan ve bir sonraki yürütme adımına kendi başına karar verebilen bir süreçtir
- Workflow'lardaki gibi önceden tanımlı bir rota yerine, koşullara (ör. “test geçti”) veya azami yineleme sayısına göre sona erip ermeye karar verir
- Gerçek hizmet ortamlarında ajanlar birkaç saniyeden birkaç saate kadar uzun süre çalışır ve LLM çağrıları, tarayıcı kontrolü gibi işlemler nedeniyle maliyetlidir
- Kullanıcının girdisini (veya başka bir ajanın girdisini) işlemesi gerektiğinden, giriş/çıkış (I/O) bekleme süresi yüksektir
Go dili neden ajanlar için uygundur?
Yüksek performanslı eşzamanlılık
- Go'nun goroutine yapısı yalnızca 2KB bellekle binlerce, hatta on binlerce hafif thread'i aynı anda çalıştırabilir
- Her goroutine çok çekirdeği kullanarak paralel işleme yapar; bu sayede I/O ve bekleme durumundaki ajanlar da rahatça çalıştırılabilir
- Kanal (Channel) tabanlı iletişim sayesinde bellek paylaşımı yerine mesaj aktarımıyla senkronizasyon sağlanır (Mutex kullanımı en aza iner)
- Ajanların asenkron biçimde mesaj alışverişi yaparak durum yönetmesi için uygundur
Merkezi iptal mekanizması
- Go'da context.Context kullanıldığında, çoğu kütüphane ve API iptal sinyalini desteklediği için çalışmayı durdurmak son derece kolaydır
- Node.js veya Python'da farklı iptal kalıpları bir arada bulunurken, Go tutarlı bir yaklaşımla güvenli iptal ve kaynak geri kazanımı sağlar
Zengin standart kütüphane
- Go'nun standart kütüphanesi oldukça geniştir; HTTP/web, dosya, ağ I/O'su gibi neredeyse tüm alanları kapsar
- Tüm I/O işlemleri goroutine içinde bloklayıcı çalışma varsayımıyla ele alındığından, iş mantığı doğrusal (straight-line) biçimde yazılabilir
- Python'da asyncio, threading, process gibi farklı eşzamanlılık kalıplarının bir arada bulunması karmaşıklık yaratır
Profilleme ve tanılama araçları
- Go'nun pprof gibi yerleşik araçlarıyla bellek sızıntıları ve goroutine (thread) sızıntıları gerçek zamanlı olarak izlenebilir
- Uzun süreli ve eşzamanlı çalışan ajanlarda ortaya çıkabilecek sızıntı sorunlarını teşhis etmede güçlüdür
LLM destekli kod yazımına uygunluk
- Go, basit sözdizimi ve zengin standart kütüphanesi sayesinde LLM'lerin Go'ya özgü stil ile kod yazmasını kolaylaştırır
- Framework bağımlılığı düşük olduğundan, LLM'nin sürümler veya kalıplar konusunda daha az endişelenmesi gerekir
Go'nun sınırlamaları
- Üçüncü taraf kütüphane ve ekosistem bakımından Python ve TypeScript'in gerisindedir
- Makine öğrenimini doğrudan uygulamak için uygun değildir (performans ve destek sınırlıdır)
- En yüksek performansın gerektiği durumlarda Rust ve C++ daha iyidir
- Hata yönetimi konusunda esnek davranan geliştiriciler için biraz rahatsız edici olabilir
2 yorum
Java'dansa Go, Go'dansa Rust :)
Hacker News görüşleri
Çoğu ajan sisteminde en büyük gecikme unsurunun sonuçta LLM çağrıları olduğu vurgulanıyor. Yazıda anılan avantajların belirli bir dil lehine olmadığı; çoğunlukla uzun bekleme süreleri, pahalı kaynak kullanımı, kullanıcıdan veya başka ajanlardan gelen girdiler ve yüksek I/O bekleme süreleriyle ilgili olduğu söyleniyor. Bu özellikler nedeniyle sunucu çalışma hızı ya da verimliliğinden çok, Python gibi dillerin sunduğu geniş yapay zeka kütüphanesi ekosistemi ve desteğinin daha önemli bir avantaj olduğu savunuluyor. Python’da
asyncioya da çoklu iş parçacığı kütüphanelerini dert etmek gerektiği yönünde eleştiriler olsa da, pratikte ajan geliştirme o kadar zor değil ve birileri zaten ilgili iş akışlarını geliştirmiş olduğundan başlamak kolay deniyorGo ile ajan kurarken eşzamanlılık ve backpressure yönetimi kalıplarının iyi oturmuş olmasının büyük avantaj olduğu deneyimlenmiş. Ajanlar çoğunlukla yavaş dış servislerle yapılan işlemler içeriyor ve bu tür işlerde Go’nun eşzamanlılık kalıpları çok faydalı oluyor. Elbette dil çok da önemli değil; en çok JavaScript kullanılıyor gibi görünüyor. Ancak konu kod üretimiyse Go ile LLM kombinasyonunun iyi bir sinerji yarattığı hissediliyor
Go, güçlü eşzamanlılık işleme yeteneği ve kolay dağıtım açısından Python’dan ayrışıyor. Go’da sadece statik binary dağıtmak yeterli olduğundan Python’daki ortam ve bağımlılık sorunlarından kaçınılabiliyor
Ajanlar orkestrasyon katmanı rolü oynuyor ve bu iş için özellikle Go, Erlang ve Node’un uygun olduğu düşünülüyor. Çok büyük AI kütüphaneleri şart değil; yoğun I/O içeren işler alan bazlı araç arayüzlerinin arkasında soyutlanıp gereken dilde alt sistemler kurulabilir deniyor
Go’nun bu tür iş yüklerinde büyük bir avantajı olmadığı, zamanın çoğunun I/O beklemeye gittiği söyleniyor. Go’nun tip sisteminin kısıtlı olduğu ve modern dillerde yerleşik gelen birçok özelliğin Go’da dolaylı yollarla çözüldüğü belirtiliyor. TypeScript, AI için çok iyi bir glue language ve Python’la birlikte kütüphane desteği çok güçlü. Python yerine TypeScript tercih edilmesinin nedeni olarak çok daha güçlü ve olgun bir tip sistemi gösteriliyor. Python’ın da hızla geliştiği ekleniyor. Node.js ve Python’da uzun süre çalışan işleri durdurmanın çok zor olduğu iddiasının sağlam temeli olmadığı düşünülüyor. Çoğu araç bu özelliği zaten destekliyor ve başlıca diller Python ile JS
Elixir ve BEAM tabanlı ajan framework’leri denenmiş; BEAM ile SQLite kombinasyonunun şu an için ajanlar açısından en ideal seçenek olduğu düşünülüyor. Ajanlar uygulamayı yeniden dağıtmadan güvenle değiştirilebiliyor ve BEAM’in eşzamanlılığı bu iş için fazlasıyla yeterli. Durum tabanlı ya da geçici ajanları uygulamak da çok kolay. Gelecekte Python, TypeScript ve Rust ile temel ajanlar kurup, dil tercihlerine göre daha karmaşık ajan geliştirmeyi mümkün kılacak MCP sunucuları da yapılması planlanıyor
Extism projesi ve Elixir SDK öneriliyor. Bu kombinasyonla çekirdek servis, yönlendirme ve mesaj iletimi Elixir ile kurulup BEAM/OTP avantajlarından yararlanılabiliyor; ayrıca başka dillerde yazılmış küçük ve hafif Wasm modülleri biçimindeki ajanlar da eklenti gibi gömülebiliyor
Extism
Elixir SDK
BEAM’in yerleşik veri deposu
mnesiayerine neden SQLite seçildiği merak ediliyormnesia docs
Ajanların zamanının büyük kısmı LLM yanıtını beklemek ve dış servisleri (API, DB) çağırmakla geçiyor. Dil çalışma zamanının performans etkisi gerçekte neredeyse yok. Ajan performansı ve ölçeklenebilirliği için gerçekten önemli bir dil özelliği varsa, bunun JSON serileştirme ve seriden çıkarma performansı olacağı söyleniyor
Bu yüzden JSON’u doğal olarak işleyen TypeScript gibi bir dil kullanmanın daha iyi olduğu düşünülüyor. TypeScript’in tip sistemi Go’dan bile çok daha güçlü
Deneyime göre LLM çağrıları dışında ajanlardaki en maliyetli kısım asenkron düzenleme (
merge,diff,patch) çakışmalarını çözmek. Bu iş düşük seviye kütüphanelere devredilebilse de, serileştirme kadar optimize edilmesi zor bir sorun olarak görülüyorBu ampcode.com ajan geliştirme rehberi akla geliyor. Python, dinamik dil özellikleri sayesinde dekoratörlerle metotları doğrudan araç çağrısına dönüştürmek, araç fonksiyonlarının tekrarından liste üretmek ya da bunları hızla JSON şemasına çevirmek gibi işlerde doğal bir kullanım sunuyor. Buna karşılık birden fazla dış tetikleyicinin (ör. kullanıcı girişi, Gmail e-postası, Slack mesajı vb.) yeni ajan çalıştırmaları başlattığı yapı, Go’nun channel ve
switch/forloop kullanımıyla çok daha sezgisel gelmiş. Python’da ise ayrı ayrı kuyruklar ve thread’ler kurmak gerektiğinden daha karmaşık oluyorYazının mantığı izlenecekse Elixir ajanlar için ideal denebilir
Go’nun sınırlı ve yetersiz tip sistemi neredeyse her uygulama için uygunsuz görülüyor. Hatta Go’nun en büyük dezavantajının dilin kendisi olduğu söyleniyor. Dil dışındaki unsurların Go’yu katlanılabilir kıldığı düşünülüyor
Yıllarca Go ile programlama yapmış biri olarak tip sistemi sorunlarının fazla olduğu görüşüne katılınıyor. LLM alanındaki insanların neredeyse yalnızca Python ya da JavaScript kullandığı gözleniyor. Herkesin daha modern dillere geçmesi gerektiği düşünülse de, Go Python/JavaScript’in dağınık import ve paket sorunlarına kıyasla yine de daha iyi bir seçenek olabilir
Go tip sisteminin sınırlamalarının ajan geliştirmede tam olarak nasıl engel yarattığını daha somut duymak isteyenler var
Aslında Go’ya statik tip sisteminin eklenme nedeni performans hedeflerine ulaşmanın başka yolunu bulamamış olmaları deniyor. Pratikte dilin dinamik tipli bir dil gibi kullanıldığı, bunun da dilin tasarım amacının yanlış anlaşılmasına yol açtığı savunuluyor. Dinamik tipli dillerin genel olarak uygunsuz olduğu söylenebilir ama Python, Erlang, Elixir gibi dillerin aktif biçimde kullanılıyor olması, bu problem alanına dinamik tiplerin daha uygun olabileceğini gösteriyor
Birden çok dönüş değerinin bileşik şekilde çalışmaması, hata desteğinin exception’lardan daha iyi olsa da çok ayrıntılı olması, channel’ların hata yapmaya açık olması ve
enumtiplerinin hayal kırıklığı yaratması eleştiriliyor. Buna rağmen interface’lerin şaşırtıcı derecede iyi çalıştığı ve paketleme sisteminin oldukça akıcı olduğu söyleniyor. Rust öğrenirken dosya yapısının Go’dan çok daha karmaşık olduğu fark edilmiş. Hatta dilin basit olması sayesinde çeşitli linter ve kod üretim araçları oluşturmak da kolay. Uzun vadeli Go kodu bakımı, Python/JS’ye kıyasla daha az kaygı veriyorGo’ya derlenen bir LISP/Scheme lehçesi iyi şekilde sürdürülse gerçekten harika olurdu
Uzun bekleyen ve çalıştırma maliyeti yüksek süreçlerde, süreç ölürse tüm işin kaybolması önemli bir dezavantaj. Bekleme sırasında durumu veritabanına serileştirmek daha güvenli olabilir, ancak bunu kolaylaştıran bir dil olmadığı söyleniyor. Checkpoint tabanlı durum makineleri yazmak kolay değil
Checkpoint tabanlı durum makinelerinin Hatchet(hatchet.run) ve Temporal(temporal.io) gibi platformların sunduğu temel özelliklerden biri olduğu açıklanıyor. Bu platformlar iş akışı içindeki fonksiyon yürütme geçmişini saklıyor ve kesinti olduğunda geçmişi otomatik olarak yeniden oynatıyor. Bellek dökümü yerine çıktı bazlı ilerleme geçmişinin çok daha verimli olduğu savunuluyor. (Hatchet kurucusu)
goroutine, thread ve uzun çalışan zincirler sonuçta atomik iş birimlerine bölünmek ve durum serileştirmesi yapmak zorunda. Bunun hata sonrası toparlanma, hata takibi, sonuçların yeniden referanslanması ve çok düğümlü dağıtım gibi gereksinimleri karşıladığı söyleniyor. Elixir’deki Oban(github.com/oban-bg/oban) framework’ü bu yaklaşımı kullanıyor; ayrıca asenkron işlerin kalıcı hale getirilmesinin önemini anlatan Oban yazısı da öneriliyor. (Oban yazarı)Golang tabanlı bir ajan kütüphanesi geliştirilirken, yeterli log varsa ajan durumunun her zaman geri yüklenebileceği düşünülmüş. Zaman damgaları ve üst çalıştırma (
run) bilgisiyle alt/yan dal çalıştırma ağacı kurulabileceği belirtiliyor. Session yönetimi için map ve DB birlikte kullanılıyor ve gerektiğinde yeniden inşa edilebiliyor. Tek tek nesneleri elde tutmak yerine, stateless nesneler map içindeidile bulunuyor; önceki action, step ve context ise durum nesnesinde tutuluyor. Ajan/iş akışı tutarlılığı da sonuçların hash ile yönetilmesiyle sağlanıyor. Şimdilik yalnızca temel ajanlar ve araçlar uygulanmış; loglama, geri yükleme ve iptal mantığı ise henüz geliştirilmemişTemporal’ın uzun süreçlerde checkpoint alma için oldukça faydalı olduğu ve dilden bağımsız çalıştığı söyleniyor
İş kuyruğu üzerinde düşünen biri, Postgres içinde basit bir kuyruk kurmayı değerlendirdiğini söylüyor. Avantajlar olarak sunucular arasında iş yükü dağıtımı, süreç sonlandıktan sonra görevlerin kaybolmaması ve daha iyi görünürlük sayılıyor. Ancak bunun kod karmaşıklığını ciddi biçimde artırabileceği, bu yüzden mimariyi basit kurmanın zor olduğu hissediliyor
AI mühendislerinin JavaScript kullanmaktan aşırı derecede kaçındığı söyleniyor. TensorFlow for Swift’in iptal edilmesi, AI dillerindeki çeşitliliğin sonu olarak görülüyor
JavaScript’ten kaçınmanın sadece AI mühendislerine özgü olmadığı düşünülüyor. 30 yılı aşkın süredir JS yazmış biri olarak buna katılındığı söyleniyor
JS’nin dil olarak çok kötü olduğu ve backend’e taşınmasının hata olduğu düşünülüyor. TypeScript’in de alttaki JS sorunlarını çözemediği savunuluyor. JS ya da TS kullanmaktan kaçınıp Go, Rust, Python, Ruby, Elixir, F# gibi alternatiflerin tercih edildiği belirtiliyor
JS’nin ajanlar için neden özellikle iyi görüldüğü merak ediliyor
ML alanında daha iyi bir eşzamanlılık modeline ihtiyaç olduğu hissediliyor. Go ile ML denendiğinde kütüphane desteğinin yetersizliği ve dış
gRPCçağrılarına ya da wrapper’lara bağımlılık nedeniyle bunun pratikte neredeyse imkansız olduğu görülmüş. Python’ın sınırları var ve C++ da aşırı ayrıntılı olduğundan üretkenliği düşürüyor