Embeddings
Embeddings
Convierte texto en vectores para búsqueda semántica, recuperación (RAG), recomendaciones, clustering y deduplicación, con los modelos text-embedding-3 de OpenAI a la mitad del precio de OpenAI. Los mismos IDs de modelo, la misma petición y respuesta, los mismos vectores: el código escrito para OpenAI funciona en cuanto cambias la URL base y la clave.
/v1/embeddingsPagas por el texto que envías y los vectores son gratis. Ambos modelos leen hasta 8,192 tokens por entrada. Text Embedding 3 Small es el ideal para empezar: barato, rápido y bueno para la mayoría de búsquedas y casos de RAG. Text Embedding 3 Large es el modelo más grande y preciso, para cuando la calidad de la recuperación importa más que el almacenamiento y el precio.
Inicio rápido
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 10Cualquier SDK de OpenAI sirve: apúntalo a https://api.zurelay.com/v1, usa tu clave de Zurelay y llama a su método embeddings. La respuesta es la de 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 devuelve un embedding por entrada, en el orden en que las enviaste, cada uno con su index. usage.prompt_tokens es lo que se facturó por la petición. Las cabeceras también lo dicen: x-zurelay-model indica el modelo y x-zurelay-input-tokens los tokens, y con x-request-id encuentras la petición en tu registro de peticiones.
Parámetros
modelstringobligatoriotext-embedding-3-smallotext-embedding-3-large.inputstring o arrayobligatorio- Qué puedes convertir en embedding: una cadena, un array de hasta 2,048 cadenas, un array de IDs de token (enteros del tokenizer
cl100k_basede OpenAI) o un array de hasta 2,048 de esos arrays. Cada entrada tiene como máximo 8,192 tokens y ninguna puede ser una cadena vacía. encoding_formatstringfloat(el valor predeterminado): cada embedding es un array de números.base64: cada uno es una cadena base64 de números float32 little-endian, más pequeños y más rápidos de descargar. Consulta Base64.dimensionsinteger- Acorta el vector: de 1 a 1,536 en
text-embedding-3-small, de 1 a 3,072 entext-embedding-3-large. Omítelo para obtener la longitud completa. Consulta Vectores más cortos. userstring- Opcional: un ID del usuario final al que va dirigida la solicitud, como en la API de OpenAI. Se acepta y no cambia nada en los vectores.
Procesamiento por lotes
Envía muchos textos en una sola solicitud: input acepta un array de hasta 2,048 y se devuelven en el mismo orden. Una solicitud con mil textos es mucho más rápida que mil solicitudes, y cuesta lo mismo: pagas por token, no por solicitud. Mantén cada solicitud por debajo de 300,000 tokens en 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 sentDivide en fragmentos los documentos de más de 8,192 tokens antes de generar sus embeddings. Para búsqueda y RAG, los fragmentos de unos cientos de tokens, uno o dos párrafos, suelen encontrar mejores coincidencias que los documentos completos.
Vectores más cortos con dimensions
Los modelos text-embedding-3 están entrenados para que un vector acortado siga funcionando: pide dimensions y obtienes la primera parte del vector completo, renormalizada a longitud 1. Los vectores más cortos ocupan menos almacenamiento y memoria y se buscan más rápido, a cambio de un poco menos de precisión. Text Embedding 3 Large con 1,024 dimensiones ocupa un tercio del espacio de sus 3,072 completas.
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
Con "encoding_format": "base64" cada embedding llega como una cadena base64 de números float32 little-endian en lugar de un array JSON: más pequeño y más rápido de descargar y procesar. Si omites encoding_format, el SDK de Python de OpenAI pide base64 por su cuenta y lo decodifica, así que obtienes floats normales en ambos casos. Si pides base64 tú mismo, obtienes la cadena, para decodificarla así:
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]Búsqueda semántica
Genera los embeddings de tus documentos una vez y guarda los vectores. Para buscar, genera el embedding de la consulta con el mismo modelo y ordena los documentos por su similitud de coseno con ella: cuanto más cerca de 1, más cerca en significado, aunque no tengan ninguna palabra en común. Los vectores de text-embedding-3 tienen longitud 1, así que el producto escalar da el mismo orden.
# 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 firstPara más de unos miles de documentos, guarda los vectores en una base de datos vectorial o un índice vectorial (pgvector, Qdrant, Pinecone, Weaviate, Chroma y similares) y deja que haga el orden.
Recuperación (RAG)
La generación aumentada por recuperación responde a una pregunta a partir de tus propios documentos: busca los pasajes más cercanos a la pregunta y luego pásaselos a un modelo de chat junto con la pregunta. La misma clave de Zurelay sirve para las dos cosas.
# 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 y el AI SDK
Los frameworks con una clase de embeddings de OpenAI funcionan con la URL base y la clave de Zurelay, y los ID de modelo siguen siendo los de 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"])La clase Python OpenAIEmbeddings de LangChain tokeniza los textos por su cuenta de forma predeterminada y envía los ID de token. Zurelay acepta arrays de tokens, así que la configuración predeterminada funciona tal cual.
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?")Con Settings.embed_model configurado, cada índice y cada retriever que crees genera sus embeddings a través de Zurelay. Para el modelo de chat, consulta la guía de 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]));Aplicaciones y almacenes vectoriales
Las aplicaciones que llaman a los embeddings de OpenAI con una URL base configurable funcionan igual: ponla en https://api.zurelay.com/v1, usa tu clave de Zurelay y uno de los ID de modelo de arriba. Esto incluye el motor de embeddings de OpenAI para documentos de Open WebUI, la API de RAG de LibreChat, el nodo Embeddings OpenAI de n8n y el proveedor de modelos compatible con OpenAI de Dify.
Los mismos vectores que OpenAI
Las solicitudes a text-embedding-3-small y text-embedding-3-large se ejecutan en los propios modelos de OpenAI. Comprobamos cada ruta contra la API de OpenAI: para el mismo texto y el mismo modelo, los vectores coinciden con los de OpenAI, con una similitud de coseno de 0.9999 o más. Así que un índice creado con la API de OpenAI sigue funcionando cuando generas los embeddings de tus consultas a través de Zurelay, y uno creado a través de Zurelay funciona con los de OpenAI. Pasar de uno a otro no exige volver a generar los embeddings.
Cambiar de modelo obliga a regenerar los embeddings
Los vectores de modelos distintos no se pueden comparar
text-embedding-3-small no significa nada junto a uno de text-embedding-3-large, ni junto a uno de cualquier otro modelo: cada modelo sitúa el texto en su propio espacio. Así que, para cambiar de modelo, vuelve a generar los embeddings de todo lo que tengas guardado con el nuevo modelo y consulta con ese modelo de ahí en adelante.Por la misma razón, a una solicitud de embeddings siempre responde el modelo que indicaste. El enrutamiento inteligente nunca la pasa a otro modelo, sean cuales sean tus ajustes: si el modelo está caído recibes 503 model_unavailable, para reintentar, en lugar de vectores que no encajan con tu índice.
Límites
- Hasta 2,048 entradas por solicitud.
- Hasta 8,192 tokens en cada entrada, y 300,000 en la solicitud completa.
- No se admiten cadenas vacías.
dimensionsde 1 a la longitud máxima del modelo: 1,536 entext-embedding-3-small, 3,072 entext-embedding-3-large.- Una solicitud que supera un límite se rechaza con un
400que indica el límite, y no cuesta nada. - Una clave limitada a ciertos modelos necesita el modelo de embeddings en su lista. Consulta Límites y reglas de las claves.
Cuánto cuestan los embeddings
Los embeddings se facturan solo por tokens de entrada, contados como los cuenta OpenAI, y los vectores son gratis. Text Embedding 3 Small cuesta $0.01 por 1M de tokens y Text Embedding 3 Large $0.065, la mitad del precio de OpenAI. Un millón de textos de 100 tokens cada uno, 100M de tokens, cuesta $1.00 generar sus embeddings con Text Embedding 3 Small y $6.50 con Text Embedding 3 Large, frente a $2.00 y $13.00 en OpenAI.
No hay mínimo por solicitud: una solicitud de 10 tokens se factura como 10 tokens. Los dimensions más cortos y base64 cuestan lo mismo. Las cabeceras usage y x-zurelay-input-tokens de cada respuesta indican sobre qué se facturó, todas las solicitudes aparecen en tu registro de solicitudes y las que fallan no cuestan nada.
Errores
Los errores llegan con el formato de OpenAI, así que los SDK de OpenAI los lanzan igual que lo harían con OpenAI.
Las claves, el crédito, los presupuestos y los límites de frecuencia dan los mismos errores que cualquier otro endpoint: consulta Errores. Los SDK de OpenAI reintentan los que vale la pena reintentar.
Pruébalo primero
¿Tienes dudas o falta algo? Escribe a nuestro equipo de soporte y te responderemos por email, normalmente en menos de un minuto.