sone centralgeliştirici

Akış

Akışlı yanıtlar nasıl gelir, bağlantı nasıl canlı tutulur ve metin neden kelime kelime değil mesaj mesaj ilerler.

Üç biçim de akışı destekler: Chat Completions ve Responses'ta "stream": true, Vercel AI SDK'da /chat her zaman akar. Hepsi sunucu tarafından gönderilen olaylar, yani SSE kullanır.

Bağlantı

Akışlı yanıtın başlıkları:

Content-Type: text/event-stream; charset=utf-8
Cache-Control: no-cache, no-transform
Connection: keep-alive
X-Accel-Buffering: no
X-Sone-Conversation-Id: conv_x8k2m9p4q7w1r3t

Vercel AI SDK akışında ayrıca x-vercel-ai-ui-message-stream: v1 gelir.

  • Önce kontroller. Anahtar, istek sınırı, asistan, sohbet ve paket kontrolleri akış başlamadan yapılır. Geçmeyen istek akış yerine sıradan bir HTTP hatası alır: Hatalar.
  • İlk olay asistan başlarken gelir. Kontroller geçince Chat Completions'ta rolü taşıyan ilk parça, Responses'ta response.created, AI SDK'da start hemen gelir. Asistan daha düşünürken bağlantının kurulduğunu ve sohbetin kimliğini bilirsiniz.
  • On saniyede bir kalp atışı. Uzun süren turlarda bağlantı : ping satırlarıyla canlı tutulur. İki nokta üst üste ile başlayan satırlar SSE yorumudur; SDK'lar onları zaten atlar, kendi ayrıştırıcınızı yazıyorsanız siz de atlayın.
  • Bitiş. Chat Completions ve AI SDK data: [DONE] ile biter. Responses response.completed ya da, bir hatada, response.failed olayıyla biter; orada [DONE] yoktur.

Metin neden mesaj mesaj gelir

Genel bir dil modeli API'sinde metin model ürettikçe, kelime kelime gelir. Burada öyle değil; bu bilerek böyle.

Asistanın yazdığı yanıt ziyaretçiye gitmeden önce işletmenin güvenlik kontrollerinden geçer: fiyat ve stok doğru mu, söz verilmemesi gereken bir şey var mı, mesaj gerçekten gönderilmeli mi. Bu kontroller yanıtın tamamına bakar. Bu yüzden bir mesaj ancak bitip kontrolden geçtikten sonra yola çıkar.

Sonuçta akış şöyle ilerler:

  1. Kontroller geçer, bağlantı açılır, ilk olay gelir.
  2. Asistan düşünür ve araçlarını kullanır. Bu birkaç saniye sürebilir. Bu sırada "Ürünlere bakılıyor" gibi kısa durumlar gelir.
  3. İlk mesaj kontrolden geçer ve gelir. Daktilo etkisi bozulmasın diye kelime gruplarına bölünerek hızla akar.
  4. Varsa sonraki mesajlar, ürün kartları ve düğmeler aynı şekilde sırayla gelir.

Kısa durumlar her biçimde başka bir yerde gelir:

BiçimDurum
Chat Completionsdelta'sı boş bir parçanın üst düzeyindeki sone.activity
ResponsesBir olay değil, SSE yorum satırı: : sone.activity {"label":"Ürünlere bakılıyor"}. sequence_number taşımaz; SDK'lar onu atlar, okumak için akışı kendiniz ayrıştırın.
Vercel AI SDKGeçici (transient: true) data-sone-status parçasının data.label alanı; yalnız onData'ya gelir

Durum metni bir araç adı değil, ziyaretçinin anlayacağı Türkçe bir cümledir. İki mesaj arasında kısa bir bekleme olabilir. Arayüzünüzde bir "yazıyor" göstergesi tutmak iyi olur.

Aynı mesajı aynı Idempotency-Key ile, ya da sohbetin kimliği ve aynı geçmişle yeniden gönderdiğinizde asistan yeniden yanıt vermez; kayıtlı yanıt akışın sonunda bir kerede gelir. Ayrıntılar: Tekrar denemek.

Bağlantı koparsa

Asistanın gönderdiği her mesaj, gönderildiği anda sohbete kaydedilir. Akış yarıda koparsa kaçırdığınız mesajları GET /conversations/{id}/messages ile okuyabilirsiniz. Sohbetin kimliği akışın başında X-Sone-Conversation-Id başlığında gelir. Ayrıntılar: İnsan devri ve ekip yanıtları.

Aynı mesajı yeniden göndermeniz gerekirse ilk gönderimdeki Idempotency-Key ile gönderin; asistan iki kez yanıt vermez. Önceki tur hâlâ yanıtlanıyorsa istek 409 conversation_busy alır.

Proxy arkasında

Akışı kendi sunucunuzdan geçiriyorsanız ara katmanın yanıtı tamponlamadığından emin olun. Nginx'te proxy_buffering off; yeterlidir. Next.js route handler'larında yanıt gövdesini olduğu gibi döndürün:

app/api/sohbet/route.ts
export async function POST(request: Request) {
  const upstream = await fetch('https://pb.sonecentral.com/api/v1/chat/completions', {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${process.env.SONE_API_KEY}`,
      'Content-Type': 'application/json',
      'Idempotency-Key': request.headers.get('Idempotency-Key') ?? crypto.randomUUID(),
    },
    body: await request.text(),
  });

  return new Response(upstream.body, {
    status: upstream.status,
    headers: {
      'Content-Type': upstream.headers.get('Content-Type') ?? 'text/event-stream',
      'Cache-Control': 'no-cache',
      'X-Sone-Conversation-Id': upstream.headers.get('X-Sone-Conversation-Id') ?? '',
    },
  });
}

Bu şekilde sunucu anahtarını kullanırsanız, isteği gönderen ziyaretçiyi kendi tarafınızda doğrulamak ve sınırlamak sizin işinizdir. Sitenizdeki sohbet penceresi için tarayıcı anahtarı daha basittir.

Bu sayfada