Embeddings
Embeddings
Verwandle Text in Vektoren für semantische Suche, Retrieval (RAG), Empfehlungen, Clustering und Deduplizierung – mit OpenAI’s text-embedding-3 Modellen zum halben OpenAI-Preis. Gleiche Model-IDs, gleicher Request und gleiche Response, gleiche Vektoren: Code, der für OpenAI geschrieben wurde, läuft, sobald du die Base URL und den Key änderst.
/v1/embeddingsDu zahlst für den Text, den du sendest – die Vektoren sind gratis. Beide Modelle lesen bis zu 8,192 Tokens pro Input. Text Embedding 3 Small ist der Einstieg: günstig, schnell und gut für die meisten Such- und RAG-Anwendungen. Text Embedding 3 Large ist das größere, genauere Modell – für Fälle, in denen Retrieval-Qualität mehr zählt als Speicher und Preis.
Schnellstart
import osfrom openai import OpenAIclient = OpenAI( base_url="https://api.zurelay.com/v1", api_key=os.environ["ZURELAY_API_KEY"],)response = client.embeddings.create( model="text-embedding-3-small", input="The food was delicious and the waiter was friendly.",)vector = response.data[0].embedding # a list of 1,536 floatsprint(len(vector), response.usage.prompt_tokens) # 1536 10Jedes OpenAI SDK funktioniert: richte es auf https://api.zurelay.com/v1, nutz deinen Zurelay Key und ruf die Embeddings-Methode auf. Die Antwort ist die von OpenAI:
{ "object": "list", "data": [ { "object": "embedding", "index": 0, "embedding": [-0.0022748, -0.0093183, 0.0158532, ..., -0.0028842] } ], "model": "text-embedding-3-small", "usage": { "prompt_tokens": 10, "total_tokens": 10 }}data enthält ein Embedding pro Input, in der Reihenfolge, in der du sie gesendet hast, jeweils mit seinem index. usage.prompt_tokens ist das, worüber der Request abgerechnet wurde. Die Header verraten es auch: x-zurelay-model nennt das Modell und x-zurelay-input-tokens die Tokens, und mit x-request-id findest du den Request in deinem Request Log.
Parameter
modelstringerforderlichtext-embedding-3-smallodertext-embedding-3-large.inputString oder Arrayerforderlich- Was du einbetten kannst: einen String, ein Array mit bis zu 2,048 Strings, ein Array von Token-IDs (Ganzzahlen aus OpenAI’s
cl100k_baseTokenizer) oder ein Array mit bis zu 2,048 solchen Arrays. Jeder Input hat maximal 8,192 Tokens, und keiner darf ein leerer String sein. encoding_formatstringfloat(der Standard): Jedes Embedding ist ein Array aus Zahlen.base64: Jedes ist ein base64-String aus float32-Zahlen in Little-Endian, kleiner und schneller herunterzuladen. Siehe Base64.dimensionsinteger- Kürze den Vektor: 1 bis 1,536 bei
text-embedding-3-small, 1 bis 3,072 beitext-embedding-3-large. Lass den Parameter weg für die volle Länge. Siehe Kürzere Vektoren. userstring- Optional: eine ID für die Endnutzerin oder den Endnutzer, für die oder den die Anfrage gedacht ist, wie in OpenAIs API. Wird akzeptiert und ändert nichts an den Vektoren.
Mehrere Texte pro Anfrage
Schick viele Texte in einer Anfrage: input nimmt ein Array mit bis zu 2,048, und sie kommen in derselben Reihenfolge zurück. Eine Anfrage mit tausend Texten ist viel schneller als tausend Anfragen und kostet dasselbe: du zahlst pro Token, nicht pro Anfrage. Bleib pro Anfrage insgesamt unter 300,000 Tokens.
# pip install tiktokenimport tiktoken# The tokenizer text-embedding-3 counts with, to keep each request under the limitsenc = tiktoken.get_encoding("cl100k_base")def batches(texts, max_inputs=2048, max_tokens=300_000): batch, tokens = [], 0 for text in texts: count = len(enc.encode(text)) if batch and (len(batch) == max_inputs or tokens + count > max_tokens): yield batch batch, tokens = [], 0 batch.append(text) tokens += count if batch: yield batchvectors = []for batch in batches(texts): response = client.embeddings.create(model="text-embedding-3-small", input=batch) vectors += [item.embedding for item in response.data] # in the order sentTeile Dokumente, die länger als 8,192 Tokens sind, in Chunks auf, bevor du sie embeddest. Für Suche und RAG finden Chunks von ein paar hundert Tokens, ein oder zwei Absätze, meist bessere Treffer als ganze Dokumente.
Kürzere Vektoren mit dimensions
Die text-embedding-3-Modelle sind so trainiert, dass ein gekürzter Vektor weiter funktioniert: Fragst du dimensions an, bekommst du den ersten Teil des vollen Vektors, neu auf Länge 1 normalisiert. Kürzere Vektoren brauchen weniger Speicher und Arbeitsspeicher und suchen schneller, bei etwas weniger Genauigkeit. Text Embedding 3 Large mit 1,024 Dimensionen braucht ein Drittel des Platzes seiner vollen 3,072.
response = client.embeddings.create( model="text-embedding-3-large", input="The food was delicious and the waiter was friendly.", dimensions=1024,)print(len(response.data[0].embedding)) # 1024Base64
Mit "encoding_format": "base64" kommt jedes Embedding als base64-String aus float32-Zahlen in Little-Endian zurück statt als JSON-Array: kleiner und schneller herunterzuladen und zu parsen. Lässt du encoding_format weg, fragt OpenAIs Python SDK selbst nach base64 und dekodiert es für dich, du bekommst also so oder so normale Floats. Fragst du selbst nach base64, bekommst du den String, den du so dekodierst:
import base64import numpy as npresponse = client.embeddings.create( model="text-embedding-3-small", input=["First text", "Second text"], encoding_format="base64",)# Each embedding is a base64 string of little-endian float32 numbersvectors = [np.frombuffer(base64.b64decode(item.embedding), dtype="<f4") for item in response.data]Semantische Suche
Embede deine Dokumente einmal und speichere die Vektoren. Zum Suchen embedest du die Query mit demselben Modell und sortierst die Dokumente nach Kosinus-Ähnlichkeit dazu: je näher an 1, desto näher in der Bedeutung, auch ohne gemeinsame Wörter. text-embedding-3-Vektoren haben Länge 1, das Skalarprodukt liefert also dieselbe Reihenfolge.
# pip install openai numpyimport osimport numpy as npfrom openai import OpenAIclient = OpenAI(base_url="https://api.zurelay.com/v1", api_key=os.environ["ZURELAY_API_KEY"])MODEL = "text-embedding-3-small"docs = [ "To change your password, open Settings, choose Security and click Change password.", "Invoices are emailed on the first day of each month and can be downloaded under Billing.", "Invite teammates from the Team page; each person signs in with their own email.", "API keys can be limited to a monthly budget, a rate limit and a list of models.",]def embed(texts): response = client.embeddings.create(model=MODEL, input=texts) return np.array([item.embedding for item in response.data])doc_vectors = embed(docs) # embed once, and store the vectors beside the textdef search(query, k=2): query_vector = embed([query])[0] # The vectors have length 1, so the dot product is the cosine similarity scores = doc_vectors @ query_vector best = np.argsort(-scores)[:k] return [(docs[i], float(scores[i])) for i in best]for text, score in search("How can I change my password?"): print(f"{score:.3f} {text}") # the password article comes firstBei mehr als ein paar tausend Dokumenten legst du die Vektoren in einer Vektor-Datenbank oder einem Vektor-Index ab (pgvector, Qdrant, Pinecone, Weaviate, Chroma und ähnliche) und lässt sie das Ranking machen.
Retrieval (RAG)
Retrieval-augmented Generation beantwortet eine Frage aus deinen eigenen Dokumenten: Such die Passagen, die der Frage am nächsten sind, und gib sie zusammen mit der Frage an ein Chat-Modell. Derselbe Zurelay-Key macht beides.
# After the search example above: retrieve, then answer from what was foundquestion = "How do I stop a key from spending too much?"notes = "\n".join(text for text, _ in search(question))answer = client.chat.completions.create( model="gpt-6-luna", messages=[ { "role": "system", "content": "Answer from these notes only. If they don't say, say so.\n\n" + notes, }, {"role": "user", "content": question}, ],)print(answer.choices[0].message.content)LangChain, LlamaIndex und das AI SDK
Frameworks mit einer OpenAI-Embeddings-Klasse funktionieren mit Zurelays Base-URL und deinem Key, und die Modell-IDs bleiben die von OpenAI.
LangChain
# pip install langchain-openaiimport osfrom langchain_openai import OpenAIEmbeddingsembeddings = OpenAIEmbeddings( model="text-embedding-3-small", base_url="https://api.zurelay.com/v1", api_key=os.environ["ZURELAY_API_KEY"],)query_vector = embeddings.embed_query("How can I change my password?")doc_vectors = embeddings.embed_documents(["First document", "Second document"])LangChains Python-OpenAIEmbeddings tokenisiert Texte standardmäßig selbst und schickt die Token-IDs. Zurelay nimmt Token-Arrays an, die Standardeinstellungen funktionieren also unverändert.
LlamaIndex
# pip install llama-index-embeddings-openaiimport osfrom llama_index.core import Settingsfrom llama_index.embeddings.openai import OpenAIEmbeddingSettings.embed_model = OpenAIEmbedding( model="text-embedding-3-small", api_base="https://api.zurelay.com/v1", api_key=os.environ["ZURELAY_API_KEY"],)vector = Settings.embed_model.get_text_embedding("How can I change my password?")Mit gesetztem Settings.embed_model embeddet jeder Index und jeder Retriever, den du baust, über Zurelay. Zum Chat-Modell siehe den LlamaIndex-Leitfaden.
Vercel AI SDK
// npm install ai @ai-sdk/openaiimport { createOpenAI } from "@ai-sdk/openai";import { cosineSimilarity, embed, embedMany } from "ai";const zurelay = createOpenAI({ baseURL: "https://api.zurelay.com/v1", apiKey: process.env.ZURELAY_API_KEY,});const model = zurelay.embedding("text-embedding-3-small");const { embeddings } = await embedMany({ model, values: ["First document", "Second document"] });const { embedding } = await embed({ model, value: "How can I change my password?" });console.log(cosineSimilarity(embedding, embeddings[0]));Apps und Vektor-Stores
Apps, die OpenAIs Embeddings mit einer einstellbaren Base-URL aufrufen, funktionieren genauso: setz sie auf https://api.zurelay.com/v1, nutze deinen Zurelay-Key und eine der Modell-IDs oben. Das gilt für Open WebUIs OpenAI-Embedding-Engine für Dokumente, die RAG-API von LibreChat, den Node Embeddings OpenAI von n8n und den OpenAI-kompatiblen Model-Provider von Dify.
Dieselben Vektoren wie OpenAI
Anfragen an text-embedding-3-small und text-embedding-3-large laufen auf OpenAIs eigenen Modellen. Wir haben jede Route gegen OpenAIs API geprüft: bei gleichem Text und Modell stimmen die Vektoren mit denen von OpenAI überein, mit einer Kosinus-Ähnlichkeit von 0.9999 oder mehr. Ein Index, den du mit OpenAIs API gebaut hast, funktioniert also weiter, wenn du deine Queries über Zurelay embeddest, und einer, der über Zurelay gebaut wurde, funktioniert mit OpenAI. Der Wechsel zwischen beiden braucht kein Re-Embedding.
Modellwechsel heißt neu embedden
Vektoren aus verschiedenen Modellen lassen sich nicht vergleichen
text-embedding-3-small-Vektor bedeutet nichts neben einem text-embedding-3-large-Vektor oder einem aus irgendeinem anderen Modell: jedes Modell ordnet Text in seinem eigenen Raum an. Um das Modell zu wechseln, embeddest du also alles Gespeicherte neu mit dem neuen Modell und suchst ab dann mit diesem Modell.Aus demselben Grund beantwortet immer das Modell deine Embeddings-Anfrage, das du angegeben hast. Smart Routing gibt sie nie an ein anderes Modell weiter, egal welche Einstellungen du hast: Ist das Modell nicht erreichbar, bekommst du 503 model_unavailable, zum erneuten Versuchen, statt Vektoren, die nicht zu deinem Index passen.
Limits
- Bis zu 2,048 Inputs pro Anfrage.
- Bis zu 8,192 Tokens pro Input und 300,000 in der ganzen Anfrage.
- Keine leeren Strings.
dimensionsvon 1 bis zur vollen Länge des Modells: 1,536 beitext-embedding-3-small, 3,072 beitext-embedding-3-large.- Eine Anfrage über einem Limit wird mit einem
400abgelehnt, das das Limit nennt, und kostet nichts. - Ein Key, der auf bestimmte Modelle beschränkt ist, braucht das Embedding-Modell auf seiner Liste. Siehe Key-Limits und Regeln.
Was Embeddings kosten
Embeddings werden nur auf Input-Tokens abgerechnet, gezählt wie OpenAI zählt, und die Vektoren sind gratis. Text Embedding 3 Small kostet $0.01 pro 1M Tokens und Text Embedding 3 Large $0.065, die Hälfte von OpenAIs Preis. Eine Million Texte mit je 100 Tokens, also 100M Tokens, kosten $1.00 zum Embedden mit Text Embedding 3 Small und $6.50 mit Text Embedding 3 Large – gegenüber $2.00 und $13.00 bei OpenAI.
Es gibt kein Minimum pro Request: Ein Request mit 10 Tokens wird mit 10 Tokens abgerechnet. Kürzere dimensions und base64 kosten gleich viel. Die Header usage und x-zurelay-input-tokens jeder Antwort sagen, worauf abgerechnet wurde, jeder Request steht in deinem Request-Log, und fehlgeschlagene Requests kosten nichts.
Fehler
Fehler kommen in OpenAIs Format, deshalb werfen OpenAIs SDKs sie genau so, wie sie es für OpenAI tun würden.
Keys, Guthaben, Budgets und Rate Limits liefern dieselben Fehler wie jeder andere Endpoint: siehe Fehler. Die SDKs von OpenAI wiederholen die Anfragen, bei denen sich ein neuer Versuch lohnt.
Probier es zuerst aus
Fragen oder fehlt etwas? Frag unser Support-Team und wir antworten per E-Mail, meist innerhalb einer Minute.