Dokümanlar menüsü
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ı#
resolveModel'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.
withModelFallbackAday 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.
FallbackCandidate{ 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.
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.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.