KI-Systeme ohne Vendor Lock-In: Was du abstrahieren solltest (und was nicht)
Wie du KI-Architekturen entwirfst, die einen Anbieterwechsel überleben. Abstraktionsschichten, Prompt-Portabilität, Multi-Modell-Routing, evaluationsgetriebene Entwicklung und wann Lock-In die richtige Wahl ist.
Die Lock-In-Falle
Jedes KI-Projekt fängt mit einem Anbieter an. OpenAI, Anthropic oder ein lokales Modell. Das SDK wandert in die Codebasis. Anbieterspezifische Features (Function Calling Format, JSON Mode, System-Prompt-Verhalten) werden fest in die Geschäftslogik eingebaut. Sechs Monate später willst du den Anbieter wechseln (Kosten, Performance, Compliance) und stellst fest, dass der Wechsel die halbe Anwendung umschreiben erfordert.
Wir haben KI-Systeme gebaut, die mehrere Anbieter gleichzeitig nutzen, und haben mitten im Projekt den Anbieter gewechselt, ohne die Geschäftslogik anzufassen. Dieser Artikel beschreibt die Architektur, die das möglich macht, und die ehrlichen Trade-offs dabei.
Für übergreifende KI-Architekturmuster schau dir unseren KI-Systeme-Guide und den KI-Orchestrierungs-Guide an.
Was Lock-In verursacht
| Lock-In-Quelle | Beispiel | Schweregrad |
|---|---|---|
| SDK-Kopplung | openai.chat.completions.create() in 50 Dateien | Hoch |
| Prompt-Format | Prompts auf GPT-4-Verhalten optimiert, versagen bei Claude | Hoch |
| Fine-Tuned Modelle | Modell mit deinen Daten trainiert, beim Anbieter gehostet | Sehr hoch |
| Proprietäre Features | Assistants API, Function Calling Format, JSON Mode | Mittel |
| Embedding Lock-In | 100K Dokumente mit text-embedding-3-small eingebettet, inkompatibel mit anderen Modellen | Sehr hoch |
| Rate-Limit-Architektur | System auf OpenAIs spezifische Rate Limits und Batching ausgelegt | Niedrig |
Die Abstraktionsschicht, die funktioniert
Eine gute Abstraktionsschicht hat drei Komponenten: ein einheitliches Interface für Modellaufrufe, eine Prompt-Verwaltungsschicht und ein Evaluations-Framework.
// Einheitliches LLM-Interface
interface LlmProvider {
generate(request: LlmRequest): Promise<LlmResponse>;
stream(request: LlmRequest): AsyncIterable<LlmChunk>;
embed(texts: string[]): Promise<number[][]>;
}
interface LlmRequest {
model: string;
messages: Message[];
temperature?: number;
maxTokens?: number;
responseFormat?: 'text' | 'json';
tools?: ToolDefinition[];
}
interface LlmResponse {
text: string;
usage: { promptTokens: number; completionTokens: number };
finishReason: string;
model: string;
provider: string;
latencyMs: number;
}
Jeder Anbieter implementiert dieses Interface:
class OpenAiProvider implements LlmProvider {
async generate(request: LlmRequest): Promise<LlmResponse> {
const response = await this.client.chat.completions.create({
model: request.model,
messages: this.convertMessages(request.messages),
temperature: request.temperature,
max_tokens: request.maxTokens,
response_format: request.responseFormat === 'json'
? { type: 'json_object' } : undefined,
});
return this.convertResponse(response);
}
}
class AnthropicProvider implements LlmProvider {
async generate(request: LlmRequest): Promise<LlmResponse> {
const response = await this.client.messages.create({
model: request.model,
system: this.extractSystemMessage(request.messages),
messages: this.convertMessages(request.messages),
temperature: request.temperature,
max_tokens: request.maxTokens ?? 4096,
});
return this.convertResponse(response);
}
}
Die Geschäftslogik nutzt das Interface, niemals das Provider-SDK direkt:
// Geschäftslogik: anbieterunabhängig
async function generateCustomerResponse(ctx: Context, ticket: string): Promise<string> {
const provider = ctx.getLlmProvider(); // aus Konfiguration aufgelöst
const response = await provider.generate({
model: ctx.getModelForUseCase('customer-support'),
messages: [
{ role: 'system', content: SUPPORT_SYSTEM_PROMPT },
{ role: 'user', content: ticket },
],
temperature: 0.3,
});
return response.text;
}
Wechsel von OpenAI zu Anthropic: Konfiguration ändern. Null Code-Änderungen in der Geschäftslogik.
Das Prompt-Portabilitätsproblem
Prompts sind nicht zwischen Modellen portabel. Ein Prompt, der für GPT-4 optimiert ist, kann bei Claude schlechtere Ergebnisse liefern, und umgekehrt. Modelle interpretieren Anweisungen unterschiedlich, behandeln Randfälle unterschiedlich und haben unterschiedliche Stärken.
Die Lösung: Prompt-Varianten pro Modellfamilie.
const SUPPORT_PROMPTS: Record<string, string> = {
'openai': `You are a customer support assistant. Be concise and helpful.
When you don't know the answer, say so clearly.
Always reference the customer's order number.`,
'anthropic': `You are a customer support assistant.
<instructions>
- Be concise and helpful
- When you don't know the answer, say so clearly
- Always reference the customer's order number
</instructions>`,
'local': `### System
You are a customer support assistant.
### Rules
1. Be concise and helpful
2. When you don't know the answer, say so clearly
3. Always reference the customer's order number`,
};
function getPrompt(useCase: string, provider: string): string {
return PROMPTS[useCase][provider] || PROMPTS[useCase]['default'];
}
Das bedeutet Wartungsaufwand (mehrere Prompt-Versionen), aber so ist die Realität. Ein einzelner Prompt für alle Modelle heißt, auf mindestens einem Modell Qualitätseinbußen zu akzeptieren.
Multi-Modell-Routing
Verschiedene Aufgaben haben verschiedene Anforderungen. Klassifikation braucht Geschwindigkeit. Generierung braucht Qualität. Embedding braucht Konsistenz. Leite jede Aufgabe an das richtige Modell weiter.
const MODEL_ROUTING: Record<string, ModelConfig> = {
'classification': {
primary: { provider: 'openai', model: 'gpt-4o-mini' },
fallback: { provider: 'anthropic', model: 'claude-haiku-4-5-20251001' },
reason: 'Schnell, günstig, gut genug für Klassifikation',
},
'generation': {
primary: { provider: 'anthropic', model: 'claude-sonnet-4-20250514' },
fallback: { provider: 'openai', model: 'gpt-4o' },
reason: 'Beste Qualität für Langform-Generierung',
},
'embedding': {
primary: { provider: 'openai', model: 'text-embedding-3-small' },
fallback: null, // Embedding-Modelle kann man nicht wechseln, ohne alles neu einzubetten
reason: 'Konsistenz: Alle Embeddings müssen dasselbe Modell verwenden',
},
'summarization': {
primary: { provider: 'anthropic', model: 'claude-haiku-4-5-20251001' },
fallback: { provider: 'openai', model: 'gpt-4o-mini' },
reason: 'Schnell und günstig für Zusammenfassungen',
},
};
Die Routing-Konfiguration ist von der Geschäftslogik getrennt. Welches Modell die Zusammenfassung übernimmt, ist eine Konfigurationsänderung, keine Code-Änderung.
Embedding Lock-In: Am schwersten zu lösen
Embeddings sind die stärkste Form von Lock-In. Sobald du 100K Dokumente mit text-embedding-3-small eingebettet hast, erfordert der Wechsel zu einem anderen Embedding-Modell, alles neu einzubetten. Die Vektoren sind zwischen Modellen inkompatibel (unterschiedliche Dimensionen, unterschiedliche semantische Räume).
Gegenmaßnahmen:
- Quelldokumente zusammen mit Embeddings speichern (damit du neu einbetten kannst)
- Nachverfolgen, welches Embedding-Modell pro Dokument verwendet wurde
- Budget für Neu-Embedding einplanen, wenn du einen Anbieterwechsel planst
- Open-Source Embedding-Modelle (sentence-transformers) für Portabilität in Betracht ziehen
Für mehr zu Embedding-Architekturen und Vektor-Suche, schau dir unseren Vektor-Sucharchitektur-Guide und den Enterprise RAG-Systeme Guide an.
Evaluationsgetriebene Entwicklung
Der Schlüssel zu einem sicheren Anbieterwechsel: Evaluiere gegen Aufgaben, nicht gegen Modelle. Wenn deine Evaluierungssuite testet "Geht die Antwort korrekt auf das Problem des Kunden ein?" statt "Entspricht das Output dem GPT-4-Format?", kannst du Modelle sicher wechseln.
interface EvalCase {
input: string;
expectedBehavior: string; // Was das Output TUN soll, nicht was es SAGEN soll
criteria: EvalCriterion[];
}
interface EvalCriterion {
name: string;
check: (output: string, context: EvalCase) => boolean | number;
}
const SUPPORT_EVALS: EvalCase[] = [
{
input: "I haven't received my order #12345",
expectedBehavior: "Acknowledge the issue, reference order number, offer next steps",
criteria: [
{ name: 'references_order', check: (out) => out.includes('12345') },
{ name: 'acknowledges_issue', check: (out) => /sorry|apologize|understand/i.test(out) },
{ name: 'offers_action', check: (out) => /check|investigate|track|follow up/i.test(out) },
{ name: 'reasonable_length', check: (out) => out.length > 50 && out.length < 500 },
],
},
];
// Evaluierungen gegen ein beliebiges Modell ausführen
async function runEvalSuite(provider: LlmProvider, model: string): Promise<EvalResults> {
const results = [];
for (const evalCase of SUPPORT_EVALS) {
const output = await provider.generate({
model,
messages: [
{ role: 'system', content: SUPPORT_SYSTEM_PROMPT },
{ role: 'user', content: evalCase.input },
],
});
const scores = evalCase.criteria.map(c => ({
name: c.name,
passed: c.check(output.text, evalCase),
}));
results.push({ input: evalCase.input, scores });
}
return summarize(results);
}
Führe die Eval-Suite vor dem Modellwechsel aus. Wenn das neue Modell mit akzeptablen Ergebnissen besteht, ist der Wechsel sicher. Wenn nicht, weißt du genau, welche Verhaltensweisen sich verschlechtert haben.
Dieses Muster ist eng verwandt mit dem, was wir in unserem KI-Observability-Guide und unserem KI-Governance-Guide beschreiben.
Was du NICHT abstrahieren solltest
Nicht alles sollte abstrahiert werden. Über-Abstraktion bringt Komplexität ohne Nutzen.
| Nicht abstrahieren | Warum |
|---|---|
| Embedding-Modell (innerhalb eines Projekts) | Vektoren sind inkompatibel. Abstraktion hilft nicht. |
| Fine-Tuned Modellspezifika | Fine-Tuning ist von Natur aus anbieterspezifisch |
| Anbieterspezifische Optimierungen | Batching, Caching, Rate-Limit-Handling unterscheiden sich pro Anbieter |
| Streaming-Format-Details | Im Provider-Adapter behandeln, nicht in der Abstraktion |
Die Abstraktion sollte abdecken: Modellauswahl, Prompt-Routing, Response-Parsing, Kostentracking und Fallback-Logik. Sie sollte NICHT versuchen, alle Anbieter identisch zu machen. Das sind sie nicht, und so zu tun als ob, erzeugt Bugs.
Wenn du wissen willst, wie wir diese Muster in realen Systemen anwenden, schau dir unseren Software Engineering Guide und den Systemarchitektur-Guide an.
Wann Lock-In die richtige Entscheidung ist
Manchmal ist es die richtige geschäftliche Entscheidung, sich an einen Anbieter zu binden:
- Fine-Tuning erfordert Commitment zu einem Anbieter. Das trainierte Modell ist nicht portabel.
- Mengenrabatte von einem einzelnen Anbieter können die Kosten deutlich senken.
- Compliance kann einen bestimmten Anbieter erfordern (Datenhaltung, Zertifizierungen).
- Time-to-Market heißt, anbieterspezifische Features ohne Abstraktions-Overhead zu nutzen.
Der Kern: Triff die Lock-In-Entscheidung bewusst, nicht zufällig. Wenn du dich entscheidest, OpenAIs Assistants API zu nutzen, weil es 3 Monate Entwicklungszeit spart, ist das ein valider Trade-off. Wenn du es nutzt, weil du nicht an Abstraktion gedacht hast, ist das technische Schulden.
Für Compliance-Überlegungen speziell im DACH-Raum, schau dir unseren DSGVO-Leitfaden und unsere KI-DSGVO-Compliance-Analyse an. Unsere Methodik beschreibt, wie wir solche Architekturentscheidungen im Projektkontext treffen.
Häufige Fehler
-
Provider-SDK in der Geschäftslogik.
openai.chat.completions.create()über 50 Dateien verstreut macht einen Wechsel unmöglich. Nutze eine Abstraktionsschicht. -
Ein Prompt für alle Modelle. Prompts sind modellspezifisch. Pflege Varianten pro Modellfamilie. Akzeptiere den Wartungsaufwand.
-
Alles abstrahieren. Über-Abstraktion bringt Komplexität. Abstrahiere das Interface, nicht die Interna.
-
Keine Evaluierungssuite. Ohne automatisierte Evals weißt du nicht, ob ein Modellwechsel die Qualität verschlechtert, bis Nutzer sich beschweren.
-
Embedding Lock-In ignorieren. Der Wechsel von Embedding-Modellen erfordert das Neu-Einbetten jedes Dokuments. Plane diese Kosten ein.
-
Versehentliches Lock-In. Die schlimmste Art. Anbieterspezifische Features nutzen, ohne zu bemerken, dass du eine Abhängigkeit schaffst.
Wir beschreiben verwandte Fehlermuster in unserem KI-Fehlermodi-Guide und unserem Human-in-the-Loop KI Guide.
Wichtigste Erkenntnisse
-
Abstrahiere das Interface, nicht die Implementierung. Ein einheitliches
LlmProvider-Interface mit anbieterspezifischen Adaptern. Geschäftslogik ruft das Interface auf. -
Prompts sind nicht portabel. Pflege Prompt-Varianten pro Modellfamilie. Ein einzelner Prompt über alle Modelle bedeutet irgendwo Qualitätsverlust.
-
Leite verschiedene Aufgaben an verschiedene Modelle. Klassifikation an ein schnelles Modell, Generierung an ein genaues Modell, Embeddings an ein konsistentes Modell. Konfigurationsgesteuert, nicht codegesteuert.
-
Evaluiere gegen Aufgaben, nicht gegen Modelle. Wenn deine Eval-Suite Verhalten testet ("Wird die Bestellnummer referenziert?") statt Format, kannst du Modelle sicher wechseln.
-
Embedding ist das am schwersten zu lösende Lock-In. Quelldokumente speichern. Nachverfolgen, welches Modell verwendet wurde. Budget für Neu-Embedding einplanen.
-
Manchmal ist Lock-In die richtige Wahl. Fine-Tuning, Mengenrabatte und Compliance können es rechtfertigen. Mach es zu einer bewussten Entscheidung.
Wir entwerfen anbieterunabhängige KI-Architekturen als Teil unserer KI-Services und Beratungspraxis. Schau dir auch unsere Lösungen und Anwendungsfälle an. Wenn du Hilfe bei der KI-Architektur brauchst, sprich mit unserem Team oder fordere ein Angebot an.
Behandelte Themen
Verwandte Guides
Unternehmenshandbuch zu Agentischen KI-Systemen
Technischer Leitfaden zu agentischen KI-Systemen in Unternehmen. Erfahre mehr ueber Architektur, Faehigkeiten und Anwendungen autonomer KI-Agenten.
Guide lesenDer komplette Leitfaden zur KI-Orchestrierung
Technischer Leitfaden zur KI-Orchestrierung in der Produktion. Lerne Request-Routing, Modellauswahl, Fallback-Strategien und Load-Balancing-Patterns.
Guide lesenAgentic Commerce: Wie du KI-Agenten sicher einkaufen lässt
Wie du gesteuerten, KI-initiierten Handel designst. Policy Engines, HITL-Freigabe-Gates, HMAC-Quittungen, Idempotenz, Tenant-Scoping und das vollständige Agentic Checkout Protocol.
Guide lesenBereit, produktionsreife KI-Systeme zu bauen?
Unser Team ist spezialisiert auf produktionsreife KI-Systeme. Lass uns besprechen, wie wir deinem Unternehmen helfen können.
Gespräch starten