Embeddings
Embeddings
Transformez du texte en vecteurs pour la recherche sémantique, la récupération (RAG), les recommandations, le clustering et la déduplication, avec les modèles text-embedding-3 d'OpenAI à la moitié du prix d'OpenAI. Mêmes ID de modèles, mêmes requêtes et réponses, mêmes vecteurs : le code écrit pour OpenAI fonctionne dès que vous changez l'URL de base et la clé.
/v1/embeddingsVous payez pour le texte que vous envoyez, et les vecteurs sont gratuits. Les deux modèles lisent jusqu'à 8,192 tokens par entrée. Text Embedding 3 Small est celui par lequel commencer : bon marché, rapide et efficace pour la plupart des usages de recherche et de RAG. Text Embedding 3 Large est le modèle plus grand et plus précis, à choisir quand la qualité de la récupération compte plus que le stockage et le prix.
Démarrage rapide
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 10N'importe quel SDK OpenAI fonctionne : pointez-le vers https://api.zurelay.com/v1, utilisez votre clé Zurelay et appelez sa méthode embeddings. La réponse est celle d'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 contient un embedding par entrée, dans l'ordre où vous les avez envoyées, chacun avec son index. C'est usage.prompt_tokens qui a servi de base à la facturation. Les en-têtes le disent aussi : x-zurelay-model indique le modèle, x-zurelay-input-tokens les tokens, et x-request-id permet de retrouver la requête dans votre journal de requêtes.
Paramètres
modelstringrequistext-embedding-3-smalloutext-embedding-3-large.inputchaîne ou tableaurequis- Ce que vous pouvez envoyer : une chaîne, un tableau de 2,048 chaînes maximum, un tableau d'ID de tokens (entiers issus du tokenizer
cl100k_based'OpenAI), ou un tableau de 2,048 tels tableaux maximum. Chaque entrée fait au plus 8,192 tokens, et aucune ne peut être une chaîne vide. encoding_formatstringfloat(par défaut) : chaque embedding est un tableau de nombres.base64: chacun est une chaîne base64 de nombres float32 little-endian, plus compacte et plus rapide à télécharger. Voir Base64.dimensionsinteger- Raccourcissez le vecteur : de 1 à 1,536 sur
text-embedding-3-small, de 1 à 3,072 surtext-embedding-3-large. Omettre pour garder la longueur complète. Voir Vecteurs plus courts. userstring- Facultatif : un ID pour l’utilisateur final à qui la requête s’adresse, comme dans l’API d’OpenAI. Accepté, sans aucun effet sur les vecteurs.
Traitement par lots
Envoyez plusieurs textes en une seule requête : input accepte un tableau allant jusqu’à 2,048 entrées, et elles reviennent dans le même ordre. Une requête avec mille textes est bien plus rapide que mille requêtes, et coûte pareil : vous payez au token, pas à la requête. Gardez chaque requête sous 300,000 tokens au total.
# 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 sentDécoupez les documents de plus de 8,192 tokens en morceaux avant de les transformer en embeddings. Pour la recherche et le RAG, des morceaux de quelques centaines de tokens, un paragraphe ou deux, trouvent généralement de meilleures correspondances que des documents entiers.
Des vecteurs plus courts avec dimensions
Les modèles text-embedding-3 sont entraînés pour qu’un vecteur raccourci fonctionne toujours : demandez dimensions et vous obtenez la première partie du vecteur complet, renormalisée à une longueur de 1. Les vecteurs plus courts prennent moins de stockage et de mémoire et la recherche est plus rapide, pour un peu moins de précision. Text Embedding 3 Large en 1,024 dimensions occupe un tiers de l’espace de ses 3,072 dimensions complètes.
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
Avec "encoding_format": "base64", chaque embedding revient sous forme de chaîne base64 de nombres float32 little-endian au lieu d’un tableau JSON : plus compacte, et plus rapide à télécharger et à analyser. Si vous omettez encoding_format, le SDK Python d’OpenAI demande lui-même le base64 et le décode pour vous : vous obtenez des floats dans les deux cas. Si vous demandez le base64 vous-même, vous recevez la chaîne, à décoder comme ceci :
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]Recherche sémantique
Transformez vos documents en embeddings une fois et stockez les vecteurs. Pour chercher, transformez la requête avec le même modèle et classez les documents par similarité cosinus avec elle : plus la valeur est proche de 1, plus le sens est proche, même sans aucun mot en commun. Les vecteurs text-embedding-3 ont une longueur de 1, donc le produit scalaire donne le même classement.
# 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 firstAu-delà de quelques milliers de documents, gardez les vecteurs dans une base de données vectorielle ou un index vectoriel (pgvector, Qdrant, Pinecone, Weaviate, Chroma et autres) et laissez-le faire le classement.
Récupération (RAG)
La génération augmentée par récupération répond à une question à partir de vos propres documents : cherchez les passages les plus proches de la question, puis transmettez-les à un modèle de chat avec la question. La même clé Zurelay fait les deux.
# 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 et le AI SDK
Les frameworks dotés d’une classe d’embeddings OpenAI fonctionnent avec l’URL de base et la clé de Zurelay, et les ID de modèles restent ceux d’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"])Le OpenAIEmbeddings Python de LangChain tokenise les textes lui-même par défaut et envoie les ID de tokens. Zurelay accepte les tableaux de tokens, donc les réglages par défaut fonctionnent tels quels.
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?")Une fois Settings.embed_model défini, chaque index et retriever que vous créez calcule ses embeddings via Zurelay. Pour le modèle de chat, voir le guide LlamaIndex.
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]));Applications et bases vectorielles
Les applications qui appellent les embeddings d’OpenAI avec une URL de base configurable fonctionnent de la même façon : mettez https://api.zurelay.com/v1, utilisez votre clé Zurelay et l’un des ID de modèles ci-dessus. C’est le cas du moteur d’embeddings OpenAI d’Open WebUI pour les documents, de l’API RAG de LibreChat, du nœud Embeddings OpenAI de n8n et du fournisseur de modèles compatible OpenAI de Dify.
Les mêmes vecteurs qu’OpenAI
Les requêtes vers text-embedding-3-small et text-embedding-3-large passent par les modèles d’OpenAI eux-mêmes. Nous avons vérifié chaque route contre l’API d’OpenAI : pour le même texte et le même modèle, les vecteurs correspondent à ceux d’OpenAI, avec une similarité cosinus de 0.9999 ou plus. Un index construit avec l’API d’OpenAI continue donc de fonctionner quand vous transformez vos requêtes en embeddings via Zurelay, et un index construit via Zurelay fonctionne avec celle d’OpenAI. Passer de l’une à l’autre ne demande aucune ré-indexation.
Changer de modèle impose de recalculer les embeddings
Les vecteurs de modèles différents ne sont pas comparables
text-embedding-3-small ne signifie rien à côté d’un vecteur text-embedding-3-large, ou d’un vecteur de n’importe quel autre modèle : chaque modèle place le texte dans son propre espace. Pour changer de modèle, recalculez donc les embeddings de tout ce que vous avez stocké avec le nouveau modèle, et interrogez avec ce modèle ensuite.Pour la même raison, une requête d’embeddings est toujours traitée par le modèle que vous avez nommé. Le routage intelligent ne la confie jamais à un autre modèle, quels que soient vos réglages : si le modèle est indisponible, vous recevez 503 model_unavailable, à réessayer, plutôt que des vecteurs qui ne correspondent pas à votre index.
Limites
- Jusqu’à 2,048 entrées par requête.
- Jusqu’à 8,192 tokens par entrée, et 300,000 pour la requête entière.
- Pas de chaînes vides.
dimensionsde 1 à la longueur complète du modèle : 1,536 surtext-embedding-3-small, 3,072 surtext-embedding-3-large.- Une requête qui dépasse une limite est refusée avec
400qui précise la limite, et ne coûte rien. - Une clé limitée à certains modèles doit avoir le modèle d’embeddings dans sa liste. Voir Limites et règles des clés.
Payer les embeddings
Les embeddings sont facturés sur les tokens d’entrée uniquement, comptés comme OpenAI les compte, et les vecteurs sont gratuits. Text Embedding 3 Small coûte $0.01 par 1M tokens et Text Embedding 3 Large $0.065, la moitié du prix d’OpenAI. Un million de textes de 100 tokens chacun, soit 100M tokens, coûtent $1.00 à vectoriser avec Text Embedding 3 Small et $6.50 avec Text Embedding 3 Large, contre $2.00 et $13.00 chez OpenAI.
Aucun minimum par requête : une requête de 10 tokens est facturée 10 tokens. Les plus courts dimensions et le base64 coûtent pareil. Les en-têtes usage et x-zurelay-input-tokens de chaque réponse indiquent ce qui a été facturé, chaque requête apparaît dans votre journal des requêtes, et les requêtes en échec ne coûtent rien.
Erreurs
Les erreurs ont le format d’OpenAI, donc les SDK d’OpenAI les lèvent comme ils le feraient pour OpenAI.
Les clés, le crédit, les budgets et les limites de débit renvoient les mêmes erreurs que tous les autres endpoints : voir Erreurs. Les SDK d’OpenAI relancent automatiquement celles qui valent la peine d’être relancées.
Essayez d’abord
Une question ou un élément manquant ? Contactez notre équipe d’assistance et nous vous répondrons par e-mail, généralement en moins d’une minute.