Prompt API ile oturum sıkıştırma

Yayınlanma tarihi: 23 Haziran 2026

Her LanguageModel oturumunun sınırlı bir bağlam penceresi vardır. Sohbet büyüdükçe model, bağlamında tam mesaj geçmişini (her kullanıcı istemi ve her asistan yanıtı) biriktirir. Pencere dolduğunda tarayıcının otomatik taşma işleme özelliği devreye girer. Yeni isteme yer açmak için en eski mesaj çiftlerini (bir istem ve yanıt çifti) siler. Gelen istem o kadar büyükse ki tüm sohbet geçmişini kaldırmak bile yeterli olmuyorsa arama QuotaExceededError ile tamamen başarısız olur.

Oturum sıkıştırma, proaktif bir alternatiftir: Summarizer API ile görüşme geçmişini özetleyin, ardından bu özetleri initialPrompts olarak kullanarak yeni bir oturum başlatın. Tarayıcı, çalışma zamanı taşması işleme sırasında initialPrompts öğesini hiçbir zaman kaldırmaz. Bu nedenle, özetlerin kendileri create() çağrıldığında bağlam penceresine sığdığı sürece, sıkıştırılmış özet modelin bağlamına kalıcı olarak sabitlenir. Yeni oturum, orijinal jeton maliyetinin çok daha düşük bir kısmıyla aynı sohbet dizisini taşır.

Oturum sıkıştırma, uzun süren LanguageModel sohbetlerin sürekliliği kaybetmeden bağlam penceresinde kalmasını sağlar. Önemli adımlar şunlardır:

  1. contextUsage değerini contextWindow değerine göre izleyin ve kullanıcıya gösterin.
  2. Erken uyarı olarak contextoverflow etkinliğini dinleyin.
  3. Language Detector API ile her mesajın dilini tespit edin, ardından dili dikkate alan bir Summarizer API örneğiyle mesajı özetleyin.
  4. Eski oturumu yok edin ve initialPrompts ile yeni bir oturum başlatın.
  5. Hata kurtarma için fullHistory kopyasını saklayın.

Bağlam kullanımını izleme

Prompt API, bir oturumun bağlamının ne kadar dolu olduğunu izlemek için iki özellik sunar:

  • session.contextUsage: Şu anda kullanılan jeton sayısı.
  • session.contextWindow: Oturumun toplam jeton kapasitesi.

Bunu bir <progress> öğesinde yansıtarak kullanıcıların oturumun sınıra ne kadar yaklaştığını bir bakışta anlamasını sağlayın. value ve max değerlerini doğrudan jeton sayılarına ayarlayın. Tarayıcı, çubuğu otomatik olarak ölçeklendirir:

<progress id="token-bar" value="0" max="1"></progress>
<label for="token-bar" id="token-label">Context: — / — tokens</label>
function updateTokenDisplay(session) {
  const usage = session.contextUsage;
  const total = session.contextWindow;

  tokenBar.value = usage;
  tokenBar.max = total;
  tokenLabel.textContent =
    `${Math.round(usage)} / ${Math.round(total)} tokens ` +
    `(${Math.round((usage / total) * 100)}%)`;
}

Çubuğun güncel kalması için her istem yanıtından sonra updateTokenDisplay() işlevini çağırın.

Bağlam taşmasını dinleme

Yeni bir istem, kalan bağlamı aştığında tarayıcının otomatik kurtarma işlemi başlar: Yeterli alan açılana kadar en eski istem ve yanıt çiftlerini tek tek kaldırır. contextoverflow etkinliği, bu çıkarma işlemi başladığı anda tetiklenir. Oturumu oluşturduktan hemen sonra bir işleyici kaydedin:

session.addEventListener('contextoverflow', () => {
  showWarning('⚠ Context window nearly full. Consider compacting the session.');
});

Bu çıkarma davranışının iki önemli özelliği vardır:

  • initialPrompts çalışma zamanında çıkarılmaz. Tarayıcı, gelen isteme yer açmak için bunları kaldırmaz. Ancak initialPrompts öğesinin LanguageModel.create() öğesine iletilen birleşik boyutu, bağlam penceresine sığamayacak kadar büyükse create(), QuotaExceededError ile reddeder. Bu nedenle, sohbetin devam edebilmesi için sıkıştırmanın yeterince küçük olduğundan emin olun.
  • Tahliye işlemi sınırlıdır. Gelen istem o kadar büyükse önceki görüşmenin tamamını kaldırmak bile yeterli olmaz. Bu durumda prompt() veya promptStreaming() çağrısı QuotaExceededError ile başarısız olur ve hiçbir şey kaldırılmaz.

İstem API'si belgelerinde bağlam taşması işleme hakkında daha fazla bilgi edinin.

Kullanıcıyı uyarmak, gönderme düğmesini devre dışı bırakmak veya tarayıcı, görüşme geçmişini sessizce silmeye başlamadan önce otomatik olarak sıkıştırmayı tetiklemek için contextoverflow etkinliğini kullanın.

Oturumu sıkıştırma

Sıkıştırma üç adımdan oluşur:

  1. Görüşme geçmişindeki her mesajı Özetleyici API ile özetleyin.
  2. Eski oturumu yok edin.
  3. Özetlerle doldurulmuş yeni bir oturum oluşturun initialPrompts.

Geçmişi özetleme

Özetleyici API, tek tek sohbet mesajlarını sıkıştırmak için idealdir. Her mesajın önce Language Detector API ile dilini tespit edin. Böylece özetleyici doğru şekilde yapılandırılabilir:

async function detectLanguage(text, threshold = 0.7) {
  const detector = await LanguageDetector.create();
  const results = await detector.detect(text);
  if (results.length > 0 && results[0].confidence >= threshold) {
    return results[0].detectedLanguage;
  }
  return null; // confidence too low — caller falls back to navigator.language
}

0.7Güven eşiği, kesin olmayan algılamalar üzerinde işlem yapılmasını önler. Güven eşiğin altında olduğunda navigator.language'ya geri dönün.

Ardından, algılanan dil için yapılandırılmış bir özetleyici oluşturun. Daha küçük ve daha düşük gecikmeli model varyantını seçmek için preference: 'speed', daha hızlı model algılanan dili desteklemiyorsa preference: 'auto''ye geri dönmek için:

const summarizers = {}; // cache, keyed by `${format}:${lang}`

async function getSummarizer(format, lang) {
  const key = `${format}:${lang}`;
  if (summarizers[key]) return summarizers[key];

  const baseOptions = {
    type: 'tldr',
    format, // 'markdown' or 'plain-text'
    length: 'short',
    expectedInputLanguages: [lang],
    expectedContextLanguages: [lang],
    outputLanguage: lang,
  };

  let options = { ...baseOptions, preference: 'speed' };
  let avail = await Summarizer.availability(options);

  if (avail === 'unavailable') {
    options = { ...baseOptions, preference: 'auto' };
    avail = await Summarizer.availability(options);
  }

  if (avail === 'unavailable') {
    throw new Error('Summarizer API unavailable on this device.');
  }

  summarizers[key] = await Summarizer.create(options);
  return summarizers[key];
}

format+lang çifti başına özetleyici önbelleğe alma, aynı dili paylaşan ardışık mesajlar olduğunda gereksiz create() çağrılarını önler.

format bağımsız değişkeni, mesajın içeriğinden türetilir. Düz metin için 'markdown' belirtmek istenmeyen biçimlendirmelere yol açabilir. Markdown için 'plain-text' belirtmek ise kod bloklarını ve vurguları kaldırır. İkisi arasındaki farkı küçük bir normal ifade gösterir:

function looksLikeMarkdown(text) {
  return /(?:^#{1,6} |^[-*+] |\d+\. |\*\*|__|\[.+?\]\(|^> |^```)/m.test(text);
}

Dil ve biçim çözüldükten sonra her iletiyi özetleyin ve modelin bağımsız bir belgeyi değil, bir sohbet dönüşünü sıkıştırdığını anlaması için context dizesini iletin:

const compacted = [];

for (const msg of history) {
  const lang = (await detectLanguage(msg.content)) ?? navigator.language;
  const format = looksLikeMarkdown(msg.content) ? 'markdown' : 'plain-text';
  const summarizer = await getSummarizer(format, lang);

  const summary = await summarizer.summarize(msg.content.trim(), {
    context:
      `This is a ${msg.role} turn from a chat conversation. ` +
      `Preserve its key meaning as concisely as possible.`,
  });

  // Only use the summary if it's actually shorter.
  compacted.push({
    role: msg.role,
    content:
      summary.trim().length < msg.content.length ? summary.trim() : msg.content,
  });
}

Eski oturumu yok etme

Eski oturumun kaynaklarını serbest bırakın ve ardından yeni oturumu oluşturun:

session.destroy();
session = null;

Sıkıştırılmış geçmişle yeni bir oturum oluşturma

Yeni oturuma görüşme bağlamını eklemek için sıkıştırılmış mesajları initialPrompts olarak iletin:

// Collect every language the detector was confident about.
const sessionLangs =
  confidentLangs.size > 0 ? [...confidentLangs] : [navigator.language];

session = await LanguageModel.create({
  expectedInputs: [{ type: 'text', languages: sessionLangs }],
  expectedOutputs: [{ type: 'text', languages: sessionLangs }],
  initialPrompts: compacted,
});

// Re-register the overflow handler on the new session.
session.addEventListener('contextoverflow', () => {
  /* ... */
});

Yeni oturum daha düşük bir contextUsage ile başlar. Sohbet kaldığı yerden devam eder: Model, önceki bağlam olarak özetleri kullandığından önceki konularla ilgili ek soruları yanıtlayabilir.

Hataları işleme

Eski oturum zaten yok edildikten sonra özetleme veya oturum oluşturma işlemi başarısız olursa kullanıcı sohbet etme özelliğini kaybeder. Hiçbir zaman sıkıştırma işlemiyle üzerine yazılmayan ayrı bir fullHistory dizisi tutun ve bunu kurtarma için yedek olarak kullanın:

const history = []; // current session's view, replaced on each compaction
const fullHistory = []; // every original message, never overwritten

// In the catch block:
if (!session) {
  session = await LanguageModel.create({
    initialPrompts: fullHistory.map(({ role, content }) => ({ role, content })),
  });
  session.addEventListener('contextoverflow', () => {
    /* ... */
  });
}

fullHistory işleminden kurtarma, bağlamı tekrar kapasiteye yaklaştırabilir ancak kullanıcı en azından tekrar çalışır duruma gelir ve hemen başka bir sıkıştırma işlemi deneyebilir.

İsteğe bağlı olarak bazı içeriklerin sıkıştırılmasını önleme

Bir iletinin her zaman bağlamda kalması gereken önemli kısımları varsa (ör. kod örnekleri) bunları ayrı olarak işleyin. Aşağıdaki örnekte, bir ileti alternatif düz yazı ve kod çiti segmentlerine ayrılıyor, ardından yalnızca düz yazı bölümleri özetlenirken kod segmentleri olduğu gibi bırakılıyor:

// Splits text into alternating prose and code-fence segments.
// Returns [{ type: 'prose'|'code', content: string }, …]
function splitByCodeFences(text) {
  const parts = [];
  const re = /^```[^\n]*\n[\s\S]*?^```[ \t]*$/gm;
  let lastIndex = 0;
  let match;
  while ((match = re.exec(text)) !== null) {
    if (match.index > lastIndex) {
      parts.push({
        type: 'prose',
        content: text.slice(lastIndex, match.index),
      });
    }
    parts.push({ type: 'code', content: match[0] });
    lastIndex = match.index + match[0].length;
  }
  if (lastIndex < text.length) {
    parts.push({ type: 'prose', content: text.slice(lastIndex) });
  }
  return parts;
}

Demoyu deneyin

Oturum sıkıştırma demosu, Prompt API ile sohbet etmenize ve oturumu istediğiniz zaman sıkıştırmanıza olanak tanır. Token çubuğu, bağlam kullanımını anlık olarak gösterir ve bağlam doldukça rengi değişir. Her sıkıştırmadan sonra, jeton sayılarının öncesi ve sonrası bir günlük girişine kaydedilir. Böylece, azalmayı doğrudan gözlemleyebilirsiniz.

Tam ve sıkıştırılmış ileti dizisi JSON'unu sayfanın alt kısmındaki daraltılabilir Hata ayıklama: İleti dizisi JSON'u bölümünde inceleyebilirsiniz.

Kaynak kodu GitHub'da.