AIREITER

22 Platform, 241 Komut: Neden Birleşik Bir Yanıt Modeli Kurmadım?

Son Güncelleme: 2026-07-31 06:22:36

Yirmiyi aşkın platformdan herkese açık veri çekecekseniz, ilk tasarım kararı çoğu zaman bellidir: tek bir Post, tek bir User tanımlayıp her platformun yanıtını bu modellere eşlemek. Sonuçta bilibili videosu, tiktok videosu, zhihu yanıtı ve linkedin gönderisi ilk bakışta aynı şeye benzer: içerik ve yazarı. İlk üç platformda son derece temiz görünen bu soyutlama, yirminci platforma geldiğinizde sizi kendi ağırlığı altında bırakır.

Ben sonunda birleşik bir model kurmadım. Yirmiyi aşkın platform ve iki yüzü aşkın komut boyunca ayakta kalan yaklaşım, ilk bakışta daha basit görünen şu ayrımdı: her platform kendi işine baksın.

Birleşik model nerede ve nasıl bozuluyor?

Bu çöküş bir anda yaşanmıyor. Sekizinci platform civarında Post modeliniz, isteğe bağlı alanlarla şişmeye başlıyor: kimi platformda danmaku sayısı var, kiminde yok; kimi platformda yayın zamanı saniye hassasiyetinde bir zaman damgasıyken, diğerinde "3 gün önce" gibi bir metin. Yirmiyi aşkın platformda model tamamen işlevini yitiriyor. Üstelik sorun bir derleme hatası değil; katman artık size zaman kazandırmıyor. Aşağı akıştaki her kod parçası önce "bu platform bu alanı gerçekten dolduruyor mu?" diye kontrol etmek zorunda kalıyor. Bu karar mantığı, ham yanıtı doğrudan okumaktan daha uzun sürüyor; birleşik katman ise işi kolaylaştırmak yerine etrafından dolaştığınız bir engele dönüşüyor. Yazma tarafında da aynı bedel var: Eklediğiniz her yeni platform, eski platformlara göre şekillenmiş kutulara yeni alanlar sıkıştırmak için sizi tekrar bu modele döndürüyor.

Her platform kendi bounded context'i olmalı

Kalıcı olan ayrım bunun tersi: birleşik bir model soyutlamayın, her platform kendi bağlamını yönetsin. Katalogda her platform, başka kimseye devretmediği dört sorumluluğa sahip bir <platform>_reverse/ context'i:

  • Girdi doğrulama. Bu platformdaki kimliklerin biçimini ve hangi parametre kombinasyonlarının geçerli olduğunu yalnızca platformun kendisi bilir.

  • Protokol. Doğrudan HTTP mi kullanılacak, yerel JavaScript imzalama mantığının bir parçası mı çalışacak; hangi alan adı ve hangi başlıklar gerekiyor? Bunların tamamı platforma özeldir.

  • İmzalama. Platformların imzalama mekanizmaları büyük farklılık gösterir. Hepsini ortak bir imzalayıcıda toplamaya çalışmak, if-else zincirleriyle dolu bir canavar üretir.

  • Yanıt normalizasyonu. Ham yanıtı, platformun kendi sahip olduğu bir yapıya dönüştürün; küresel ve birleşik bir modele değil.

En kolay yanlış anlaşılan madde dördüncüsü. "Birleşik model yok" demek, "normalizasyon yok" demek değil. Elbette her platform kendi yanıtını normalize eder; fark, hedef şemanın ortak bir model tarafından dayatılmaması, platformun kendisi tarafından tanımlanmasıdır. Birleştirme ancak gerçekten aynı nesneden söz ettiğiniz yerde anlamlıdır. Örneğin aynı platformdaki iki endpoint aynı gönderi yapısını paylaşıyorsa, bu geçerli bir ortaklaştırmadır; çünkü ortada gerçekten aynı domain nesnesi vardır. Hata, platform içindeki bu ortaklığı platformlar arasına taşımaktır.

Ortak katmana yalnızca gerçekten ortak olanlar girsin

Peki ortak katmanda ne olmalı? Platformdan platforma aynı davranan, gerçekten platformlar arası yetenekler; yalnızca yüzeyde benzer görünenler değil. Benim ortak katmanımda yalnızca üç şey var:

  1. Arayüz okuma modeli: Her platformun argparse tanımlarından birleşik bir yetenek kataloğu çıkarılıyor. Birleştirilen şey komutların ne döndürdüğü değil, nasıl keşfedildiği ve tanımlandığı. İlki gerçek bir platformlar arası ortaklık; ikincisi platforma özel. ("Tanım arayüzdür" fikrini arayüz olarak kod yazısı daha ayrıntılı açıklıyor.)

  2. Yerel loopback taşıma: Kimlik doğrulamalı istekler, tüm platformlara aynı şekilde davranan ve hiçbir platformun iş alanına dokunmayan yerel bir WebSocket oturum servisinden geçiyor.

  3. Yönlendirme giriş noktası: Platformu bulur, komutu o platformun context'ine teslim eder ve burada durur.

Test basit: Ortak katmana girecek bir şey, her platformda gerçekten aynı şekilde çalışmalı. Taşıma, yönlendirme ve arayüz tanımlarının üretilme biçimi her platformda aynıdır. Buna karşılık bilibili'deki "bir içerik" ile linkedin'deki "bir içerik" aynı davranmaz; dolayısıyla ortak katmana ait değildir. Soyutlamanın en büyük tuzağı "benziyor" hissidir. İki video birbirine benzer, bu yüzden onları birleştirmek istersiniz. Ama yüzeysel benzerlik davranışsal eşdeğerlik değildir; bunu paylaşılabilir bir domain modeli saymak, birleşik modelin çöküşünün asıl nedenidir.

Komut dağılımı, soyutlamanın nerede işe yaradığını gösteriyor

Birleşik model konusunda hâlâ kararsızsanız, gerçek komut dağılımına bakmak yeterli. 22 platform ve 241 komut var; ancak dağılım son derece dengesiz:

Platform

Komutlar

tiktok

34

bilibili

26

linkedin

18

zhihu

18

douyin

17

xiaohongshu

16

Diğer 16 platform

Her biri 1 ila 13

İlk altı platform toplam 129 komuta sahip; yani tüm komutların yarısından fazlası burada. Kalan yarı ise 16 uzun kuyruk platforma yayılıyor. Bunların çoğunda yalnızca iki ya da üç komut, bazılarında ise tek bir komut bulunuyor.

Bu dağılım, soyutlamanın ekonomisini netleştiriyor: birleşik modelin maliyeti sabittir. Her entegrasyonu yapan kişi alanları doldurmak, null kontrolleri eklemek ve modelin etrafından dolaşmak zorundadır. Buna karşılık fayda, platform başına dağıtılır. İki ya da üç komutu olan uzun kuyruklu bir platform için soyutlamanın getirisi negatiftir; onu birleşik modele uydurmak üzere yazdığınız adaptör kodu, platformun tüm iş mantığından daha uzun sürer.

Tek bir uygulama için soyutlama ayırmayın

Bu dağılımın doğal sonucu bir başka kural: Ortada tek bir uygulama varsa, ileride belki ikinci bir uygulama çıkar diye repository, factory ya da interface katmanı eklemeyin. Yeni bir platform eklemek, yalnızca bir <platform>_reverse/ context'i eklemek olmalı; önce ortak bir base class'a dokunmanız gerekmemeli.

Bir interface katmanının değeri, birden fazla uygulamayı değiştirilebilir kılmasından gelir. Tek uygulamada değeri sıfırken bakım maliyeti pozitiftir. Var olmayan ikinci bir uygulama için yer ayırmakla, var olmayan platformlar arası ortaklık için yer ayırmak aynı hatadır. Diller arası geçiş de bunu yeniden gösterdi: Eski registry'deki birkaç yüz komutun bir bölümü açıkça taşınmadan bırakıldı; onlar için stub ya da uyumluluk proxy'si de yazılmadı. Çünkü boş bir kabuk, eksikten daha maliyetlidir; sonraki kişiye orada bir şey varmış izlenimi verir. Önceden ayrılmış soyutlama da aynıdır.

Platformlar arası normalizasyonda modele de platform bağlamını verin

"Platform bazında ayrım, birleşik model yok" yaklaşımı, normalizasyon için bir model kullandığınızda da aynen geçerli. Yirmiyi aşkın platformun ham yanıtını analiz edilebilir bir yapıya dönüştürmek için bunu bir modele vermek doğal. Buradaki en kolay hata ise kod katmanındakiyle aynı: birleşik bir şema tanımlayıp her platformun ham JSON'unu "bunu bu şemaya eşle" talimatıyla modele göndermek. Bu yaklaşım çalışmaz. Model, bilibili'deki izlenme sayısı alanıyla tiktok'taki izlenme sayısı alanının gerçekten aynı anlama gelip gelmediğini bilemez. En küçük ortak paydaya zorladığınızda da ya platformun ihtiyaç duyduğu bir alanı atar ya da onu yarım yamalak doldurur.

Doğru yöntem, platforma özel bağlam vermektir: Modele "bu bilibili, bu alanların anlamı şu, bu platform için istediğim çıktı yapısı bu" deyin. Her platformu kendi içinde normalize edin; platformlar arası birleştirmeyi analiz katmanına bırakın. Süreç, modelden farklı beceriler isteyen birkaç adımdan oluşuyor:

Adım

Gerekli yetenek

Tercih

model id

Tek bir platformun tüm ham yanıt yapısını okumak

Uzun bağlam; tam yanıtı ve alan notlarını tek seferde işleyebilme

Kimi K3

kimi-k3

Normalizasyon sınırını belirlemek: Hangi alanlar gerçekten platformlar arası, hangileri platforma özgü?

Güçlü muhakeme; aşırı birleştirmeye direnç

Claude Opus 5

claude-opus-5

Platform başına alanları toplu çıkarmak, öğe öğe eşlemek

Uygun maliyet; yüksek eşzamanlılıkta yüzlerce ila binlerce çağrı

Claude Sonnet 5

claude-sonnet-5

İki platformdaki aynı adlı alanların neden örtüşmediğini açıklamak

Orta seviye muhakeme; alanlar üzerinden farkları açıklayabilme

GPT-5.6 Sol

gpt-5.6-sol

Model değiştirdiğinizde sonucun gözle görülür biçimde farklılaştığı tek yer ikinci adım. Burada asıl sınanan şey, iki alanın aslında aynı olmadığını kabul edip etmeyeceğiniz. Bu, algoritma ailesi tespitindeki karşı kanıt bölümünde olduğu gibi işler: Zayıf bir model, "birleştir" ipucunuzu takip eder; güçlü bir model ise sınırı işaret eder.

Asıl sorun model değiştirme maliyeti

Dört katman, üç farklı sağlayıcı, üç SDK, üç kimlik doğrulama yöntemi ve üç hata formatı demek. Adımlar arasında model değiştirmek için istemcinizi üç kez yeniden yazmak mantıklı değil. Bu nedenle çoğu kişi tüm süreci tek bir katmanla yürütüyor; çoğu zaman da "sınırı belirleme" adımında yalnızca düzleştiren bir katman kullanıyor. Sonuçta kurulan şema, yirmiyi aşkın platformda yeniden çöküyor.

AIReiter bu katmanı sadeleştiriyor: Tek anahtar, OpenAI uyumlu tek arayüz ve arkasında dört katmanın tamamı. Geçiş için istek gövdesindeki model alanını değiştirmeniz yeterli.

# Set the normalization boundary: the reasoning tier
curl https://aireiter.com/api/v1/chat/completions \
  -H "Authorization: Bearer $AIREITER_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-opus-5",
    "messages": [{"role": "user", "content": "<one platform response sample + have it mark which fields are platform-specific>"}]
  }'

# Extract fields per platform in bulk: change the model field, leave the rest
#   "model": "claude-sonnet-5"
# Field-difference attribution:
#   "model": "gpt-5.6-sol"

Halihazırda OpenAI SDK kullanıyorsanız, base_url değerini https://aireiter.com/api/v1 olarak ayarlayın; başka hiçbir şeyi değiştirmeniz gerekmez. Anthropic SDK tarafında ise aynı anahtarla POST /api/v1/messages endpoint'ine istek atın.

Fiyat tarafında Claude modelleri liste fiyatına göre %30 indirimli, GPT modelleri yarı fiyatına; Kimi K3 de aynı anahtarla çağrılabiliyor. İndirim, en büyük maliyet kaleminin tam üzerine geliyor: Platform başına toplu alan çıkarma, çağrı yoğunluğu en yüksek adım. Yirmiyi aşkın platformun her birinde yüzlerce ila binlerce kayıt var; kayıt başına bir çağrı yapılıyor ve en uygun fiyatlı Sonnet, buna ek %30 indirimle kullanılıyor. Kimi K3 ile uzun bir yanıtın tamamını okumak ise girdi başına birkaç yüz bin token tüketiyor; bu da ayrı bir maliyet kalemi. Sınırları belirleyen muhakeme katmanında çağrı sayısı düşük olduğundan, maliyeti neredeyse yok denecek kadar az.

  • API anahtarı alın

  • Kayıt olmadan deneyin: Önce tek bir platformun yanıtını elle çalıştırın. Modelin farkları gerçekten işaretleyip işaretlemediğine, yoksa onları hızla düzleştirmeye mi çalıştığına bakın; ardından entegrasyon kararını verin.

Sonuç

Platformlar arası veri toplamada ilk refleks olan birleşik Post/User soyutlaması, küçük ölçekte çok iyi hissettirir; ancak yirmiyi aşkın platformda kaçınılmaz biçimde çöker. Maliyet sabittir, fayda platform başına dağılır ve komut dağılımı çok uzun kuyrukludur. Dayanıklı ayrım, platform başına bir bounded context oluşturmaktır: Her biri kendi girdi doğrulamasına, protokolüne, imzalamasına ve yanıt normalizasyonuna sahip olmalı. Ortak katmanda yalnızca tüm platformlarda gerçekten aynı davranan şeyler yer almalı: taşıma, yönlendirme ve arayüz tanımlarını üretme. Yalnızca birbirine benzeyen bir domain modeli değil. Tek uygulaması olan ya da gerçekte bulunmayan bir ortaklık için de soyutlama ayırmayın. Model kullanımında da kural aynı: Birleşik şema vermek yerine platforma özel bağlamla normalize edin; platformlar arası birleştirmeyi yalnızca analiz katmanında yapın. Dört aşamalı iş akışının tamamı, dört katmanlı ayrımı daha ayrıntılı ele alıyor. Tek bir birleşik arayüz üzerinden bağlandığınızda, model değiştirme maliyeti bu katmanları kullanmamak için bir gerekçe olmaktan çıkıyor.