Skip to main content
CID222 Docs
GeliştirmeKılavuzlar

En iyi uygulamalar

CID222 ağ geçidiyle entegrasyon kurarken kimlik bilgilerini nasıl saklayacağınız, istekleri nasıl boyutlandıracağınız, tamponlanan akışı nasıl okuyacağınız ve güvenli biçimde nasıl yeniden deneyeceğiniz.

  • Sürüm: 0.4
  • Rol: admin_user, normal_user

Ağ geçidiyle ilgili üç olgu, entegrasyon kararlarınızın neredeyse tamamını belirler. Ağ geçidi modelin yanıtını tamponlar ve göndermeden önce filtreler; bu nedenle ekrana basacağınız token parçacıkları yoktur. Yalnızca oturum açma yollarına hız sınırı uygular; bu nedenle istek yolunda geri çekilmenizi gerektiren bir 429 yoktur. Ve farklı uç noktalara ulaşan iki tür taşıyıcı belirteç kabul eder. Tasarımınızı bunlara göre yaparsanız geri kalanı sıradan HTTP'dir.

Örneklerde <gateway-host>, ağ geçidinin dinlediği adrestir — varsayılan olarak 3000 portu ya da önündeki ters proxy'nin yayımladığı adres.

Kimlik bilgilerini sunucu tarafında tutun

Ağ geçidi API anahtarı, cid_key_ ile başlayıp 64 onaltılık karakterle devam eden bir taşıyıcı kimlik bilgisidir ve Authorization: Bearer cid_key_… biçiminde sunulur. X-API-Key başlığı yoktur. Bu dizeyi elinde tutan her şey kiracının sağlayıcı bütçesini harcayabilir.

  • Anahtarı asla bir tarayıcıya veya mobil ikiliye göndermeyin. Ağ geçidini kendi sunucunuzdan çağırın, tarayıcı da sizin sunucunuzla konuşsun.
  • Anahtarı ortam değişkeninden okuyun. Depoya işlemeyin ve bir imaj katmanına gömmeyin.
  • Her ortam için ayrı anahtar kullanın. Geliştirme, hazırlık ve üretim kendi anahtarlarını alır; böylece biri başka bir yerde kesintiye yol açmadan iptal edilebilir.
  • Belirli aralıklarla ve ayrılmalarda yenileyin. Bir yönetici anahtarı API Anahtarları → API Anahtarını Yenile altından yeniden oluşturur; eski değer anında çalışmaz olur.
  • Mümkün olan yerde expires_at belirleyin. Süre sonu olmayan bir anahtar kendiliğinden hiç geçersizleşmez.
// Server-side route. The key never leaves the server.
export default async function handler(req, res) {
  const upstream = await fetch('https://<gateway-host>/chat/completions', {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${process.env.CID222_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ model: 'gpt-4o', messages: req.body.messages }),
  });
 
  // The gateway answers with text/event-stream. Forward it, do not buffer it.
  res.setHeader('Content-Type', 'text/event-stream');
  res.setHeader('Cache-Control', 'no-cache');
  res.setHeader('X-Accel-Buffering', 'no');
  for await (const chunk of upstream.body) res.write(chunk);
  res.end();
}

Warning

Bir kiracı grubuna verilen anahtar, gruba en erken eklenen üyenin kimliğini ödünç alır. O kullanıcıyı kaldırmak anahtarı iptal etmez, kimliğini başka bir üyeye devreder. Anahtarın sahibi olan kişi ayrıldığında anahtarı açıkça iptal edin.

Göndermeden önce girdiyi doğrulayın

Ağ geçidi, transform: true ve whitelist: true ile genel bir doğrulama işlem hattı uygular. Bilinmeyen gövde alanları reddedilmez, sessizce çıkarılır; bu yüzden yanlış yazılmış bir alan adı, ayarınızı yok sayan başarılı bir istek üretir. Alan adlarını 200 yanıtına güvenmek yerine DTO ile karşılaştırın.

Var olan sınırlar şunlardır:

SınırDeğerNerede geçerli
İstek gövdesi50 MB/webhooks/* dışındaki her rota
Tespitte text1–50.000 karakterPOST /api/v1/guardrails/detect
Görüntü yükleme10 MB çözülmüş baytPOST /image-analysis/analyze
Belge yükleme20 MBPOST /document-analysis/analyze-file

/chat/completions üzerinde mesaj başına karakter sınırı yoktur. Kontrolden çıkmış bir istem için sağlayıcı çağrısı harcamadan önce kendi sınırınızı koyun.

function validateMessage(content) {
  if (typeof content !== 'string' || !content.trim()) {
    throw new Error('Message cannot be empty');
  }
  // Your own budget, not a gateway limit — the gateway caps the body at 50 MB.
  if (content.length > 10000) {
    throw new Error('Message too long for this application');
  }
  return content;
}

Token parçacıkları değil, tek bir içerik olayı bekleyin

POST /chat/completions her zaman text/event-stream ile yanıt verir. İstek gövdesindeki stream alanı DTO tarafından kabul edilir ama hiçbir yerde okunmaz — devreye alabileceğiniz akışsız bir mod yoktur, devre dışı bırakma imkânı da yoktur.

Bu akışta taşınan şey bir token beslemesi değildir. Düzenleyici, sağlayıcının parçacıklarını tüketir, yanıtın tamamını biriktirir, üzerinde çıktı filtresini çalıştırır ve sonucu tek bir olay olarak yayar:

{"id":"filtered-response","content":"…the whole reply…","finish_reason":"stop","filtered":false,"entities_masked":0}

Yani istemci önce varsa kontrol olaylarını görür, sonra model üretirken sessizliği, ardından tek bir büyük içerik olayını, en son da data: [DONE] satırını. Arayüzü buna göre planlayın: daktilo efekti değil, tek adımda tamamlanan bir ilerleme göstergesi. delta.text, content_block_delta veya bir choices[] gövdesi bekleyen istemci sonsuza kadar bekler.

Note

Yine de akışı okuyun. Yanıt gövdesini bir dizeye toplayıp response.json() çağırmak başarısız olur; yük bir JSON belgesi değil, SSE çerçeveleridir.

Bağlantıları yeniden kullanın

Tespit, sağlayıcı çağrısından önce çalışır; bu nedenle bir istek, modelin yanıt verme süresi artı filtre süresi boyunca bağlantıyı tutar. Her istekte yeni bir TLS bağlantısı açmak bunun üstüne bir el sıkışma ekler. Süreç boyunca havuzlanmış bir dağıtıcıyı canlı tutun.

// Node 18+, native fetch. `agent` is a node-fetch v2 option and is ignored here.
import { Agent, fetch } from 'undici';
 
const dispatcher = new Agent({ keepAliveTimeout: 60_000, connections: 32 });
 
export function callGateway(body) {
  return fetch('https://<gateway-host>/chat/completions', {
    method: 'POST',
    dispatcher,
    headers: {
      Authorization: `Bearer ${process.env.CID222_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(body),
  });
}

Oturumlar ile durumsuz uç nokta arasında bilinçli seçim yapın

Oturumlar konuşmayı sunucuda tutar; böylece tüm geçmiş yerine tek bir mesaj gönderirsiniz ve bağlam penceresini, özetlemeyi ve oturum başına token muhasebesini ağ geçidi yönetir.

Bunun bedeli API anahtarıdır. /sessions/* yalnızca bir kullanıcı JWT'si kabul eder: bir cid_key_ taşıyıcısı oturum oluşturamaz ve oturuma mesaj gönderemez. Oturum trafiği, POST /auth/login ile alınan bir kullanıcı JWT'si gerektirir; bu belirteç JWT_EXPIRES_IN süresinde — varsayılan olarak 24 saatte — sona erer ve kullanıcı ya da bir yönetici tarafından daha erken iptal edilebilir.

İhtiyacınızKullanın
API anahtarıyla kimliklenen makine entegrasyonuGeçmişi kendiniz göndererek POST /chat/completions
Sunucu tarafında konuşma durumu, bağlam yönetimi ve özetlemeKullanıcı JWT'si ile POST /sessions, ardından POST /sessions/:id/messages

GET /sessions hiçbir sorgu parametresi almaz ve sayfalama yapmaz. Liste yanıtları context: [] ile birlikte bir message_count döndürür; tam bağlam için GET /sessions/:id çağırın.

Yalnızca yeniden denenebilir olanı yeniden deneyin

İstek yolunda hız sınırlaması yoktur. /chat/completions, /api/v1/guardrails/detect, /sessions/*, /image-analysis/*, /document-analysis/* ve /models hiç kısıtlanmaz. Yalnızca kimlik doğrulaması gerektirmeyen üç rota kısıtlanır: istemci IP'si başına dakikada 10 istekle POST /auth/login, dakikada 5 istekle POST /auth/forgot-password ve POST /auth/reset-password. Ağ geçidinde hiçbir yer Retry-After başlığı veya bir hız sınırı başlığı kümesi yaymaz; dolayısıyla bunları okuyan yeniden deneme mantığı null okur.

Geriye yeniden denemeye değer kısa bir liste kalır:

  • Hiç bayt gelmeden önce bağlantı hatası veya zaman aşımı. Üstel geri çekilmeyle yeniden deneyin.
  • JSON ile yanıt veren bir rotadan gelen 5xx — yönetim ve analiz rotaları. Geri çekilmeyle yeniden deneyin.
  • /auth/login üzerinden gelen 429. Bir dakikalık pencerenin dolmasını bekleyin; ne kadar kaldığını söyleyen bir başlık yoktur.

Geri kalan her şey, tekrarlanacak değil düzeltilecek bir istemci hatasıdır. Bir yeniden denemenin kurtaramayacağı şeye de dikkat edin: /chat/completions herhangi bir iş yapmadan önce durum kodunu ve SSE başlıklarını gönderir; bu nedenle o noktadan sonraki bir hata, durum kodu olarak değil, 200 yanıtı üzerinde bir olay olarak gelir. İsteği tekrarlamak sağlayıcı harcamasını da tekrarlar.

async function withRetry(fn, maxAttempts = 3) {
  for (let attempt = 0; attempt < maxAttempts; attempt++) {
    try {
      return await fn();
    } catch (error) {
      // 4xx is a request to fix. A content block is not an error at all —
      // it arrives as an SSE event on a 200.
      if (error.status >= 400 && error.status < 500) throw error;
      if (attempt === maxAttempts - 1) throw error;
      await new Promise((r) => setTimeout(r, 2 ** attempt * 1000));
    }
  }
}

Modeli bilinçli seçin

Tohum verisinin gerçekten kaydettiği bir model isteyin ve ad belirsizse provider gönderin. gpt-4o, gpt-4o-mini ve gpt-4-turbo hem openai hem de azure_openai tarafından kaydedilir ve bunları ayıran alan provider'dır. Azure'un 3.5 modeli noktasız biçimde gpt-35-turbo'dur.

  • Önce GET /models çağırın. Yalnızca sağlayıcısının kiracınız için etkin kimlik bilgisi bulunan modelleri döndürür; dolayısıyla o çağıran için yetkili listedir.
  • Sorunun yanıtı için yeterliyse küçük modeli tercih edin. gpt-4o-mini ve gpt-4o openai altında kayıtlıdır.
  • Kullanıcıya dönük her şeyde max_tokens belirleyin. Kontrolden çıkmış bir tamamlamanın tek tavanı budur.
  • Beklediğiniz davranışı her kullanıcı turunda tekrarlamak yerine bir system mesajına koyun.

Ağ geçidinin ne tespit ettiğini izleyin

  • Tespit akışını izleyin. Tüm Tespitler, her inceleme yolunda nelerin maskelendiğini, işaretlendiğini ve reddedildiğini gösterir. Reddetmelerdeki artış genellikle bir saldırıyı değil, bir filtre değişikliğini gösterir.
  • Token kullanımını takip edin. token_usage olayı gerçek prompt_tokens / completion_tokens dağılımını taşır; sağlayıcı bir istem önbelleği indirimi bildirdiğinde cached_input_tokens da gelir. Bunu istek başına kaydedin; maliyet raporları bunun üzerine kurulur.
  • İlk token süresine değil, uçtan uca gecikmeye alarm kurun. Yanıt tamponlandığı için ilk bayt ile son bayt pratikte aynı andır.
  • Filtre değişikliklerini yayımlamadan önce test edin. Filtre Testi, bir kural kümesini sağlayıcı çağrısı harcamadan örnek içerik üzerinde çalıştırır.

Sınırlar ve bilinen eksikler

  • İstek yolunda hız sınırlaması yok. Hatalı davranan bir istemci sağlayıcı kotasını engelsizce tüketebilir. Sınırı kendi uygulamanızda veya ağ geçidinin önündeki proxy'de uygulayın.
  • İstemciye kademeli akış yok. Çıktı filtrelemesi karar verebilmek için yanıtın tamamına ihtiyaç duyar; bu yüzden ağ geçidi üzerinden token bazlı bir arayüz bugün mümkün değildir.
  • stream etkisizdir. Doğrulanır ve ardından yok sayılır; bu da istek günlüklerinde desteklenen bir anahtar gibi görünmesine yol açar.
  • Bilinmeyen alanlar uyarı olmadan düşürülür. Alan adındaki bir yazım hatası sessizce kaybolur.
  • Bir API anahtarı oturumları, görüntü analizini ve belge analizini kullanamaz. Bu yüzeyler yalnızca JWT kabul eder; bu yüzden bunlara ihtiyaç duyan bir makine entegrasyonunun bir kullanıcı kimlik bilgisi tutması ve yenilemesi gerekir.
  • Grup anahtarı bir üyenin kimliğini ödünç alır. O üyeyi kaldırmak anahtarı iptal etmez, devreder.
  • Tespit kalitesi metin uzunluğuna, tespit motoruna ve filtre yapılandırmasına bağlıdır. Her doğruluk veya gecikme rakamını bunlara koşullu sayın; bkz. Performans ve doğruluk.

İlgili sayfalar

  • Hata yönetimi — her durum kodunun ve SSE reddetme olayının ne anlama geldiği ve hangilerini yeniden denemeye değer olduğu.
  • Entegrasyon örnekleri — burada anlatılan SSE sözleşmesi için çalışan istemciler.
  • Sohbet API'si — istek DTO'sunun tamamı ve olay listesi.

Son güncelleme