AIREITER

OpenRouter Structured Output: Şemanız Neden Yok Sayılıyor?

Son Güncelleme: 2026-08-23 01:24:49

Bir OpenRouter modelinde temiz ve tip güvenli çıktı üreten JSON şeması, aynı istek gövdesiyle başka bir modelde farklı alan adları, boş bir string ya da 400 hatası döndürebilir. Reddit kullanıcısı u/MicBeckie, OpenRouter structured outputs üzerinden Qwen modellerini denediğinde "10 denemenin 9'unda sürekli hata aldığını" söylüyor. Aynı kurulumdaki OpenAI modelleri ise şemaya sadık kalmış.

Bu, tek bir hata kaydı açarak çözülebilecek türden bir sorun değil. OpenRouter'da structured output desteği model bazında değil, endpoint bazında belirleniyor. Üstelik “destek” de tek bir anlama gelmiyor: Şemayı üretim aşamasında katı biçimde zorlayan yerel modlardan, şemanızı yalnızca öneri olarak modele ileten sağlayıcılara kadar üç farklı uygulama seviyesi var. Bu rehberde özelliğin nasıl yönlendirildiğini, pratikte görülen altı hata türünü ve şema çıktısını üretime hazır hâle getiren önlemleri ele alıyoruz. Uygulama mekanikleri resmî structured outputs dokümantasyonuna; hata örnekleri ise metin içinde bağlantı verilen geliştirici tartışmalarına dayanıyor.

OpenRouter structured outputs dokümantasyon sayfası

OpenRouter'da structured output desteği ne anlama geliyor?

OpenRouter, type: "json_schema" değerine sahip bir response_format parametresi; şema için bir name, strict bayrağı ve JSON Schema tanımı kabul ediyor. En temel istek şu şekilde görünüyor:

{
  "model": "openai/gpt-4o",
  "messages": [{ "role": "user", "content": "Extract the shipping info" }],
  "response_format": {
    "type": "json_schema",
    "json_schema": {
      "name": "shipping_info",
      "strict": true,
      "schema": {
        "type": "object",
        "properties": {
          "tracking_number": { "type": "string", "description": "Carrier tracking ID" },
          "carrier": { "type": "string" },
          "eta_days": { "type": "number", "description": "Days until delivery" }
        },
        "required": ["tracking_number", "carrier", "eta_days"],
        "additionalProperties": false
      }
    }
  }
}

Resmî dokümandaki iki nokta, bunun çalışıp çalışmayacağını doğrudan belirliyor:

  • Destek modelin değil endpoint'in özelliğidir. Beş sağlayıcı üzerinden sunulan bir modelde structured output yalnızca ikisinde çalışabilir. Model sayfasındaki Providers bölümü, her sağlaycı için structured_outputs parametresini gösterir. Dokümanlar ayrıca “endpoint desteğinin zaman içinde değişebileceği” uyarısını yapıyor.
  • Kapsam dar bir başlangıçtan büyüdü. OpenRouter, structured outputs özelliğini 12 Aralık 2024'te duyurduğunda yalnızca OpenAI 4o ve Fireworks modellerini destekliyordu. Diğer destekler sonradan, sağlayıcı sağlayıcı geldi. Bu yüzden bugün oluşturulan herhangi bir model listesi hızla güncelliğini yitirir.

Dokümanlar ayrıca her özelliğe açıklama eklemeyi ve additionalProperties: false kullanmayı öneriyor. Çünkü daha düşük uygulama seviyelerinde şema, aynı zamanda model için prompt malzemesine dönüşüyor.

Tek bir bayrağın arkasındaki üç uygulama seviyesi

strict: true ifadesi, isteğin ulaştığı yere göre farklı şeyler ifade ediyor. Resmî rehber, sağlayıcı davranışlarını üç katmana ayırıyor:

KatmanSağlayıcının şemanızla yaptığı işlemÇıktıya güvenebilir misiniz?
Yerel strict modŞemayı token üretimi sırasında tam olarak uygularEvet: çıktı yapısı gereği şemayla eşleşir
Dönüştürülmüş formatŞemanızı sağlayıcıya özgü structured-output formatına çevirirÇoğunlukla: yalnızca o formatın desteklediği şema özellikleriyle sınırlı
Güçlü yönlendirmeŞemayı model için kılavuz olarak eklerHayır: iyi bir günde şema benzeri çıktı, kötü bir günde uydurma alanlar

OpenRouter, istek anında belirli bir endpoint'in hangi katmanı kullandığını etiketlemiyor; dokümanlar bunun için her sağlayıcının kendi belgelerine yönlendiriyor. Yerel strict modlar kabul ettikleri JSON Schema özelliklerini de sınırlar. Bu nedenle alışılmadık anahtar kelimeler, en katı endpoint'lerde hata verirken başka yerlerde yalnızca yönlendirme olarak kabul edilebilir.

Sağlayıcı yönlendirme sayfasında Claude için özel bir durum belgelenmiş: response_format.type: "json_schema" kullanıldığında OpenRouter, katı ve şema doğrulamalı tool argümanlarını etkinleştiren Anthropic structured-outputs-2025-11-13 beta başlığını otomatik ekliyor. Ancak tools üzerinden gönderilen strict: true tool tanımları için çağrıyı yapan tarafın bu beta başlığını açıkça göndermesi gerekiyor. Aksi durumda OpenRouter strict değerini kaldırıp isteği onsuz yönlendiriyor. Hata sessiz gerçekleşiyor: Tool çağrılarınız artık şemaya göre doğrulanmıyor, fakat herhangi bir hata da almıyorsunuz.

Aynı şemanın bozulduğu altı senaryo

Resmî rehberde açıkça tanımlanan iki hata türü hızlıca başarısız olur. Topluluk tartışmalarında ortaya çıkan diğer dört tür ise asıl zaman kaybettirenlerdir.

Hızlı hata 1: endpoint structured output desteklemiyor. İstek, özelliğin desteklenmediğini belirten bir hatayla sonlanır. Can sıkıcıdır ama yoruma açık değildir. Hızlı hata 2: JSON Schema geçersiz. Şemanın ayrıştırılamaması veya endpoint'in şema kurallarını ihlal etmesi nedeniyle API isteği reddeder.

Sessiz hata 1: şema tamamen yok sayılır. Yanıt geçerli JSON'dur, ancak bambaşka bir şemaya aittir. r/LocalLLaMA'deki şemaya uyulmuyor tartışmasında u/DaniyarQQQ şöyle yazıyor:

Şemama hiç benzemeyen bir json döndürüyor.

Aynı tartışmada u/MicBeckie, teşhis sorununu şöyle özetliyor:

Ya json gereksinimle tamamen eşleştiğinde başarılı sonuç görüyorum ya da json'u inceleme imkânım olmadan hata alıyorum.

Wrapper kaynaklı hata 2: hiç göndermediğiniz tool_choice için 400. Bağlantı verilen LangChainJS örneğinde withStructuredOutput(), “structured output” işlevini oluşturduğu bir fonksiyona zorunlu tool_choice atayarak uyguluyordu. Tool çağrılarını duyuran ancak zorunlu tool seçimini desteklemeyen modellerde istek invalid_request_error ile sonlanıyor. DeepSeek v4 örneğinde hata doğrudan modeli de belirtiyordu: deepseek-reasoner does not support this tool_choice. u/shansoft, LangChainJS üzerinden tam olarak bu sorunla karşılaştı (tartışma). u/eyueldk'nin “tool call desteklediğini söylüyorsa structured output da desteklemeli” varsayımı burada geçerli çıkmadı. Tool-call desteği ile katı şema desteği birbirinden ayrı yeteneklerdir.

Sessiz hata 3: hata yok, içerik de yok. Bir gpt-oss-120b bildiriminde, strict schema isteğinin doğrudan sağlayıcı yönlendirmesinde 400 verdiği; OpenRouter üzerinden ise 200 dönmesine rağmen message.content değerinin boş olduğu anlatılıyor. r/openrouter'daki başka bir tartışmada “desteklenen” bir modelin yalnızca [1] veya [1.1] döndürdüğü görülüyor. Boş string'i sorunsuz ayrıştıran bir SDK, hatayı üç katman daha aşağıya taşır.

Sessiz hata 4: endpoint yanıt vermeden bekler. DeepSeek v4 için structured output seçeneği sunduğunu belirten endpoint'ler hakkında u/Beneficial-Loss-1031 şunu aktarıyor (tartışma):

deepinfra/fp4 ve akashml/fp8 structured output seçeneğine sahip, ancak API'nin yanıt vermesi için her birinde 3 dakika bekledim ve hiçbir şey alamadım.

#Hata biçimiGördüğünüz belirtiTipik neden
1Desteklenmeyen endpointHata: structured outputs desteklenmiyorYetenek sunmayan bir sağlayıcıya yönlendirme
2Geçersiz şemaİstek sırasında API hatasıŞema endpoint kurallarını ihlal ediyor
3Şemanın yok sayılmasıGeçerli JSON, yanlış alanlarYönlendirme katmanında uygulama
4tool_choice 400invalid_request_errorSDK'nin şemayı zorunlu tool call ile taklit etmesi
5Boş içerik200, boş message.contentSağlayıcının strict modu hatalı işlemesi
6BeklemeDakikalarca yanıt yokBildirimde doğrulanmamış — fp4/fp8 endpoint'lerinde 3 dakikalık bekleme

Modeli suçlamadan önce isteği sağlamlaştırın

En yüksek etkili ayar, provider nesnesindeki require_parameters: true seçeneğidir. Varsayılan değer false'tur; bilinmeyen parametreler bu durumda onları sessizce yok sayabilecek sağlayıcılara iletilir. false iken bile response_format ve structured outputs, endpoint'ler arasında yalnızca yumuşak bir tercihtir: önceliklidir, garantili değildir. Sağlayıcı yönlendirme dokümanlarına göre bayrağı true yapmak, yönlendirmeyi gönderdiğiniz tüm parametreleri destekleyen endpoint'lerle sınırlar:

{
  "model": "deepseek/deepseek-chat",
  "messages": [{ "role": "user", "content": "Extract the shipping info" }],
  "response_format": { "type": "json_schema", "json_schema": { "name": "shipping_info", "strict": true, "schema": { "...": "..." } } },
  "provider": {
    "require_parameters": true,
    "order": ["fireworks"],
    "allow_fallbacks": false
  }
}

Her ek kısıtlama uygun sağlayıcı havuzunu daraltır. allow_fallbacks: false ise erişilebilirlikten ödün vererek belirleyicilik sağlar. Aynı yönlendirme dokümanları, varsayılan stratejinin son 30 saniyedeki çalışma süresi ve fiyatın ters karesi üzerinden yük dengeleme yaptığını belirtiyor. Bu yaklaşım şema yeteneğini değil, ucuz ve sağlıklı endpoint'leri optimize eder. order alanını tek sağlayıcıya sabitleyip fallback'leri kapatmak, yönlendirmeyi tekrar üretilebilir kılar: İstek, kesinti sırasında başka bir sağlayıcıya kayamaz. Yine de o tek endpoint'in uygulama seviyesini sizin doğrulamanız gerekir.

Yönlendirmenin yakalayamadığı sorunları iki denetim alışkanlığı ortaya çıkarır:

  • İsteği hangi sağlayıcının karşıladığını kontrol edin. OpenRouter'ın generation metadata verisi, her üretim için sağlayıcı yönlendirmesini model, gecikme ve token sayılarıyla birlikte gösterir. Çıktı kalitesi değiştiğinde bu bilgi, modelin mi davranış değiştirdiğini yoksa router'ın mı sağlayıcı değiştirdiğini anlamanızı sağlar.
  • Her durumda istemci tarafında doğrulama yapın. Katmanların hiçbiri sizin tarafınızdaki Pydantic veya Zod ayrıştırmasının yerine geçmez. r/LLMDevs test tartışmalarından çıkan ortak ders şu: “geçerli JSON”, “şemaya uygun JSON” ve “anlamsal olarak doğru sonuç” üç farklı eşiğe karşılık gelir. API'nin sorumluluğu en fazla ilk ikisinde kısmi olabilir.

Streaming destekleniyor, ayrıştırma size kalıyor

Structured output, stream: true ile birlikte kullanılabilir. Dokümanların tanımladığı sözleşmeye göre model geçerli kısmi JSON parçaları yayınlar ve akış tamamlandığında birleşen yanıt şemayla eşleşir. Bu uyumluluk endpoint'in uygulama katmanına bağlıdır; yönlendirme katmanındaki bir endpoint yine de kurala uymayan çıktı birleştirebilir. Bu yüzden nihai nesneyi kendiniz doğrulayın. Dokümanlar artımlı bir ayrıştırıcı da sunmuyor; gecikmeye duyarlı arayüzlerde asıl mühendislik sorunu burada ortaya çıkıyor. r/LLMDevs'teki streaming en iyi uygulamalar tartışmasından:

Sonunda JSON'u kendim tamamlayan bir fonksiyon yazdım. — u/am174744

“...bu aslında bir state machine.” — u/ImNotLegitLol, onar sonra ayrıştır yaklaşımını düzeltiyor

Pratik seçenekler şunlar: Kısmi JSON kabul eden bir ayrıştırıcı kullanmak, yalnızca tamamlanmış alanları ekranda göstermek veya artımlı gösterimi tamamen atlayıp nihai nesne birleşene kadar yükleniyor göstergesi sunmak.

Response Healing neyi düzeltir, neyi düzeltemez?

OpenRouter'ın Response Healing eklentisi, streaming kullanılmayan json_schema isteklerini hedefler ve eksik JSON, araya giren Markdown kod blokları gibi kusurlu biçimlendirmeleri onarır. Ancak düzelttiklerinden daha önemli iki sınırı var:

  1. Streaming kapsam dışındadır. Dokümanlar eklentiyi streaming olmayan isteklerle sınırlandırır.
  2. Şema ihlalleri kapsam dışındadır. Healing, JSON'u ayrıştırılabilir hâle getirir; şemanızı yok sayan bir yanıtı şemaya uygun hâle getirmez. Yukarıdaki 3 numaralı hata biçimine çözüm değildir.

Şemaya gerçekten uyan modelleri seçmek

Model listeleri eskir, değerlendirme ölçütleri ise eskimez. Aşağıdaki üç filtre, yukarıdaki hata türlerinin çoğunu yakalar:

  1. Yerel strict uygulama. Şemayı token üretimi sırasında zorlayan sağlayıcıları; şemayı dönüştüren veya yalnızca yönlendirme olarak kullananlara tercih edin. Model sayfasındaki Providers tablosu hangi endpoint'lerin structured_outputs duyurduğunu gösterir; uygulama kalitesini ise sağlayıcı katmanı belirler.
  2. Denetlenebilir tek sağlayıcı. Birden fazla çağrıda sağlayıcı bilgisini bilinen ve güvenilir bir endpoint'le karşılaştırın. Router istekleri farklı katmanlardaki sağlayıcılara dağıtıyorsa hata oranınız bir yönlendirme piyangosuna dönüşür. Sağlayıcıyı sabitleyin veya tek sağlayıcılı bir model seçin.
  3. Okuduğunuz değil, çalıştırdığınız smoke test. Topluluk sinyalleri her iki yönde de hızla eskir: Yukarıdaki Qwen hata bildirimleri ve DeepSeek v4'ün eksik desteği, sağlayıcılar endpoint'lerini güncelledikçe değişebilir. Önem taşıyan tek güvenilirlik oranı, kendi şemanızla elde ettiğiniz orandır.

OpenRouter structured outputs: sık sorulan sorular

json_object ile json_schema arasındaki fark nedir?

json_object yalnızca sözdizimsel olarak geçerli JSON ister; json_schema ise yanıtın uyması gereken bir şema sağlar. json_object, alan düzeyindeki şemanıza uygunluğu değil JSON sözdizimini garanti eder. Bu nedenle sonraki kodunuzun belirli alan adlarına ihtiyacı varsa doğrulamayı kendiniz yapmalısınız.

Hangi OpenRouter modelleri structured output destekliyor?

Güvenebileceğiniz sabit bir liste yok: Destek endpoint bazındadır, zaman içinde değişir ve Aralık 2024'te yalnızca OpenAI 4o ile Fireworks modelleriyle başlamıştır. Her endpoint için structured_outputs bayrağını model sayfasındaki Providers bölümünden kontrol edin.

Model şemamı neden yok sayıyor?

Üç yaygın neden var: İstek yönlendirme katmanındaki veya destek sunmayan bir endpoint'e gitmiş olabilir; bunu require_parameters: true ve sağlayıcı sabitlemeyle çözebilirsiniz. Şemanız, endpoint'in strict modunun kabul etmediği anahtar kelimelere dayanıyor olabilir. Ya da SDK wrapper'ı, zorunlu tool seçimini desteklemeyen bir modelde structured output'u tool calling üzerinden taklit ediyor olabilir.

OpenRouter structured outputs ile Pydantic veya LangChain kullanabilir miyim?

Evet. Resmî dokümanlar istek formatının OpenRouter'ın chat-completions tarzı API'siyle uyumlu olduğunu belirtiyor; bu nedenle Pydantic ile üretilen şemalar ve OpenAI SDK doğrudan çalışır. LangChain'in withStructuredOutput() yöntemi de kullanılabilir, ancak response_format gönderdiğini doğrulayın. DeepSeek v4'te 400 hatalarına yol açan yöntem, şemayı tool_choice üzerinden taklit etmekti.

Structured output streaming ile çalışır mı?

Evet. Akış geçerli kısmi JSON yayınlar, ancak nihai şema uyumu endpoint'in uygulama katmanına bağlıdır; birleşen nesneyi kendiniz doğrulayın. Parça parça gelen veriyi artımlı ayrıştırmak uygulamanızın sorumluluğundadır ve Response Healing akışlara uygulanmaz.

OpenRouter yanıtları şemama göre doğruluyor mu?

Tüm endpoint'ler için geçerli bir garanti olarak hayır. Uygulama sağlayıcı katmanına bağlıdır; Response Healing ise şema ihlallerini değil, yalnızca hatalı JSON biçimini onarır. İstemci tarafı doğrulama zorunlu olmaya devam eder.

10 çağrılık smoke test

Structured output kullanan herhangi bir modeli üretime almadan önce şu testi uygulayın:

  1. Temsil gücü olan tek bir şema belirleyin: Orta karmaşıklıkta olsun, additionalProperties: false içersin ve tüm özellikler açıklamalara sahip olsun.
  2. strict: true ve require_parameters: true ile 10 özdeş istek gönderin; fallback'ler açık kalsın. Bu aşama özellikle fallback davranışını ölçtüğü için onları kapatmayın.
  3. Her yanıtı üç ölçütte değerlendirin: Ayrıştırılabilir JSON mu? Şemaya uygun mu? Anlamsal olarak tutarlı mı?
  4. Generation metadata üzerinden her yanıtı hangi sağlayıcının sunduğunu kaydedin. Dört farklı sağlayıcıdan gelen 10/10 başarı oranı garanti değil, yönlendirme piyangosudur.
  5. Karar verin: Olduğu gibi yayına alın; başarılı endpoint'e provider.order ile sabitleyip 10 çağrıyı sabit yönlendirmeyle yeniden çalıştırın; ya da modeli değiştirip istemci tarafında doğrulama ve yeniden deneme katmanı ekleyin.

Başarı eşiğini siz belirlersiniz. Ancak sabit bir şemada 9/10'un altındaki her sonuç, yeniden deneme ve doğrulama kodunun isteğe bağlı olmadığını gösterir. Bunlar ürünün bir parçasıdır.

İlgili okumalar: OpenRouter auto router sağlayıcıları nasıl seçer?, OpenRouter prompt caching ile maliyetleri düşürme ve OpenRouter 429 rate limit hatalarını çözme.