Kit unterstützt vier KI-Provider über ein einheitliches Interface. Jeder Provider implementiert dieselbe abstrakte
BaseProvider-Klasse — ein Wechsel des Providers erfordert nur das Ändern einer Umgebungsvariable. Diese Seite behandelt die Provider-Einrichtung, Modellkonfiguration, Auto-Erkennung, Fallback-Ketten und Fähigkeiten.Schnelleinrichtung
Mit einem einzigen API-Schlüssel in
apps/boilerplate/.env.local funktionieren sowohl LLM-Chat als auch RAG-Chat sofort. Keine Konfiguration von AI_PROVIDER oder AI_MODEL nötig — Kit verwendet sinnvolle Standardwerte.Verfügbare Provider
API-Schlüssel:
OPENAI_API_KEY Standardmodell: gpt-5-nano Base-URL-Override: OPENAI_BASE_URL| Modell | Kontext | Eingabe (pro 1M) | Ausgabe (pro 1M) | Optimal für |
|---|---|---|---|---|
gpt-5.2 | 400K | $1,75 | $14,00 | Neuestes Flaggschiff-Reasoning |
gpt-5 | 400K | $1,25 | $10,00 | Coding und agentische Aufgaben |
gpt-5-mini | 400K | $0,25 | $2,00 | Klar definierte Aufgaben |
gpt-5-nano | 400K | $0,05 | $0,40 | Standard — schnell, günstigster |
gpt-4.1 | 1M | $2,00 | $8,00 | Komplexe Aufgaben, Coding |
gpt-4.1-mini | 1M | $0,40 | $1,60 | Effizienter Coding |
o3 | 200K | $2,00 | $8,00 | Tiefgreifendes Reasoning |
o4-mini | 200K | $1,10 | $4,40 | Reasoning mit kleinem Budget |
OpenAI ist für RAG-Embeddings (
text-embedding-3-small) erforderlich, auch wenn ein anderer Provider für den Chat verwendet wird.Auto-Erkennung
Wenn
AI_PROVIDER nicht gesetzt ist, wählt Kit automatisch den Provider basierend auf den verfügbaren API-Schlüsseln aus. Die Erkennungsreihenfolge lautet: Anthropic → OpenAI → Google → xAI.src/lib/ai/config.ts — Provider Auto-Detection
export function getActiveProvider(): AIProvider | null {
// If provider is explicitly set, use it (AI_API_KEY can serve as its key)
if (aiConfig.AI_PROVIDER) {
return aiConfig.AI_PROVIDER
}
// Auto-detect based on available API keys (Anthropic preferred)
if (aiConfig.ANTHROPIC_API_KEY) return 'anthropic'
if (aiConfig.OPENAI_API_KEY) return 'openai'
if (aiConfig.GOOGLE_AI_API_KEY) return 'google'
if (aiConfig.XAI_API_KEY) return 'xai'
return null
}
Um einen bestimmten Provider zu erzwingen, setze
AI_PROVIDER explizit:bash
# Anthropic erzwingen, auch wenn OpenAI-Schlüssel vorhanden ist
AI_PROVIDER=anthropic
Modell-Aliases
Kit bietet benutzerfreundliche Aliases für Modellnamen. Verwende
claude statt claude-sonnet-4-5-20250929 oder gpt4 statt gpt-4.1:src/lib/ai/config.ts — Model Aliases
export const MODEL_ALIASES: Record<string, string> = {
// OpenAI aliases
gpt5: 'gpt-5',
'gpt5.2': 'gpt-5.2',
'gpt5-mini': 'gpt-5-mini',
'gpt5-nano': 'gpt-5-nano',
gpt4: 'gpt-4.1',
'gpt4-mini': 'gpt-4.1-mini',
'gpt-4': 'gpt-4.1',
o3: 'o3',
'o4-mini': 'o4-mini',
// Anthropic aliases
claude: 'claude-sonnet-4-5-20250929',
'claude-opus': 'claude-opus-4-6-20260205',
'claude-sonnet': 'claude-sonnet-4-5-20250929',
'claude-haiku': 'claude-haiku-4-5-20251001',
opus: 'claude-opus-4-6-20260205',
sonnet: 'claude-sonnet-4-5-20250929',
haiku: 'claude-haiku-4-5-20251001',
// Google aliases
gemini: 'gemini-2.5-flash',
'gemini-pro': 'gemini-2.5-pro',
'gemini-flash': 'gemini-2.5-flash',
'gemini-lite': 'gemini-2.5-flash-lite',
'gemini-3': 'gemini-3-flash-preview',
// xAI aliases
grok: 'grok-4-1-fast-reasoning',
'grok-code': 'grok-code-fast-1',
'grok-fast': 'grok-4-fast-reasoning',
'grok-4.1': 'grok-4-1-fast-reasoning',
}
Aliases funktionieren überall — API-Routen, Hooks und Konfiguration. Übergib
model: 'claude' oder model: 'gemini-pro' und Kit löst sie automatisch zur vollständigen Modell-ID auf.Provider-Factory
Die Provider-Factory erstellt und cached Provider-Instanzen. Sie validiert die Konfiguration mit Zod, erstellt die richtige Provider-Klasse und cached Instanzen anhand eines SHA-256-Hashes des API-Schlüssels:
src/lib/ai/provider-factory.ts — Factory with Cache
export function createAIProvider(config: ProviderConfig): BaseProvider {
// Validate configuration
const validation = ProviderConfigSchema.safeParse(config)
if (!validation.success) {
const errors = validation.error.issues.map((err) => ({
field: err.path.join('.'),
message: err.message,
}))
throw new ValidationError('Invalid provider configuration', errors)
}
const validatedConfig = validation.data
// Check cache
const cacheKey = createCacheKey(validatedConfig)
const cached = providerCache.get(cacheKey)
if (cached) {
return cached
}
// Create new provider instance
let provider: BaseProvider
switch (validatedConfig.provider) {
case 'openai':
provider = new OpenAIProvider(validatedConfig)
break
case 'anthropic':
provider = new AnthropicProvider(validatedConfig)
break
case 'google':
provider = new GoogleProvider(validatedConfig)
break
case 'xai':
provider = new XAIProvider(validatedConfig)
break
default:
// This should never happen due to validation, but TypeScript needs it
throw new InvalidProviderError(validatedConfig.provider)
}
// Cache the provider instance
providerCache.set(cacheKey, provider)
return provider
}
Wesentliche Verhaltensweisen:
- Validierung zuerst — Zod-Schema validiert Provider, API-Schlüssel und Modell, bevor eine Instanz erstellt wird
- Cache nach Konfigurations-Hash — Derselbe Provider + API-Schlüssel + Modell gibt die gecachte Instanz zurück
- Switch-Anweisung — Ordnet Provider-String der konkreten Klasse zu (OpenAI, Anthropic, Google, xAI)
Fallback-Ketten
Wenn der bevorzugte Provider nicht verfügbar ist, fällt Kit über einen Bewertungsalgorithmus auf die beste verfügbare Alternative zurück. Jeder Provider wird basierend auf den Anforderungen der Anfrage bewertet:
src/lib/ai/provider-factory.ts — Provider Selection
export interface ProviderRequirements {
needsVision?: boolean
needsEmbeddings?: boolean
needsFunctions?: boolean
needsLargeContext?: boolean
preferCheap?: boolean
preferFast?: boolean
}
/**
* Select the best provider based on requirements
*/
export function selectProvider(
requirements: ProviderRequirements = {}
): AIProvider {
const available = getAvailableProviders()
if (available.length === 0) {
throw new ValidationError('No AI providers configured', [
{
field: 'API_KEYS',
message: 'At least one provider API key must be set',
},
])
}
// Score each provider based on requirements
const scores: Record<AIProvider, number> = {
openai: 0,
anthropic: 0,
google: 0,
xai: 0,
}
for (const provider of available) {
let score = 10 // Base score for being available
if (requirements.needsVision) {
if (
provider === 'openai' ||
provider === 'anthropic' ||
provider === 'google'
) {
score += 5
}
}
if (requirements.needsEmbeddings) {
if (provider === 'openai' || provider === 'google') {
score += 5
}
}
if (requirements.needsFunctions) {
// All providers support functions
score += 1
}
if (requirements.needsLargeContext) {
if (provider === 'anthropic' || provider === 'google') {
score += 5 // Both have 1M+ context windows
}
}
if (requirements.preferCheap) {
if (provider === 'google') {
score += 10 // Gemini Flash is very cheap
} else if (provider === 'openai') {
score += 5 // GPT-4o-mini is cheap
}
}
if (requirements.preferFast) {
if (provider === 'openai' || provider === 'google') {
score += 5
}
}
scores[provider] = score
}
// Find provider with highest score
let bestProvider: AIProvider = available[0]
let bestScore = scores[bestProvider]
for (const provider of available) {
if (scores[provider] > bestScore) {
bestProvider = provider
bestScore = scores[provider]
}
}
return bestProvider
}
Das Bewertungssystem berücksichtigt:
| Anforderung | Beste Kandidaten | Bonus-Punkte |
|---|---|---|
needsVision | OpenAI, Anthropic, Google | +5 |
needsEmbeddings | OpenAI, Google | +5 |
needsLargeContext | Anthropic, Google (1M+) | +5 |
preferCheap | Google (+10), OpenAI (+5) | +5 bis +10 |
preferFast | OpenAI, Google | +5 |
Jeder verfügbare Provider erhält einen Basis-Score von 10. Der Provider mit dem höchsten Gesamtscore wird ausgewählt.
Provider-Fähigkeiten
Nicht alle Provider unterstützen alle Funktionen. Die Fähigkeitsmatrix hilft Kit, informierte Fallback-Entscheidungen zu treffen:
| Fähigkeit | OpenAI | Anthropic | xAI | |
|---|---|---|---|---|
| Streaming | Ja | Ja | Ja | Ja |
| Functions/Tools | Ja | Ja | Ja | Ja |
| Vision | Ja | Ja | Ja | Nein |
| Embeddings | Ja | Nein | Ja | Nein |
| System Messages | Ja | Ja | Ja | Ja |
| Max. Kontext | 1M | 200K (1M Beta) | 1M | 2M |
Die RAG-Suche verwendet OpenAIs Embedding-Modell (konfigurierbar über
AI_EMBEDDING_MODEL, Standard: text-embedding-3-small), unabhängig vom aktiven Chat-Provider. Stelle sicher, dass OPENAI_API_KEY gesetzt ist (oder AI_API_KEY als Fallback), wenn du das RAG-System verwendest — auch mit Anthropic oder Google als primärem Provider.Reasoning-Modell-Behandlung
GPT-5-Familie und o-Series-Modelle sind Reasoning-Modelle mit besonderen Parameter-Einschränkungen. Das
isReasoningModel-Flag auf ModelInfo steuert das Laufzeitverhalten:| Modell | Reasoning | Temperature | Standard maxTokens |
|---|---|---|---|
| GPT-5, GPT-5.2, GPT-5 Mini, GPT-5 Nano | Ja | Nicht unterstützt | 16.384 |
| o3, o4-mini | Ja | Nicht unterstützt | 16.384 |
| GPT-4.1 | Nein | 0,7 (Standard) | 1.000 |
Wesentliche Einschränkungen:
- Temperature wird nicht unterstützt — das Übergeben an Reasoning-Modelle löst eine SDK-Warnung aus und kann das Verhalten verschlechtern. Kit lässt
temperaturebei Reasoning-Modellen vollständig weg. - maxTokens deckt SOWOHL internes Reasoning ALS AUCH sichtbare Ausgabe ab — Reasoning-Modelle verwenden den Großteil des Token-Budgets für interne Gedankenketten. Der Standard von 1.000 ist viel zu niedrig; Kit verwendet 16.384 für Reasoning-Modelle.
- Symptom eines zu niedrigen maxTokens:
finishReason: 'length'mit 0 Ausgabe-Tokens → leere Antwort für den Benutzer.
typescript
// Reasoning-bewusstes Parameter-Handling (openai.ts)
const isReasoning = modelInfo?.isReasoningModel === true
streamText({
...(isReasoning ? {} : { temperature: options.temperature ?? 0.7 }),
maxTokens: options.maxTokens ?? (isReasoning ? 16384 : 1000),
})
Streaming-Antwort-Diagnose
streamText() aus dem Vercel AI SDK gibt lazy Promises zurück, die sich nach dem Stream-Ende auflösen. Kit liest diese für Diagnosezwecke:| Eigenschaft | Typ | Zweck |
|---|---|---|
result.finishReason | Promise<string> | Grund für das Stream-Ende ('stop', 'length', 'content_filter') |
result.usage | Promise<object> | Token-Anzahlen (promptTokens, completionTokens) |
result.warnings | Warning[] | Nicht unterstützte Parameter, Modell-Deprecations |
finishReason-Werte:
| Wert | Bedeutung | Maßnahme |
|---|---|---|
'stop' | Normaler Abschluss | Keine |
'length' | Token-Budget erschöpft | maxTokens erhöhen |
'content_filter' | Provider hat Antwort blockiert | Content-Policy prüfen |
Kit protokolliert eine Warnung, wenn der Stream mit 0 Inhalts-Chunks oder einem Nicht-
'stop'-Finish-Reason endet. Diese Diagnosedaten sind für das Debuggen leerer KI-Antworten unverzichtbar.Benutzerdefinierte Base-URLs
Jeder Provider unterstützt eine benutzerdefinierte Base-URL für Proxys, selbst gehostete Modelle oder alternative Endpunkte:
| Variable | Standard | Zweck |
|---|---|---|
OPENAI_BASE_URL | https://api.openai.com/v1 | OpenAI-API-Proxy oder kompatibler Endpunkt |
ANTHROPIC_BASE_URL | https://api.anthropic.com | Anthropic-API-Proxy |
GOOGLE_AI_BASE_URL | https://generativelanguage.googleapis.com/v1 | Google-AI-Proxy |
XAI_BASE_URL | https://api.x.ai/v1 | xAI-API-Proxy |
OPENAI_ORG_ID | — | OpenAI-Organisations-ID für die Abrechnung |
Fehlerbehandlung und Wiederholungsversuche
Alle Provider teilen dieselbe Wiederholungslogik aus
BaseProvider. Fehlgeschlagene Anfragen werden mit exponential Backoff wiederholt:src/lib/ai/providers/base-provider.ts — Retry Configuration
export abstract class BaseProvider {
protected readonly provider: AIProvider
protected readonly apiKey: string
protected readonly baseURL?: string
protected readonly timeout: number
protected readonly retryConfig: RetryConfig
protected defaultModel: string
protected defaultTemperature: number
protected defaultMaxTokens: number
constructor(config: ProviderConfig) {
this.provider = config.provider
this.apiKey = config.apiKey
this.baseURL = config.baseURL
this.timeout = config.timeout ?? 30000 // 30 seconds default
this.defaultModel = config.model ?? this.getDefaultModel()
this.defaultTemperature = config.defaultTemperature ?? 0.7
this.defaultMaxTokens = config.defaultMaxTokens ?? 1000
this.retryConfig = {
maxRetries: config.maxRetries ?? 3,
baseDelay: 1000,
maxDelay: 10000,
backoffFactor: 2,
}
}
Das Wiederholungsverhalten:
- Max. Wiederholungen: 3 (pro Provider konfigurierbar)
- Basis-Verzögerung: 1.000 ms
- Max. Verzögerung: 10.000 ms (Obergrenze)
- Backoff-Faktor: 2× (1s → 2s → 4s)
- Jitter: 0–30 % zufällige Variation zur Vermeidung des Thundering-Herd-Problems
- Timeout: 30 Sekunden pro Anfrage (konfigurierbar)
Nur wiederholbare Fehler lösen Wiederholungsversuche aus — Netzwerk-Timeouts und 5xx-Antworten. Client-Fehler (400, 401, 403) schlagen sofort fehl.
Die Fehlerklassen-Hierarchie bietet strukturierte Fehlerinformationen:
| Fehlerklasse | Wann | Wiederholbar |
|---|---|---|
AIProviderError | Basisklasse für alle Provider-Fehler | Unterschiedlich |
NetworkError | Verbindungsfehler, DNS-Fehler | Ja |
TimeoutError | Anfrage überschreitet Timeout | Ja |
ValidationError | Ungültige Konfiguration oder Anfrage | Nein |
InvalidProviderError | Unbekannter Provider-String | Nein |