Technischer Leitfaden

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.

26. März 202614 Min. LesezeitOronts Engineering Team

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-QuelleBeispielSchweregrad
SDK-Kopplungopenai.chat.completions.create() in 50 DateienHoch
Prompt-FormatPrompts auf GPT-4-Verhalten optimiert, versagen bei ClaudeHoch
Fine-Tuned ModelleModell mit deinen Daten trainiert, beim Anbieter gehostetSehr hoch
Proprietäre FeaturesAssistants API, Function Calling Format, JSON ModeMittel
Embedding Lock-In100K Dokumente mit text-embedding-3-small eingebettet, inkompatibel mit anderen ModellenSehr hoch
Rate-Limit-ArchitekturSystem auf OpenAIs spezifische Rate Limits und Batching ausgelegtNiedrig

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 abstrahierenWarum
Embedding-Modell (innerhalb eines Projekts)Vektoren sind inkompatibel. Abstraktion hilft nicht.
Fine-Tuned ModellspezifikaFine-Tuning ist von Natur aus anbieterspezifisch
Anbieterspezifische OptimierungenBatching, Caching, Rate-Limit-Handling unterscheiden sich pro Anbieter
Streaming-Format-DetailsIm 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

  1. Provider-SDK in der Geschäftslogik. openai.chat.completions.create() über 50 Dateien verstreut macht einen Wechsel unmöglich. Nutze eine Abstraktionsschicht.

  2. Ein Prompt für alle Modelle. Prompts sind modellspezifisch. Pflege Varianten pro Modellfamilie. Akzeptiere den Wartungsaufwand.

  3. Alles abstrahieren. Über-Abstraktion bringt Komplexität. Abstrahiere das Interface, nicht die Interna.

  4. Keine Evaluierungssuite. Ohne automatisierte Evals weißt du nicht, ob ein Modellwechsel die Qualität verschlechtert, bis Nutzer sich beschweren.

  5. Embedding Lock-In ignorieren. Der Wechsel von Embedding-Modellen erfordert das Neu-Einbetten jedes Dokuments. Plane diese Kosten ein.

  6. 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

KI Vendor Lock-InLLM AbstraktionsschichtMulti-Modell-StrategieKI-AnbieterunabhängigkeitModell-RoutingPrompt-PortabilitätKI-Architektur

Bereit, 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