GNL
Dokümanlar menüsü
Core · Ücretsiz@gnldev/durable

Model yönlendirme & yedekleme

String model id'sini çözer (resolveModel) ve bir aday listesi üzerinden ilk çalışan modele deterministik olarak düşen (journal'da dondurulan) bir yedekleme zinciri kurar.

Ne işe yarar / ne zaman kullanılır#

Üretimde tek bir model sağlayıcısına bağımlı kalmak risklidir: rate-limit, geçici kesinti veya kota aşımı tüm run'ı düşürebilir. withModelFallback bir aday listesi (ör. önce gpt-4o, olmazsa gpt-4o-mini) tanımlamanızı sağlar; ilk denemede hangi model başarılı olursa o an seçilir ve bu seçim journal'a yazılır.

Kritik nokta: bu seçim kalıcıdır. Aynı runId'nin sonraki adımları veya bir çökmeden sonraki resume'u — geçici arıza geçmiş olsa bile — hep aynı kazanan modele yapışır. Bu, replay determinizmini korur (bir sonraki adımda farklı bir modelin farklı bir cevap üretmesiyle run'ın "dallanmasını" engeller).

Kurulum / import#

Ayrı bir alt-paket yok; @gnldev/durable kök export'undan gelir:

import { withModelFallback, resolveModel, runDurable } from '@gnldev/durable';
import type { FallbackCandidate } from '@gnldev/durable';

Sağlayıcı paketleri (@ai-sdk/openai, @ai-sdk/anthropic, @ai-sdk/google, @ai-sdk/mistral) yalnız resolveModel içeriden lazy import() ile yüklenir — provider lock-in yoktur, kullandığınızı ayrıca kurmanız yeterlidir.

Adım adım kullanım#

1) Adayları tanımlayın — her aday spec (journal'a yazılacak stabil etiket) ve model (AI SDK LanguageModelV2) çiftidir. 2) Journal ve runId ile withModelFallback'i çağırıp dönen sarmalayıcıyı runDurable'a model alanı olarak verin:

import { withModelFallback } from '@gnldev/durable';
const model = withModelFallback([ { model: 'openai:gpt-4o' }, { model: 'openai:gpt-4o-mini' } ], journal, runId);
await runDurable({ runId, journal, model, tools, prompt });

İlk çağrıda GNL adayları sırayla dener; başarılı olan kazanır ve <runId>:cfg:model anahtarına CAS (claim) ile yazılır. Aynı run'ın sonraki her adımı önce journal'daki kaydı okur — kayıt varsa yalnız o kazanan aday denenir, diğerlerine hiç dokunulmaz.

Eğer aday modeli tek bir 'provider/model' string'i olarak tutuyorsanız, önce resolveModel ile gerçek modele çevirip FallbackCandidate şeklinde derleyin:

import { resolveModel, withModelFallback } from '@gnldev/durable';

const candidates = await Promise.all(
  ['openai/gpt-4o', 'anthropic/claude-haiku-4-5'].map(async (spec) => ({
    spec,
    model: await resolveModel(spec),
  })),
);
const model = withModelFallback(candidates, journal, runId);

Sadece tek bir aday verirseniz withModelFallback kısa devre yapar ve doğrudan o modeli döner — üretim/geliştirme arasında geçiş yaparken aynı çağrı şeklini koruyabilirsiniz.

İlgili opt-in: exclusiveModelStep (çift LLM maliyetine kapı)#

Model seçimi ile ilgili ayrı ama komşu bir sorun: aynı runId'nin iki worker'ı eşzamanlı resume edilirse, ikisi de aynı model adımını görüp iki kez gerçek doGenerate çağrısı yapabilir — çift token maliyeti. runDurable/streamDurable'a opt-in exclusiveModelStep verilirse, eşzamanlı bir worker'ın TAZE (startedAt şu andan geriye ttlMs'ten yeni; varsayılan 30 saniye) 'running' model claim'i gördüğünde RunBusyError fırlatılır:

await runDurable({ runId, journal, model, tools, prompt, exclusiveModelStep: { ttlMs: 30_000 } });
// a second concurrent worker that sees a FRESH claim on the same step gets RunBusyError (a duplicate doGenerate is prevented)

STALE bir claim (sahibi çökmüş) mevcut davranışla devam eder — hızlı crash-resume penceresi bu opt-in ile bozulmaz, yalnız gerçekten eşzamanlı/canlı bir rakip worker engellenir.

API referansı#

fnresolveModel

'provider/model' formatındaki string'i (openai, anthropic, google, mistral) ilgili @ai-sdk/* paketinden lazy import ederek gerçek modele çevirir; paket kurulu değilse veya provider tanınmıyorsa açıklayıcı hata fırlatır.

fnwithModelFallback

Aday listesini (candidates), journal ve runId alır; ilk başarılı modeli dener/dondurur ve doGenerate/doStream'i buna göre yönlendiren bir model nesnesi döner.

typeFallbackCandidate

{ spec: string; model: any } — spec journal'a yazılan stabil etiket (ör. 'openai/gpt-4o' veya obje modeller için '#<index>'), model ise gerçek LanguageModelV2.

Dikkat
Fallback seçimi runId başına kalıcıdır: aynı runId'yi farklı bir aday listesiyle tekrar çağırırsanız, journal'da zaten dondurulmuş bir kazanan varsa (listede eşleşen spec bulunduğu sürece) yalnız o denenir — diğer adaylar sessizce atlanır. Yeni bir deneme için farklı bir runId kullanın.
İpucu
withDurableModel bunun DIŞINA sarılır: replay sırasında journal'daki kayıtlı cevap doğrudan döner, fallback mantığı hiç çalışmaz — yani deterministik replay bu davranıştan etkilenmez.