DevTools'ta Network sekmesini açıp GraphQL kullanan bir sayfanın yüklenmesini izliyorsunuz. İstediğiniz query { ... } ifadesini bulmak için tüm istek gövdelerini tarıyorsunuz ama ortada sorgudan tek kelime yok. Elinizde yalnızca bir operationName, altmış dört karakterlik bir hash ve bir variables paketi var.
Gözden kaçırdığınız bir şey yok. Karşınızdaki yapı persisted operation: istemci artık düz metin sorguyu göndermiyor, yalnızca önceden kaydedilmiş hash'i iletiyor. Sunucu bu hash'i kendi kayıt defterinde buluyor, gerçek sorguyu yeniden oluşturup çalıştırıyor. Paket yakalayarak sorguyu çıkarma yöntemi burada tıkanıyor. Hangi operasyonun çağrıldığını ve hangi değişkenlerle çalıştığını görebilirsiniz; ancak operasyonun seçtiği alanları ya da yanıtın yapısını göremezsiniz.
Bu noktada çoğu kişinin ilk tepkisi yanlış oluyor: hash'i “kırması” gerektiğini düşünüyor. Hash tek yönlüdür, kırılamaz; zaten buna gerek de yoktur. Asıl mesele sınıflandırmadır. Önce hangi senaryoda olduğunuzu belirleyin, ardından nasıl ilerleyeceğinize karar verin. İki yaklaşımın maliyeti bir büyüklük mertebesi kadar farklıdır; yanlış tercihle ciddi emek harcarsınız.
Persisted operation neden sorguyu ağ trafiğinden çıkarır?
Önce bu mekanizmanın neden var olduğunu anlamak gerekir; aksi halde doğru yaklaşımı değerlendiremezsiniz.
Düz metin GraphQL'in sorunu açık: sorgu metni uzun ve hantaldır, her istekte tüm alan ağacını göndermek gereksiz yük yaratır ve sunucunun keyfî sorguları kabul etmesi tüm şemanın saldırı yüzeyini açar. Persisted operation bu iki soruna da yanıt verir. Derleme aşamasında istemcinin kullanacağı her sorgu çıkarılır, hash'lenir ve sunucuda beyaz liste olarak kaydedilir. Çalışma anında istemci yalnızca hash ile değişkenleri gönderir; sunucu sadece kayıtlı hash'leri kabul eder, beyaz listede olmayan tüm sorguları reddeder. Bu, scraping'i engellemek için tasarlanmış kasıtlı bir önlemden ziyade gerçek bir performans tasarımıdır. Apollo'nun Automatic Persisted Queries dokümantasyonu da düz metin sorgu yerine sorgunun SHA-256 değerini kullanmayı önerilen bir pratik olarak anlatır. Yakalamada sorgunun görünmemesi bunun doğal sonucudur.
Reverse engineering açısından etkisi nettir: “ne getirilecek?” bilgisi istekten çıkarılmıştır. Elinizde üç şey kalır: operasyon tanımlayıcısı — hash veya okunabilir bir operationName —, değişken paketi ve yanıt. Operasyonun hangi alanları seçtiğini anlatan ara katman ağ üzerinde değildir.
Gerçek projelerde bu yelpazenin iki ucuyla da karşılaşırsınız. Bir uçta platform persisted yapıya hiç geçmemiştir; düz metin sorgu hâlâ istek gövdesinde açıkça durur. Diğer uçta ise istek, içinde tek bir alan adı bile okuyamadığınız opak bir zarfa dönüşmüştür. Bu iki durum farklı yöntemler gerektirir; aşağıda ayrı ayrı ele alacağız.
Doğru sorguya ulaşmanın maliyetleri çok farklı iki yolu
İlk yol, düz metni veya eşleme tablosunu istemci derlemesinde bulmaktır. İkinci yolsa düz metnin peşine hiç düşmeden operasyonu olduğu gibi bir kara kutu şeklinde tekrar oynatmaktır.
İlk yöntem daha kapsamlı göründüğü için çoğu kişi varsayılan olarak ona yönelir. Emek israfı da tam burada başlar. Bu yöntem ancak düz metin gerçekten istemciye dağıtıldıysa ucuzdur; çoğu durumda bu varsayım geçerli değildir.
Birinci yol: istemci derlemesinde sorguyu veya eşlemeyi bulmak
En düşük maliyetli senaryoda düz metin hiç gizlenmemiştir.
Bir Çin kısa video platformunun hot-rank yapısı buna örnek: tek bir /graphql endpoint'i vardır; istek gövdesi standart {operationName, variables, query} üçlüsünü içerir; query alanında tam GraphQL sorgusu bulunur ve operationName, hotRankQuery gibi okunabilir bir addır. Burada ayrıca “elde edilecek” bir şey yoktur; tek bir yakalama her şeyi önünüze koyar. Platform persisted operation kullanmamıştır ve yelpazenin en kolay ucundadır.
Biraz daha fazla emek isteyen durum, persisted operation kullanıldığı halde eşlemenin istemcide tutulmasıdır. İstemcinin bir hash gönderebilmesi için hangi operasyonun hangi hash'e karşılık geldiğini bilmesi gerekir. Bu operationName-hash tablosu, kimi zaman düz metin sorguyla birlikte, genellikle frontend bundle'ına gömülür. Derleme araçları bunu manifest dosyası olarak üretebilir veya bir modülün içine satır içi yerleştirebilir. Bulduğunuzda hem düz metni hem hash'i aynı anda elde edersiniz; sonrasında alan eklemekte veya selection set'i değiştirmekte özgürsünüzdür.
Zorluk bulma işleminin kendisi değil; derlemenin on binlerce satır uzunluğunda, minify edilmiş ve obfuscate edilmiş olmasıdır. Eşleme parçalanmış veya farklı yerlere satır içi dağılmış da olabilir. Modelin bu yazıdaki asıl değer kattığı nokta burasıdır; aşağıda ayrıca değineceğim. Bu bir muhakeme problemi değil, parçalı retrieval problemidir.
Birinci yolun testi basit: düz metin veya eşleme istemcinin herhangi bir yerindeyse, önce on dakika boyunca onu arayın. Bulursanız bu en güçlü yöntemdir ve endpoint üzerinde tam denetim sağlarsınız.
İkinci yol: sorguyu aramayın, operasyonu kara kutu olarak tekrar oynatın
Çünkü çoğu zaman düz metin istemcide bulunmaz.
Doğru uygulanmış bir persisted operation'da istemcide yalnızca hash kalır; düz metin sorgu sadece sunucunun kayıt defterindedir. Bundle'ı didik didik arayabilirsiniz, yine de bulamazsınız; çünkü o sorgu hiç dağıtılmamıştır. Böyle bir durumda birinci yola yüklenmek, var olmayan bir şeyi aramaktır.
İkinci yol bu alandaki en az değer verilen çözümlerden biridir: düz metne ihtiyacınız yoktur. İhtiyacınız olan sorgunun alan ağacı değil, yanıttır. Bu nedenle operasyon tanımlayıcısını — hash veya operationName — ve değişken zarfını kaydedin; bunları aynen gönderin, yalnızca ilgilendiğiniz giriş parametrelerini değiştirin. Hangi alanların seçildiğini hiç öğrenmeyebilirsiniz ama sunucu onları yine de döndürür. Veri toplama ve izleme işlerinin büyük çoğunluğu için bu yeterlidir.
YouTube'un innertube yapısı bu yaklaşımın klasik örneğidir. Hatta GraphQL bile değildir: youtubei/v1/{player,search,next} biçiminde, kendini tanımlayan sabit bir endpoint seti kullanır. İstek gövdesinde context zarfı — istemci türü ve sürümü — ile parametre paketi bulunur. Kimse YouTube'un iç sorgu grafiğini “yeniden kurmaya” çalışmaz; bu ne mümkün ne de anlamlıdır. Yapılması gereken, güncel sayfa kaynaklarından istemci sürümünü ve context bilgisini bir kez okumak; ardından bu zarfı her istekte aynen taşırken yalnızca videoId ya da arama terimi gibi girdileri değiştirmektir. Operasyonun semantiği baştan sona kara kutu kalır. Kritik bir değerin statik kodda bulunmadığı ve çalışma anı kaynaklarından okunması gerektiği bu durum, ayrıca ele alınan ayrı bir reverse-engineering problem sınıfıdır.
İkinci yolun avantajı, düz metnin istemcide olup olmamasından bağımsız olmasıdır. Hash veya opak zarf fark etmez; onu anlamaya çalışmaz, sadece aslına uygun biçimde yeniden üretirsiniz. Bedeli ise istemcinin zaten gönderdiği isteklerle sınırlı kalmanızdır. İstemcinin hiç istemediği bir alanı istiyorsanız kara kutu tekrar oynatma size bunu veremez.
Tekrar oynatmayı bozan bir durum daha vardır: zarf, her istek için yeniden hesaplanan ve süresi dolan bir imza alanı taşıyabilir. Kara kutu yaklaşımı burada biter; bu alanı ayrıca çözmeniz gerekir. İmzanın hangi algoritma ailesine ait olduğunu tanımak ise başka bir yazının konusudur.
Platform tasarımı hangi yöntemi belirler?
Bu iki gerçek örneği tek tabloda topladığınızda, hangi yaklaşımın neden seçildiği netleşir:
Platform örneği | İstek biçimi | Düz metin istemcide mi? | Doğal yaklaşım | Neden? |
|---|---|---|---|---|
Bir kısa video platformunun hot-rank GraphQL'i |
| Evet, düz metin doğrudan istek gövdesinde | Birinci yol (neredeyse sıfır maliyet) | Persisted operation yok; operationName okunabilir, sorgu düz metin, tek yakalama yeterli |
YouTube innertube | Sabit endpoint'ler + | Bahsedilecek bir düz metin sorgu yok | İkinci yol (kara kutu tekrar oynatma) | GraphQL değil; yeniden oluşturulacak sorgu yok, context zarfını bir kez okuyup aynen taşıyın |
Bu iki uç arasındaki fark tek bir şey söyler: yöntemi siz seçmezsiniz, platformun API tasarımı belirler. İlk platform gücünü başka yerde kurmuştur; düz metnin açıkta olması sorun değildir, kötüye kullanımı başka yollarla sınırlar. Bu nedenle bilgiyi neredeyse zahmetsizce alırsınız. İkincisi ise “ne getirilecek?” bilgisini opak bir zarfa dönüştürmüştür; peşine düşülecek düz metin yoktur, yapılabilecek tek şey tekrar oynatmaktır.
Asıl değerlendirme gerçek persisted GraphQL'in bulunduğu geniş orta bölgede gerekir. Düz metin istemcide olabilir — bundle'a gömülü eşleme, yani birinci yol — veya yalnızca sunucuda bulunabilir; istemcide sadece hash kalmıştır ve ikinci yol gerekir. Başlamadan önce bunu iki uçtan birine yerleştirmeniz gerekir.
Önce şu soruyu sorun: Düz metin sorguya gerçekten ihtiyacınız var mı?
Maliyetteki bir büyüklük mertebesi farkın tamamı bu değerlendirmeye bağlıdır.
Platform gerçekten yalnızca hash'i istemciye gönderiyor ve düz metni sunucuda tutuyorsa, siz de düz metni çıkarmak için birinci yolda ısrar ederseniz günlerce bundle kazabilirsiniz. Sonunda aradığınız şeyin hiç dağıtılmadığını anlarsınız. Bu bir zorluk problemi değil, yön problemi; ne kadar uğraşırsanız uğraşın sonuç satın alamazsınız.
Tersi de geçerlidir: sorguyu değiştirmeniz gerekiyorsa, yani istemcinin hiç istemediği bir alanı talep edecekseniz, ikinci yolun kara kutu tekrar oynatması size yardımcı olamaz. Düz metin için yeniden birinci yola dönersiniz; onu elde edemiyorsanız da takılırsınız.
Dolayısıyla başlanacak soru “sorguyu nasıl elde ederim?” olmamalı. Önce şunu sorun: Düz metin sorguya gerçekten ihtiyacım var mı?
İstemcinin zaten yaptığı bir isteği yeniden üretip yanıtını okumak: İkinci yolu, yani kara kutu tekrar oynatmayı kullanın. En ucuz ve en çok göz ardı edilen seçenektir; düz metin var olsun ya da olmasın çalışır. Varsayılan tercihiniz bu olmalı.
Selection set'i değiştirmek veya istemcinin hiç göndermediği bir sorguyu kurmak: Birinci yol, yani düz metni elde etmek zorunludur. Bunun ucuz olup olmayacağı, istemcinin eşlemeyi dağıtıp dağıtmadığına bağlıdır. Dağıtmadıysa maliyet bir büyüklük mertebesi sıçrar; bunu kabul etmeniz veya sorguyu değiştirmeye gerçekten ihtiyacınız olup olmadığını yeniden düşünmeniz gerekir.
Bu değerlendirmeyi en başa almak, “birinci yola dalıp üç gün sonra aslında ikinci yolun gerektiğini fark etme” türü israfın çoğunu önler. “Yeniden yazmak mı, kara kutuyu kabullenmek mi?” eksenindeki bu kalite kaybı takası purification ladder yazısının konusudur; burada ise yalnızca hangi yöntemi seçeceğinizi belirler.
Eşlemeyi bulmak muhakeme değil, parçalı retrieval işidir
Birinci yolun teknik açıdan zor olan tek adımı, frontend derlemesinin on binlerce satırı içinde operasyon bildirimini ve eşlemeyi bulmaktır. Modelin gerçekten zaman kazandırdığı yer tam burasıdır. Ancak önce bunun ne tür bir görev olduğunu doğru tanımlamak gerekir.
Bu bir muhakeme görevi değildir. Modelin kodun ne hesapladığını anlamasına ihtiyaç duymazsınız. İhtiyacınız olan, geniş bir metin gövdesi içinde şu noktaları bulmasıdır: operationName-hash eşlemesini hangi blok bildiriyor, düz metin sorgu hangi modüle satır içi gömülmüş, context zarfı nerede hazırlanıyor? Bu, parçalı retrieval problemidir. Burada ölçülen şey modelin kendi kendine tartışma yeteneği değil, yeterli bağlamı aynı anda görebilmesi ve doğru noktayı hassas biçimde işaretleyebilmesidir.
Önce mekanik bölme adımını uygulayın: derlemeyi bir script ile modüllere ayırın, indeksleyin, polyfill'leri ve ilgisiz iş modüllerini eleyin. Ortaya çıkan sonucu modele verdiğinizde görev temiz ve basit hale gelir: “Bu bloklarda bildirimi bul.”
Bu akışta dört katman, ihtiyaç duydukları yetenek bakımından net biçimde ayrılır:
Adım | Gereken yetenek | Tercih | model id |
|---|---|---|---|
On binlerce satır içinde eşlemeyi / operasyon bildirimini bulmak | Uzun bağlam; büyük bir derleme parçasını tek seferde okuyup hassas konum gösterebilme | Kimi K3 |
|
Birinci mi ikinci yol mu karar vermek; birkaç örnekten hangi zarf alanlarının değiştiğini çıkarmak | Güçlü muhakeme; yapıyı okuyup takası değerlendirme | Claude Opus 5 |
|
Yüzlerce operasyonu toplu etiketlemek, replay stub'ları üretmek, değişken türlerini doldurmak | Düşük maliyet, yüksek eşzamanlılık | Claude Sonnet 5 |
|
Replay bağlantı kurmadığında farkı okuyup nedeni belirlemek (eksik context alanı mı, hash sürümü mü değişti?) | Orta seviye muhakeme; yanıt farkı üzerinden açıklama yapabilme | GPT-5.6 Sol |
|
İlk katman bu yazının ana konusudur. Bulma adımında model değiştirmek sonucu gözle görülür şekilde değiştirir; çünkü sınırı bağlam penceresidir. Derleme on binlerce satırdır. Kısa bağlamlı model her şeyi sığdıramaz ve kesmek zorunda kalır. Tek bir kesme işlemi eşlemenin bulunduğu bölümü dışarıda bırakabilir; sonrasında modelin “bulamıyorum” demesi arama yapamadığından değil, o kısmı hiç görmediğindendir.
Aradaki farkı sözünüze güvenerek kabul etmeyin, test edin:
Gerçek bir isteği yakalayın; operasyon tanımlayıcısını — operationName veya hash — ve değişkenlerini kaydedin.
Frontend derlemesini bir script ile parçalara ayırın, tanımlayıcıyla birlikte
kimi-k3'e verin ve “Bu operasyonun nerede bildirildiğini, eşleşen düz metin sorguyu veya hash eşlemesini hangi bloğun tuttuğunu bul” deyin.Tek bir şeye bakın: Doğrudan doğru satıra atlıyor mu? İsabet, ıskalama veya yakın ama yanlış bir konum.
Kontrol için aynı girdiyi kısa bağlamlı bir modele verin ve sığdıramadığı için kaçırıp kaçırmadığına bakın. Model seçim ölçütünüz isabet oranı olmalı.
Tek turda şunu görürsünüz: Bu tür görevlerde uzun bağlam “biraz daha iyi” değildir; yapabilmek ile yapamamak arasındaki farktır.
Asıl sorun model değiştirme maliyeti
Üç sağlayıcıdan dört model, üç SDK, üç kimlik doğrulama düzeni, üç hata formatı. Retrieval, değerlendirme, toplu işlem ve neden atfetme için farklı modeller kullanmak istiyorsanız saf yaklaşım üç istemciyi de bağlamaktır. Çoğu kişi maliyeti hesaplayıp buna değmeyeceğine karar verir; tüm süreç boyunca tek modelle devam eder. Ardından uzun bağlamlı retrieval aşamasında derlemeyi sığdıramayan katmanı kullanır ve “model bulamıyor” diye suçlar.
AIReiter bu katmanı sadeleştirir: tek anahtar, OpenAI uyumlu tek arayüz ve arkasında dört katman. Geçiş için istek gövdesindeki model alanını değiştirmeniz yeterlidir.
# Eşlemeyi bul: uzun bağlam katmanı, büyük parçalanmış derlemeyi tek seferde alır
curl https://aireiter.com/api/v1/chat/completions \
-H "Authorization: Bearer $AIREITER_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "kimi-k3",
"messages": [{"role": "user", "content": "<chunked frontend build + the operation identifier to locate>"}]
}'
# Operasyonları toplu etiketleme / replay stub'ları üretme: model alanını değiştirin, geri kalanı aynı
# "model": "claude-sonnet-5"
# Replay neden atfetme:
# "model": "gpt-5.6-sol"
Zaten 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 çağrısını kullanın.
Fiyat tarafında Claude modelleri liste fiyatına göre %30 indirimli, GPT modelleri yarı fiyatına çalışır; Kimi K3 de aynı anahtarla çağrılabilir. Bu akışın maliyeti iki noktada toplanır: birinci yoldaki bulma aşaması; burada her girdide birkaç yüz bin token'lık parçalanmış derleme kimi-k3'e verilir. İkinci nokta ise yüzlerce operasyonu etiketlemek ve replay stub'ları toplu üretmektir; en fazla çağrının yapıldığı bu aşama, %30 indirimle claude-sonnet-5 üzerinde çalışır. İndirim tam olarak çağrı yoğunluğu en yüksek toplu işleme aşamasına denk gelir.
Kayıt olmadan deneyin: önce derlemenin bir parçasını elle verin ve uzun bağlam katmanının eşlemeyi tek geçişte bulup bulmadığını görün; ardından entegrasyon yapmaya karar verin.
Sonuç
Dokümantasyonu olmayan bir GraphQL API, onunla entegre olamayacağınız anlamına gelmez. Persisted operation yalnızca “ne getirilecek?” bilgisini istekten iki olası yere taşımıştır: istemci derlemesine — bulun, birinci yol — veya yalnızca sunucuya — düz metni aramayın, operasyonu kara kutu olarak tekrar oynatın, ikinci yol.
Bu iki yolun maliyeti bir büyüklük mertebesi farklıdır. Hangisinin doğru olduğunu “hangisi daha kapsamlı?” sorusu değil, daha önce yanıtlanması gereken iki soru belirler: Düz metin istemcide mi ve sorguyu değiştirmeniz gerekiyor mu? Başlamadan bu ikisini yanıtlamak, emeğin büyük bölümünü boşa harcamayı önler.
Modelin buradaki rolü özeldir: birinci yolda “on binlerce satır içindeki bildirimi bulma” adımı tamamen retrieval işidir. Uzun bağlamlı katman tümünü tek geçişte okuyup doğru noktayı gösterebilir; günler sürebilecek kazıma işini dakikalara indirir. Hangi yolu seçmeniz gerektiğine sizin yerinize karar vermez; bu yazıyı okuduktan sonra o değerlendirmeyi siz yapmalısınız. Model yalnızca eşlemeyi bulmanın zahmetli kısmını üstlenir.