Die Embedding API erzeugt keinen Text, sondern bildet Text auf eine Zahlenfolge ab. Semantische Suche, RAG, Clustering, Deduplizierung und Empfehlungen arbeiten mit dieser Zahlenfolge. Die Integration selbst ist nicht schwer; heikel sind Dimensionen, Batching, Normalisierung und Indexierung – ein Fehler dort verschlechtert die Suchergebnisse unbemerkt.
Dieser Beitrag verwendet eine OpenAI-kompatible Schnittstelle als Beispiel und erklärt Anfrage und Antwort, Aufrufe mit Python und curl, Batch-Strategie, Vektorspeicherung, RAG-Verkettung, häufige Fehler und Migrationsprüfungen.
Hinweis: OpenAI, PostgreSQL und weitere genannte Marken gehören ihren jeweiligen Inhabern. Dieser Beitrag dient nur der technischen Erläuterung und steht in keiner Verbindung zu den betreffenden Anbietern; Schnittstellen, Modelle und Preise richten sich nach der offiziellen Dokumentation und unseren Seiten.
1. Schnittstelle und Authentifizierung
Die OpenAI-kompatible Embedding-Schnittstelle lautet:
POST https://ai.zhongshangqihang.com/v1/embeddings
Authorization: Bearer sk-dein-schluessel
Content-Type: application/json
Die Base URL endet bei /v1; /embeddings nicht selbst anhängen und dann an das SDK übergeben. Das SDK ergänzt den Pfad je nach Methode automatisch; doppeltes Anhängen führt zu 404.
Der Request-Body benötigt mindestens zwei Felder:
{
"model": "text-embedding-3-small",
"input": ["Wer trägt die Rücksendekosten?", "Wer zahlt die Versandkosten der Rücksendung?"]
}
input kann ein einzelner String oder ein String-Array sein. Bei einem Array werden mehrere Vektoren in derselben Reihenfolge zurückgegeben, was sich für Batch-Verarbeitung eignet. Leere Strings werden meist abgelehnt und sollten in der Bereinigungsphase entfernt werden.
2. Anfrage- und Antwortfelder
| Feld | Position | Beschreibung |
|---|---|---|
model |
Anfrage | Pflichtfeld; Modellname gemäß Plattformdokumentation und Modellpreisen |
input |
Anfrage | String oder String-Array; einzelne Eingabe nicht über der Modellobergrenze |
dimensions |
Anfrage | nur bei manchen Modellen; verkürzt die Ausgabedimension |
encoding_format |
Anfrage | meist float, alternativ base64 zur Reduzierung des Übertragungsvolumens |
data[].embedding |
Antwort | Vektor-Array, Reihenfolge entspricht der Eingabe |
data[].index |
Antwort | Position der Eingabe im Array |
usage |
Antwort | prompt_tokens und total_tokens für den Abgleich |
Das Feld index in der Antwort ist wichtig. Bei Retries nach Batch-Fehlern oder beim Zusammenführen paralleler Aufrufe nicht annehmen, dass die Rückgabereihenfolge immer der Eingabe entspricht; die Ausrichtung über index ist zuverlässiger.
3. Python-Aufruf und Ähnlichkeit
Nach Installation des SDK ein minimales Beispiel:
import os
from math import sqrt
from openai import OpenAI
client = OpenAI(
api_key=os.environ["ZSQH_API_KEY"],
base_url="https://ai.zhongshangqihang.com/v1",
)
resp = client.embeddings.create(
model="text-embedding-3-small",
input=["Wer trägt die Rücksendekosten?", "Wer zahlt die Versandkosten der Rücksendung?"],
)
a, b = resp.data[0].embedding, resp.data[1].embedding
cos = sum(x * y for x, y in zip(a, b)) / (
sqrt(sum(x * x for x in a)) * sqrt(sum(y * y for y in b))
)
print(len(a), round(cos, 4), resp.usage.total_tokens)
Der Code prüft drei Dinge zugleich: Der Key funktioniert, die Dimension entspricht der Erwartung, und die Ähnlichkeit zweier ähnlicher Texte ist plausibel. Für Produktionsprojekte NumPy oder die Distanzfunktion der Vektordatenbank verwenden, nicht reines Python auf großen Datenmengen.
4. Dimensionen, Normalisierung und Modellkonsistenz
Übliche Dimensionen von OpenAI-Embedding-Modellen:
text-embedding-3-small: 1536 Dimensionen.text-embedding-3-large: 3072 Dimensionen.text-embedding-ada-002: 1536 Dimensionen.
Der Parameter dimensions kann die Ausgabe der text-embedding-3-Reihe verkürzen, etwa von 3072 auf 1024, um Speicher und Bandbreite zu sparen. Die Verkürzung verliert einen Teil der Information; ob sich das lohnt, mit dem eigenen Evaluationsset prüfen und nicht nur an der Dimensionszahl entscheiden.
Laut OpenAI-Dokumentation sind die Embeddings auf Länge 1 normalisiert, sodass die Kosinusähnlichkeit direkt über das Skalarprodukt berechnet werden kann. Bei selbst betriebenen Modellen, Drittanbieter-Modellen oder manuell gekürzten Dimensionen ist eine erneute L2-Normalisierung nötig. Am sichersten ist dieselbe Normalisierungslogik beim Schreiben und Abfragen, ausdrücklich im Code dokumentiert.
Eine harte Randbedingung: Alle Vektoren in der Vektordatenbank müssen aus demselben Modell, mit derselben Dimension und derselben Normalisierung stammen. Nach einem Modellwechsel dürfen alte Vektoren nicht weiter gemischt werden, sonst sind Ähnlichkeiten nicht vergleichbar.
5. Wie Batch-Anfragen aufgeteilt werden
Batching reduziert HTTP-Overhead, aber größer ist nicht automatisch besser. Die aktuelle OpenAI-Dokumentation nennt als Grenzen: eine einzelne Eingabe bis etwa 8K Token und alle Eingaben einer Anfrage zusammen bis 300.000 Token; maßgeblich sind die Angaben des jeweiligen Anbieters.
In der Praxis nach Token-Budget aufteilen, nicht nach fester Anzahl:
- Text bereinigen: Leerraum, Duplikate und überlange Abschnitte entfernen.
- Mit dem Tokenizer die Token pro Eintrag schätzen; überlange Texte vorher chunken.
- Nach Gesamt-Token-Budget gruppieren, etwa einige zehntausend Token pro Batch, mit Reserve für Retries.
- Bei 429 und 5xx exponentielles Backoff verwenden; 4xx-Parameterfehler nicht blind wiederholen.
- Pro Batch Modell, Dimension, Token und Dauer protokollieren, um Abgleich und Reproduzierbarkeit zu ermöglichen.
Retries sollten idempotent gedacht werden. Als Cache-Schlüssel eignet sich „Text-Hash + Modellname + Dimension“, damit derselbe Text nicht doppelt berechnet wird. Nach einem fehlgeschlagenen Batch zuerst prüfen, welche index bereits erfolgreich waren, und nur die fehlenden nachholen.
6. In die Vektordatenbank schreiben
Am Beispiel von pgvector in PostgreSQL lässt sich das Schema vereinfachen:
CREATE TABLE chunks (
id bigserial PRIMARY KEY,
content text NOT NULL,
source text,
embedding vector(1536)
);
CREATE INDEX ON chunks USING hnsw (embedding vector_cosine_ops);
Abfrage über die Kosinusdistanz:
SELECT id, content
FROM chunks
ORDER BY embedding <=> $1
LIMIT 5;
Neben dem Vektor mindestens speichern: Originaltext, Quelle, Mandant oder Berechtigungsumfang, Chunk-Position, Modellname und Dimension. Ohne diese Metadaten kann die Antwort keine Quelle zitieren und keine Berechtigungsfilter anwenden. Produktiv zusätzlich Indexart, Recall-Parameter, Backup und inkrementelle Aktualisierung berücksichtigen, nicht erst bei größeren Datenmengen.
7. Reihenfolge der RAG-Verkettung
Ein funktionsfähiger RAG-Ablauf sieht meist so aus:
- Dokumente parsen und bereinigen, Kopf- und Fußzeilen sowie Duplikate entfernen.
- Nach Überschrift oder Absatz chunken, mit geringer Überlappung zwischen den Chunks.
- Für jeden Chunk das Embedding aufrufen und batchweise in die Vektordatenbank schreiben.
- Bei einer Nutzerfrage die Frage mit demselben Modell vektorisieren.
- Über Kosinusähnlichkeit Top-K abrufen, dann nach Berechtigung und Quelle filtern.
- Bei Bedarf Keyword-Retrieval für Hybrid-Suche ergänzen oder ein Rerank-Modell einsetzen.
- Suchergebnisse und Frage gemeinsam an das Chat-Modell übergeben und Antworten mit Quellenangabe verlangen.
Für die Chunk-Größe gibt es keine einheitliche Antwort. Bei chinesischen Dokumenten ist ein Start von 300 bis 800 Zeichen üblich, danach anhand der Frage-Antwort-Qualität anpassen. Zu große Chunks machen die Suche unpräzise, zu kleine liefern unvollständigen Kontext. Statt über Parameter zu grübeln, früh ein kleines Evaluationsset mit festen Fragen und Referenzantworten anlegen und bei jeder Änderung durchlaufen lassen.
8. Häufige Fehler und Diagnose
401(Authentifizierung fehlgeschlagen): Key falsch, gelöscht, ohne Bearer übergeben oder Umgebungsvariable leer.404 Not Found: Base URL ohne/v1oder Pfad doppelt zusammengesetzt.model not found: Modellname falsch oder das Konto hat keine Berechtigung für das Modell.400wegen zu langer Eingabe: einzelne Eingabe über der Modellobergrenze; vorher chunken.400wegen leerer Eingabe: Das Array enthält einen leeren String; in der Bereinigungsphase entfernen.429: Rate oder Parallelität überschritten; Parallelität senken und exponentielles Backoff verwenden.- Uneinheitliche Dimensionen: Schreiben und Abfragen nutzen unterschiedliche Modelle oder
dimensions. - Ähnlichkeit durchgehend 0 oder ungewöhnlich nah beieinander: Normalisierung prüfen, falsches Feld gelesen oder Nullvektor gespeichert?
Bei der Diagnose zuerst Modellname, Eingabeanzahl, Länge pro Eintrag und Rückgabedimension ausgeben. Die meisten Probleme liegen nicht an „schlechter Modellqualität“, sondern an einer Inkonsistenz zwischen Anfrage und Speicherung.
9. Migration und Prüfung vor dem Start
Bei der Migration von einer offiziellen API oder einem anderen Gateway zu einem OpenAI-kompatiblen Gateway ändern sich meist nur zwei Dinge: base_url und api_key. Embedding hat jedoch einen zusätzlichen Aufwand: Ändert sich das Modell oder die Dimension, müssen historische Vektoren neu aufgebaut werden.
Vor dem Start mindestens prüfen:
- Unterstützt die neue Plattform den verwendeten Modellnamen und die Dimension?
- Muss die gesamte Datenbank neu vektorisiert werden, und sind Zeitfenster und Kosten dafür akzeptabel?
- Werden Abfrage- und Schreibseite gleichzeitig umgestellt, damit alte und neue Vektoren nicht gemischt werden?
- Gibt es einen stufenweisen Rollout, bei dem ein Teil des Traffics für den Recall-Vergleich umgestellt wird?
- Deckt das Monitoring Fehlerrate, Latenz, Token-Verbrauch und Anteil leerer Ergebnisse ab?
- Gibt es einen Rollback-Pfad, bei dem alter Key und alter Index nach der Umstellung noch einige Zeit erhalten bleiben?
Ändert sich nur die Base URL und bleiben Modell und Dimension gleich, ist die Migration deutlich einfacher; wird auch das Modell gewechselt, sollte sie wie ein Datenneuaufbau geplant werden. Konkrete Modelle und Preise entnehmen Sie den Modellpreisen.
Häufige Fragen
Worin unterscheidet sich die Embedding-Schnittstelle von Chat Completions?
Embedding liefert einen Vektor fester Länge für Retrieval, Clustering und Ähnlichkeitsberechnung; Chat Completions liefert generierten Text. Die Authentifizierung ist meist gleich, Request-Body und Antwortstruktur unterscheiden sich vollständig.
Wie viele Texte können pro Anfrage übergeben werden?
Die Schnittstelle akzeptiert ein String-Array, die eigentliche Grenze sind Gesamt-Token und Länge pro Eintrag. Die aktuelle OpenAI-Dokumentation nennt 300.000 Token pro Anfrage und etwa 8K Token pro Eintrag. Praktische Batches nach Token-Budget schneiden und nicht am Limit entlangfahren.
Müssen Vektoren selbst normalisiert werden?
Wenn die Plattform ausdrücklich angibt, dass die Vektoren normalisiert sind, lässt sich die Kosinusähnlichkeit über das Skalarprodukt berechnen. Bei selbst betriebenen Modellen, manuell gekürzten Dimensionen oder unklarer Herkunft beim Schreiben und Abfragen dieselbe L2-Normalisierung anwenden.
Können alte Vektoren nach einem Embedding-Modellwechsel weiter genutzt werden?
Nicht direkt gemischt. Vektorräume unterschiedlicher Modelle sind nicht vergleichbar; gleiche Dimension bedeutet nicht semantische Übereinstimmung. Nach einem Modellwechsel den Index neu aufbauen und Modellname sowie Dimension in den Metadaten festhalten.
Muss chinesischer Text zuerst segmentiert werden?
Meist nicht. Moderne Embedding-Modelle verarbeiten Rohtext direkt; eine Segmentierung kann sogar Kontext verlieren. Zu behandeln sind Bereinigung, Chunking, Deduplizierung und Längensteuerung.
Nächster Schritt
Wer zunächst eine Anfrage testen möchte, kann über die Registrierungsseite einen Key mit niedrigem Kontingent anlegen und das curl- oder Python-Beispiel auf eigenen Text anpassen. Für die endgültige Auswahl anschließend die Modellpreise prüfen und mit einer kleinen Menge echter Geschäftstexte den Recall vergleichen. Preise und Modelle können sich ändern; maßgeblich ist die aktuelle Darstellung auf unserer Website.
