Yapay Zeka Ajanları İçin Asenkron Araç Çağrıları: start() Neden Bloklayan run() Yönteminden Daha İyi?
Kısa cevap: Yapay zekâ ajanları için asenkron araç çağrıları, engelleyici (blocking) tek bir run() işlemini küçük bir sözleşmeye böler: start() anında bir iş tanıtıcısı (job handle) döndürür, status() ilerlemeyi bildirir, stop() işlemi iptal eder ve sonuç, ajanın bir sonraki turunda okuyacağı bir olay (event) olarak geri gelir. Uzun süren işler arka planda çalışırken ajan konuşmaya ve yeni talimatlar almaya devam eder.
Günümüzdeki çoğu ajan bir aracı çağırır ve bekler. 6 dakikalık bir test çalıştırması sırasında ikinci bir soru sorduğunuzda bu soru kuyrukta bekler. Bu durum 200 ms süren bir arama için sorun olmasa da bir dağıtım (deploy) veya web tarama (crawl) işlemi için oldukça can sıkıcıdır.
DeepSeek Harness ekibinin yakın tarihli "Exploring Super-agent Design" makalesi bu çözümü "full-duplex" (çift yönlü eşzamanlı) olarak adlandırıyor: engelleyici run() çağrısını start() ve stop() ile değiştirmek. Bu rehber, ajan döngüsü (agent loop) tarafını ele almaktadır: araç sözleşmesi, sonuçların sisteme nasıl geri aktığı, iptal işlemleri ve her aracın ihtiyaç duyduğu API yapısı. Tek bir yavaş çağrının HTTP tarafı hakkında bilgi edinmek için AI Agents and Long-Running API Calls: Polling vs Webhooks başlıklı yazıyı okuyabilirsiniz.
Bir ajan döngüsünde asenkron araç çağrıları nedir?
Asenkron bir araç çağrısı, sonuç yerine bir tanıtıcı (handle) döndüren bir araç çağrımıdır. Ajan döngüsü tanıtıcıyı kaydeder, sırasını tamamlar ve kullanıcı için boşta kalır. İş bittiğinde çalışma zamanı (runtime) konuşmaya bir tamamlanma olayı ekler ve model bunu bir sonraki turunda tıpkı diğer mesajlar gibi okur.
Aradaki fark kimin beklediğidir: run() ile model bekler, start() ile ise çalışma zamanı bekler.
Engelleyici run() | Asenkron start() | |
|---|---|---|
| Döndürülen değer | Nihai sonuç | İş kimliği (job id), "Başlatıldı" |
| İşlem sırasında ajan | Donmuş / kilitli | Konuşuyor, planlama yapıyor, yeni işler başlatıyor |
| Yeni kullanıcı mesajı | Araç yanıtı dönene kadar kuyrukta bekletilir | Anında işlenir |
| İptal | Tüm turu sonlandırır | stop(job_id) |
DeepSeek makalesi bunu doğrudan kullanıma sunulmuş hazır bir ayar olarak değil, bir mimari olarak tanımlıyor. Full-duplex yapısının DeepSeek Harness içinde uygulandığını ancak varsayılan olarak etkinleştirilmediğini ve bazı parçalarının yazarların resmi bir DeepSeek ürünü olmadığını belirttiği dsh-superagent-prototype adlı bir prototip eklentide yer aldığını ifade ediyor. Bunu örnek alınacak bir tasarım şablonu olarak değerlendirebilirsiniz. Arka plan bilgisi için DeepSeek Harness nedir başlıklı yazıya ve tamamlayıcı nitelikteki süper ajan nasıl inşa edilir rehberine göz atabilirsiniz.
Engelleyici çağrı sorunu: Yavaş çalışan tek bir araç ajanı kilitler
Test paketini çalıştırması (5 dakika) ve hatalı bir içe aktarma (import) hakkında bir soruyu yanıtlaması istenen bir kodlama ajanı hayal edin. Engelleyici çağrılarda, sorunuz testlerle hiçbir ilgisi olmamasına rağmen testlerin arkasında bekler. Bu durumda üç temel sorun ortaya çıkar:
- Gecikmeler üst üste biner. Yavaş çalışan her araç, çalışma süresinin tamamını arkasındaki her şeyin bekleme süresine ekler.
- Talimatlar güncelliğini yitirir. İki dakika sonra "aslında e2e testlerini atla" dersiniz; ancak ajan işlem tamamlanana kadar bunu algılayamaz.
- Zaman aşımları sorun yaratır. Ağ geçitleri (gateway) dakikalarca açık tutulan bağlantıları sonlandırır; bu nedenle uzun süren bir
run()işlemi, arka plandaki iş başarılı olsa bile başarısızlıkla sonuçlanabilir.
Makale, hedeflenen bu özelliği "üretken" (productive) olarak tanımlıyor: ajan, önceki iş bitmeden bir sonraki talimatı alabilir. Bunu sağlamanın yolu ise asenkron araçlardan geçer.
start, status, stop: Asenkron araç sözleşmesi
Uzun süren her yetenek için modele tek bir araç vermek yerine, minimal dönüş yapılarına sahip üç araç sağlayın.
{ "name": "start_test_run", "description": "Start the test suite. Returns immediately with a job_id. The result arrives later as a job_completed event; do not wait for it.", "input_schema": { "type": "object", "properties": { "suite": { "type": "string", "enum": ["unit", "e2e", "all"] }, "idempotency_key": { "type": "string" } }, "required": ["suite", "idempotency_key"] } } start_test_run yalnızca {"job_id": "job_8f2", "status": "queued"} döndürür ve başka hiçbir şey içermez. get_job_status(job_id) çağrısı queued, running, done veya failed durumlarının yanı sıra kısa bir ilerleme notu döndürür. stop_job(job_id) ise iptal talebinde bulunur ve ulaşılan durumu bildirir.
Modelin süreci doğru yürütmesini sağlayan iki kural vardır: Açıklamaya "bekleme" (do not wait) ifadesini ekleyin; aksi takdirde model dar bir döngüde sürekli get_job_status sorgusu yapacaktır (polling). Ayrıca start fonksiyonundan asla veri döndürmeyin; aksi takdirde model hangi veri yapısını aldığını tahmin etmek zorunda kalır.
Sonuçlar döngüye nasıl geri döner?
Modelin sürekli sorgu (polling) yapması birincil plan değil, yalnızca bir yedek plan olmalıdır. Daha iyi bir tasarımda çalışma zamanı işleri izler ve konuşmaya yeni bir mesaj olarak tamamlama olayını iletir (push):
[event] job_completed job_id=job_8f2 tool=start_test_run status=done summary: 412 passed, 3 failed (auth/session.test.ts) details: get_job_result(job_8f2) Olay mesajını kısa tutun ve veri yükünün (payload) tamamını ayrı bir getirme (fetch) aracının arkasına yerleştirin; böylece 40.000 satırlık bir günlük (log) asla bağlamı (context) işgal etmez.
Ardından toplu işleme (batching) adımına geçin. DeepSeek makalesi, bir tur sırasında gelen tetikleyicileri toplayıp bunları bir sonraki model çağrısında birleştiren bir yönlendirici (router) tanımlıyor; uzun girdi ve kısa çıktı, ön doldurmaya (prefill) dahil ediliyor. Yaptıkları deneyde, dakikadaki tetikleyici sayısı 1'den 40'a çıktı, ortalama toplu işlem boyutu 1,0'dan 2,8'e yükseldi ve karar başına harcanan süre 6,4 saniyeden 1,6 saniyeye düştü. Bu değerler genel bir karşılaştırma testi (benchmark) değil, makalenin kendi test sonuçlarıdır; ancak üç olayı tek seferde okuyan bir çağrı, her biri tek bir olayı okuyan üç çağrıdan her zaman daha verimlidir. Basit bir kural: Model üretim yaparken olayları ve kullanıcı mesajlarını kuyruğa alın; tur sona erdiğinde bunları geliş sırasına göre birlikte gönderin.
Sıralama, iptal ve tekillik anahtarları (idempotency keys)
Sıralama. İşler herhangi bir sırayla tamamlanabilir. B işi A işine bağlıysa, bağımlılığı açıkça tanımlayın: B'yi yalnızca A'nın tamamlanma olayından sonra başlatın veya API'nin depends_on parametresi kabul etmesini sağlayın.
İptal. stop bir garantiden ziyade bir taleptir. Gerçek nihai durumu döndürün (cancelled veya daha önce bittiyse done) ve modelin bunu dürüstçe raporlamasını sağlayın. MCP'nin Tasks uzantısı da aynı yaklaşımı benimser: belgelerinde iptal işlemini işbirlikçi (cooperative) olarak tanımlar, bu nedenle bir görev cancelled dışında bir nihai duruma da ulaşabilir.
Tekillik anahtarları (Idempotency keys). Modeller yeniden deneme yapabilir; dolayısıyla iletilemeyen bir yanıt ikinci bir start çağrısını tetikleyebilir. Her start çağrısında bir idempotency_key zorunlu kılın ve API'nin aynı anahtarı tekrar gördüğünde mevcut işi döndürmesini sağlayın. Bu anahtar olmadan "veritabanı göçünü çalıştır" komutu iki kez yürütülebilir.
Kısmi sonuçlar. Sürecin sonuna kadar beklemek yerine erken çıktıları (örneğin taranan ilk 50 sayfayı) get_job_result(job_id, cursor) aracılığıyla erişilebilir kılın.
Bağlam büyümesi. Model tamamlanan işler doğrultusunda aksiyon aldıktan sonra bu işleri tek bir satırda özetleyin.
Zaman aşımları. Her işe bir son tarih (deadline) verin ve bu süre aşıldığında job_timed_out uyarısı üretin.
Temeldeki API nasıl görünmelidir?
Asenkron bir araç, yalnızca arkasındaki iş API'si kadar iyidir: işi kabul et, bir kimlik geri döndür ve çağıranın durumu kontrol etmesine izin ver. RFC 9110, 202 Accepted durum kodunu "istek işlenmek üzere kabul edildi ancak işleme henüz tamamlanmadı" şeklinde tanımlar; MDN'in 202 referansı ise bunun pratik kullanımını ele alır.
Bir start() aracı için minimal bir iş API'si:
| Çağrı | Yanıt | Kullanan |
|---|---|---|
POST /jobs (Idempotency-Key başlığı ile) | 202 + {"job_id", "status":"queued"} + Location: /jobs/{id} | start |
GET /jobs/{id} | 200 + queued, running, done veya failed | status, iş izleyici (job watcher) |
GET /jobs/{id}/result | Çıktı ile 200 veya tamamlanmadıysa 409 | Getirme aracı (fetch tool) |
DELETE /jobs/{id} | 202 iptal talebi alındı; sonraki çağrılarda 404 veya 409 | stop |
| İsteğe bağlı geri arama URL'si (callback URL) | Tamamlandığında çağırana POST isteği | İş izleyici (job watcher) |
Çalışma zamanının sorgulama yapmak yerine olayları iletmesini (push) sağlayan unsur bu geri aramadır (callback). İkisi arasında seçim yapmak için desteğe ihtiyaç duyarsanız aralarındaki dengeler webhooks vs polling yazısında, olaya dayalı API tarafı ise AsyncAPI nedir yazısında ele alınmaktadır.
Araçlarınız MCP protokolünü kullanıyorsa, artık bunun için bir standart mevcut. MCP teknik özellikleri (2026-07-28 sürümü), Tasks özelliğini isteğe bağlı bir uzantı olarak listeler: Bir sunucu, tools/call çağrısına bir taskId içeren CreateTaskResult ile yanıt verebilir; istemci tasks/get sorgulaması yapar (veya notifications/tasks bildirimlerini dinler) ve tasks/cancel ile durdurma talebinde bulunur. Durumlar working, input_required, completed, failed ve cancelled şeklindedir. Hem istemcinin hem de sunucunun bunu açıkça desteklemesi gerekir ve ana makine (host) desteği değişkenlik gösterebilir; bu nedenle güvenmeden önce istemcinizi kontrol edin.
Kodlama ajanınızın iş API'sini Apidog CLI ile oluşturmasını ve test etmesini sağlayın
İş API'si, herhangi bir ajan müdahale etmeden önce doğrulayabileceğiniz kısımdır. Tasarımı ve testleri kodlama ajanınıza teslim edin ve Apidog CLI'ı yönetmesini sağlayın. Siz tek bir prompt yazarsınız; ajan ise şartnameyi ve test senaryolarını yazar, ardından bunları çalıştırır.
Kurulum yalnızca üç komut gerektirir:
npm install -g apidog-cli@latest apidog auth login --with-token <YOUR_TOKEN> npx -y skills add https://apidog.com # pick your agent when prompted Ardından ajanınıza tek bir prompt verin:
In Apidog project <projectId>, design the job API a start() tool needs: POST /jobs returns 202 with job_id, GET /jobs/{id} returns queued|running|done|failed, DELETE /jobs/{id} cancels. Create the endpoints, then create test cases that assert: 202 and a job_id on create, a status that reaches done within 60 seconds, the same job_id when the Idempotency-Key repeats, and 409 or 404 on GET result after cancel. Run them against the staging environment <envId> and summarize failures. Ajan, CLI üzerinden her bir yük yapısını okur, doğrular; ardından yazar ve çalıştırır:
apidog cli-schema get endpoint-create apidog cli-schema validate endpoint-create --file post-jobs.json apidog endpoint create --project <projectId> --file post-jobs.json apidog cli-schema get test-case-create apidog cli-schema validate test-case-create --file case-create-202.json apidog test-case create --project <projectId> --file case-create-202.json apidog run --test-case <caseId> --project <projectId> -e <envId> -r cli,json cli raporlayıcısı terminalde her doğrulama (assertion) için başarılı ve başarısız sonuçları yazdırır; json raporu ise ajanın geriye dönük okuyup açıklayabileceği yapılandırılmış bir çıktı sunar. Testler başarıyla geçtikten sonra aynı komutu CI ortamında -r junit ile çalıştırın; Apidog CLI agent workflow rehberi bu döngüyü adım adım anlatır, Apidog CLI in Claude Code ise ajan kurulumunu kapsar. Apidog'un Ücretsiz planı 4 kullanıcıya kadar destek sunar.
Asenkron araçlar ne zaman gereklidir, ne zaman değildir?
Şu durumlarda asenkron araçları tercih edin:
- Bir aracın çalışması düzenli olarak birkaç saniyeden uzun sürüyorsa (derlemeler, test paketleri, web taramaları, render işlemleri, dağıtımlar).
- İşlem sürerken kullanıcılar ajanla iletişim kurmaya devam ediyorsa.
Şu durumlarda engelleyici (blocking) yapıda kalın:
- Çağrı bir veya iki saniyenin altında yanıt veriyorsa.
- Bir sonraki adım zaten sonuç olmadan başlayamıyorsa.
- Arka planda gerçek bir iş API'siyle destekleyemiyorsanız. Arka planda dahili olarak engelleyici çalışan sahte bir asenkron araç, boş yere karmaşıklık getirir.
Pratik bir ayrım: Okuma işlemlerini engelleyici tutun; uzun süren yazma ve hesaplama işlemlerini ise asenkron yapın.
SSS
Asenkron araç çağrıları ile paralel araç çağrıları arasındaki fark nedir? Paralel araç çağrıları tek bir tur içerisinde aynı anda birden fazla aracı çalıştırır ve model yine de hepsinin tamamlanmasını bekler. Asenkron araç çağrıları ise anında yanıt döner ve sonraki turlarda tamamlanır; böylece işlemler devam ederken model iletişim kurmaya devam edebilir.
Asenkron araçlar geliştirmek için MCP'ye ihtiyacım var mı? Hayır. Bir iş kimliği (job id) döndüren herhangi bir araç ve tamamlanma olaylarını sisteme aktaran bir çalışma zamanı yeterli olacaktır. MCP'nin isteğe bağlı Tasks uzantısı, hem istemciniz hem de sunucunuz destekliyorsa tanıtıcı, sorgulama ve iptal çağrılarını standartlaştırır.
Ajan bir işin ne zaman bittiğini nasıl anlar? Bunu çalışma zamanı bildirir. Bir iş izleyici (job watcher), iş API'sini sorgular veya bir geri arama (callback) alır, ardından konuşmaya kısa bir tamamlanma olayı ekler. Model bunu bir sonraki turunda okur.
Kullanıcı işlem devam ederken iptal ederse ne olur? Ajan stop(job_id) çağrısı yapar, API bu talebi kaydeder ve iş gerçek nihai durumunu raporlar. İptal talebi ulaşmadan önce işlem bittiyse ajan durdurulduğunu iddia etmek yerine bunu açıkça belirtmelidir.
DeepSeek'in full-duplex modu doğrudan açabileceğim bir özellik mi? Bir ürün özelliği olarak hayır. Makale, bunun DeepSeek Harness içinde uygulandığını ancak varsayılan olarak kapalı olduğunu ve ilgili eklentinin yazarların resmi bir DeepSeek ürünü olmadığını belirttiği bir prototip olduğunu ifade ediyor. Bunu bir referans tasarım olarak kullanabilirsiniz.


