Routing, Failover und Multi-Modal
Welcher Provider ein Feature ausführt, welche Fallback-Kette greift und ob ein Teil des Verkehrs auf einen Kandidaten läuft, steht im Contract — nicht im Anwendungscode. Diese Seite zeigt, wie das SDK aus dieser Konfiguration routet und welche der Defaults und Optionen dabei wirken.
Multi-Provider-Routing und Failover
Abschnitt betitelt „Multi-Provider-Routing und Failover“Aus dem Contract kommt ein primärer Provider plus eine Fallback-Kette. Der Aufruf-Code benennt keinen Provider; er ruft nur asm.invoke mit der featureId auf. Welche Modelle dahinterstehen, entscheidet die Provider-Konfiguration der freigegebenen Contract-Version.
Pro Aufruf arbeitet das SDK die Slot-Kette der Reihe nach ab — beginnend beim primären Provider, dann jeder Fallback-Slot. Ein Slot gilt als gescheitert und löst den Wechsel zum nächsten aus, wenn:
- der Provider mit einem
5xx-Status antwortet (z. B.500,503), - der Provider die
failoverDeadlineMsüberschreitet (Default 5 s), - ein Netzfehler auftritt.
Bei 429 (Rate-Limit) wartet das SDK zunächst mit exponentiellem Backoff und versucht denselben Provider erneut, bevor es auf den nächsten Slot wechselt. Zusätzlich gilt pro Provider die harte Obergrenze invokeTimeoutMs (Default 30 s); die failoverDeadlineMs wird intern auf diese Obergrenze begrenzt.
Der Wechsel ist transparent: Der Aufruf-Code ändert sich nicht, wenn ein Fallback einspringt. result.data enthält in jedem Fall das gegen das Output-Schema geprüfte Ergebnis.
import { createAsmClient } from '@ai-systems-manager/sdk'
// Die Provider-Konfiguration der freigegebenen Contract-Version legt OpenAI// als primären Provider und Anthropic als Fallback fest. Im Code steht davon// nichts — nur die failoverDeadlineMs lässt sich pro Client oder pro Aufruf// nachregeln.const asm = createAsmClient({ baseUrl: process.env.ASM_BASE_URL!, token: process.env.ASM_FEATURE_TOKEN!, failoverDeadlineMs: 5_000,})
const result = await asm.invoke<{ category: string; urgency: 'low' | 'high' }>( 'feat_email_triage_01HZQ900000000000000000000', { email: 'Need quote for project ASAP', subject: 'urgent quote request' },)console.log('Triage:', result.data)Scheitern alle Slots, wirft das SDK eine AsmError mit dem code ALL_PROVIDERS_EXHAUSTED. Das Feld details.providerChain listet jeden Versuch mit provider, model, latencyMs, success und — bei Fehlschlag — error (mit code, message und optional statusCode).
import { AsmError } from '@ai-systems-manager/sdk'
try { const result = await asm.invoke('feat_email_triage_01HZQ900000000000000000000', input) console.log(result.data)} catch (err) { if (err instanceof AsmError && err.code === 'ALL_PROVIDERS_EXHAUSTED') { for (const attempt of err.details?.providerChain ?? []) { console.error(attempt.provider, attempt.model, attempt.success, attempt.error?.code) } }}Die Failover-Optionen lassen sich sowohl am Client als auch pro Aufruf setzen. Die Aufruf-Option hat Vorrang.
| Option | Default | Bedeutung |
|---|---|---|
failoverDeadlineMs | 5_000 (5 s) | Frist für den primären Provider, bevor das SDK zum nächsten Slot wechselt. |
invokeTimeoutMs | 30_000 (30 s) | Harte Obergrenze pro Provider-Aufruf. Begrenzt zugleich die wirksame failoverDeadlineMs. |
primaryTimeoutMs | gleich invokeTimeoutMs | Per-Aufruf-Override der harten Obergrenze für den primären Slot. |
Phased-Rollout (Canary)
Abschnitt betitelt „Phased-Rollout (Canary)“Trägt die Provider-Konfiguration des Contracts ein providerConfig.routing.trafficSplit mit candidatePct und candidate, verteilt das SDK den Anteil candidatePct der Aufrufe deterministisch auf den Kandidaten; der Rest läuft auf dem primären Provider.
Die Zuordnung ist deterministisch und klebrig (sticky): Das SDK hasht den splitKey aus den Aufruf-Optionen — oder, wenn keiner gesetzt ist, die interne requestId — mit FNV-1a und ordnet den Bucket der Variante zu. Derselbe splitKey landet damit über Sessions hinweg immer auf derselben Variante. Das eignet sich für A/B-Vergleiche pro Benutzer: Übergib eine stabile User-ID als splitKey.
import { createAsmClient } from '@ai-systems-manager/sdk'
const asm = createAsmClient({ baseUrl: process.env.ASM_BASE_URL!, token: process.env.ASM_FEATURE_TOKEN!,})
const userIds = ['user-A', 'user-B', 'user-C']for (const userId of userIds) { const result = await asm.invoke<{ summary: string }>( 'feat_summarizer_01HZQ900000000000000000000', { text: 'Long document …' }, { splitKey: userId }, ) // Dieselbe userId erzeugt immer dieselbe Variante (sticky Routing). console.log(`${userId}: ${result.data.summary.slice(0, 60)}…`)}Scheitert der Kandidat, gibt es in V1 keine eigene Fallback-Kette für ihn: Der Verkehr fällt in die Fallback-Kette des primären Providers zurück (flache Topologie). Den Trafficsplit selbst (Anteil und Kandidat) konfigurierst du im App-Cockpit unter Rollout — diese Oberfläche ist derzeit eine Demo.
Multi-Modal-Eingaben
Abschnitt betitelt „Multi-Modal-Eingaben“Für Bild- oder PDF-Eingaben übergibst du im input ein binäres Feld. Das SDK erkennt automatisch, dass die Eingabe nicht rein textuell ist, und wechselt auf den Messages-Pfad des Vercel AI SDK (eine content-Array-Nachricht mit Text- und Binär-Teilen). Erkannt werden drei Formen eines Feldwerts:
- ein Objekt mit
mimeType,data(einBuffer) und optionalfilename, - direkt ein
Buffer(bzw.Uint8Array), - eine
URL-Instanz.
Alle übrigen, skalaren Felder (string, number, boolean, null) bleiben für die Text-Ersetzung im Prompt-Template verfügbar.
import { readFile } from 'node:fs/promises'import { createAsmClient } from '@ai-systems-manager/sdk'
const png = await readFile('./receipt.png')
const asm = createAsmClient({ baseUrl: process.env.ASM_BASE_URL!, token: process.env.ASM_FEATURE_TOKEN!,})
const result = await asm.invoke<{ vendor: string total: number currency: string}>('feat_receipt_analysis_01HZQ900000000000000000000', { context: 'expense report', image: { mimeType: 'image/png', data: png, filename: 'receipt.png' },})console.log('Receipt:', result.data)Der primäre Provider — und ein zur Eingabe passender Fallback bzw. Kandidat — muss die nötige Fähigkeit unterstützen: vision für Bilder, pdf für application/pdf. Prüft das SDK vorab, dass eine Fähigkeit fehlt, wirft es eine AsmError:
| Fall | Code |
|---|---|
| Primärer Provider unterstützt die Fähigkeit nicht | MULTI_MODAL_NOT_SUPPORTED_BY_PROVIDER |
Kandidat (aus routing.trafficSplit) unterstützt sie nicht | MULTI_MODAL_NOT_SUPPORTED_BY_FALLBACK |
Wo das konfiguriert wird
Abschnitt betitelt „Wo das konfiguriert wird“Primärer Provider, Fallback-Kette und Trafficsplit sind Teil der Provider-Konfiguration des Contracts und werden auf der Plattform gepflegt — siehe Modelle und Provider. Im SDK-Code stehen weder Provider noch Modelle; der Aufruf bleibt unverändert, wenn sich das Routing ändert. Pro Aufruf lässt sich nur das Verhalten nachregeln: failoverDeadlineMs, primaryTimeoutMs, splitKey und ein signal (siehe SDK einrichten und Fehlerbehandlung).