Embeddings

Embeddings

Ubah teks menjadi vektor untuk pencarian semantik, retrieval (RAG), rekomendasi, clustering, dan deduplikasi, dengan model text-embedding-3 milik OpenAI seharga setengah dari harga OpenAI. ID model sama, request dan response sama, vektor sama: kode yang ditulis untuk OpenAI langsung berjalan begitu Anda mengganti base URL dan key.

POST/v1/embeddings
ModelIDPer 1M token inputHarga OpenAIDimensi
Text Embedding 3 Smalltext-embedding-3-small$0.01$0.021,536, atau kurang
Text Embedding 3 Largetext-embedding-3-large$0.065$0.133,072, atau kurang

Anda membayar untuk teks yang Anda kirim, dan vektornya gratis. Kedua model membaca hingga 8,192 token per input. Text Embedding 3 Small adalah pilihan untuk memulai: murah, cepat, dan cukup untuk sebagian besar kebutuhan pencarian dan RAG. Text Embedding 3 Large adalah model yang lebih besar dan lebih akurat, untuk saat kualitas retrieval lebih penting daripada penyimpanan dan harga.

Mulai cepat

import os
from openai import OpenAI
client = 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 floats
print(len(vector), response.usage.prompt_tokens) # 1536 10

SDK OpenAI apa pun bisa dipakai: arahkan ke https://api.zurelay.com/v1, gunakan key Zurelay Anda, lalu panggil metode embeddings-nya. Responsnya sama seperti dari OpenAI:

Respons (vektor dipersingkat)
{
"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 berisi satu embedding per input, sesuai urutan yang Anda kirim, masing-masing dengan index-nya. usage.prompt_tokens adalah dasar penagihan request tersebut. Header juga menyebutkannya: x-zurelay-model menunjukkan nama model dan x-zurelay-input-tokens jumlah token, sedangkan x-request-id menemukan request itu di log request Anda.

Parameter

modelstringwajib
text-embedding-3-small atau text-embedding-3-large.
inputstring atau arraywajib
Yang bisa di-embed: sebuah string, array berisi hingga 2,048 string, array ID token (bilangan bulat dari tokenizer cl100k_base milik OpenAI), atau array berisi hingga 2,048 array semacam itu. Setiap input maksimal 8,192 token, dan tidak boleh ada yang berupa string kosong.
encoding_formatstring
float (bawaan): setiap embedding berupa array angka. base64: masing-masing berupa string base64 dari angka float32 little-endian, lebih kecil dan lebih cepat diunduh. Lihat Base64.
dimensionsinteger
Perpendek vektor: 1 sampai 1,536 di text-embedding-3-small, 1 sampai 3,072 di text-embedding-3-large. Biarkan kosong untuk panjang penuh. Lihat Vektor lebih pendek.
userstring
Opsional: ID pengguna akhir tujuan permintaan, seperti di API OpenAI. Diterima, dan tidak mengubah apa pun pada vektor.

Batching

Kirim banyak teks dalam satu permintaan: input menerima array hingga 2,048, dan hasilnya kembali dalam urutan yang sama. Satu permintaan berisi seribu teks jauh lebih cepat daripada seribu permintaan, dengan biaya yang sama: Anda membayar per token, bukan per permintaan. Jaga total setiap permintaan di bawah 300,000 token.

# pip install tiktoken
import tiktoken
# The tokenizer text-embedding-3 counts with, to keep each request under the limits
enc = 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 batch
vectors = []
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 sent

Pecah dokumen yang lebih panjang dari 8,192 token menjadi potongan sebelum di-embed. Untuk pencarian dan RAG, potongan beberapa ratus token, satu atau dua paragraf, biasanya menemukan kecocokan lebih baik daripada dokumen utuh.

Vektor lebih pendek dengan dimensions

Model text-embedding-3 dilatih agar vektor yang diperpendek tetap berfungsi: minta dimensions dan Anda mendapat bagian awal vektor penuh, dinormalisasi ulang ke panjang 1. Vektor lebih pendek memakai penyimpanan dan memori lebih sedikit serta lebih cepat dicari, dengan akurasi sedikit berkurang. Text Embedding 3 Large pada 1,024 dimensi hanya memakan sepertiga ruang dari 3,072 dimensi penuhnya.

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)) # 1024
Gunakan satu model dan satu ukuran untuk semua yang Anda bandingkan: vektor dengan panjang berbeda tidak bisa dibandingkan, dan banyak database vektor menetapkan panjangnya saat indeks dibuat. Vektor lebih pendek biayanya sama: harganya per token input.

Base64

Dengan "encoding_format": "base64" setiap embedding kembali sebagai string base64 berisi angka float32 little-endian, bukan array JSON: lebih kecil, dan lebih cepat diunduh serta di-parse. Jika encoding_format tidak diisi, SDK Python OpenAI meminta base64 sendiri dan mendekodenya untuk Anda, jadi Anda tetap mendapat float biasa. Kalau Anda sendiri yang meminta base64, Anda mendapat string-nya, untuk didekode seperti ini:

import base64
import numpy as np
response = 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 numbers
vectors = [np.frombuffer(base64.b64decode(item.embedding), dtype="<f4") for item in response.data]

Embed dokumen Anda sekali lalu simpan vektornya. Untuk mencari, embed kueri dengan model yang sama dan urutkan dokumen berdasarkan cosine similarity terhadapnya: makin dekat ke 1, makin dekat maknanya, meski tak ada kata yang sama. Vektor text-embedding-3 berpanjang 1, jadi dot product memberi urutan yang sama.

# pip install openai numpy
import os
import numpy as np
from openai import OpenAI
client = 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 text
def 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 first

Untuk lebih dari beberapa ribu dokumen, simpan vektor di database vektor atau indeks vektor (pgvector, Qdrant, Pinecone, Weaviate, Chroma, dan sejenisnya) dan biarkan itu yang mengurutkan.

Retrieval (RAG)

Retrieval-augmented generation menjawab pertanyaan dari dokumen Anda sendiri: cari bagian yang paling dekat dengan pertanyaan, lalu serahkan ke model chat bersama pertanyaannya. Kunci Zurelay yang sama dipakai untuk keduanya.

# After the search example above: retrieve, then answer from what was found
question = "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, dan AI SDK

Framework dengan class embeddings dari OpenAI berfungsi dengan base URL dan kunci Zurelay, dan ID modelnya tetap milik OpenAI.

LangChain

# pip install langchain-openai
import os
from langchain_openai import OpenAIEmbeddings
embeddings = 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"])

OpenAIEmbeddings Python dari LangChain secara bawaan menokenkan teks sendiri dan mengirim ID token. Zurelay menerima array token, jadi pengaturan bawaannya langsung berfungsi.

LlamaIndex

# pip install llama-index-embeddings-openai
import os
from llama_index.core import Settings
from llama_index.embeddings.openai import OpenAIEmbedding
Settings.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?")

Dengan Settings.embed_model diatur, setiap indeks dan retriever yang Anda buat melakukan embed lewat Zurelay. Untuk model chat, lihat panduan LlamaIndex.

Vercel AI SDK

// npm install ai @ai-sdk/openai
import { 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]));

Aplikasi dan penyimpanan vektor

Aplikasi yang memanggil embeddings OpenAI dengan base URL yang bisa diatur bekerja dengan cara yang sama: atur ke https://api.zurelay.com/v1, pakai kunci Zurelay Anda dan salah satu ID model di atas. Termasuk mesin embedding OpenAI milik Open WebUI untuk dokumen, RAG API milik LibreChat, node Embeddings OpenAI di n8n, dan penyedia model kompatibel OpenAI milik Dify.

Vektor yang sama dengan OpenAI

Permintaan ke text-embedding-3-small dan text-embedding-3-large berjalan di model milik OpenAI sendiri. Kami memeriksa setiap rute terhadap API OpenAI: untuk teks dan model yang sama, vektornya cocok dengan milik OpenAI, dengan cosine similarity 0.9999 atau lebih. Jadi indeks yang Anda bangun dengan API OpenAI tetap berfungsi saat Anda meng-embed kueri lewat Zurelay, dan indeks yang dibangun lewat Zurelay berfungsi dengan OpenAI. Berpindah di antara keduanya tidak perlu embed ulang.

Ganti model berarti embed ulang

Vektor dari model berbeda tidak bisa dibandingkan

Vektor text-embedding-3-small tidak berarti apa-apa di samping vektor text-embedding-3-large, atau vektor dari model lain mana pun: setiap model menempatkan teks di ruangnya sendiri. Jadi untuk berganti model, embed ulang semua yang sudah Anda simpan dengan model baru, dan mulai saat itu kueri dengan model tersebut.

Karena alasan yang sama, permintaan embeddings selalu dijawab oleh model yang Anda sebutkan. Perutean cerdas tidak pernah meneruskannya ke model lain, apa pun pengaturan Anda: jika model sedang down Anda mendapat 503 model_unavailable, untuk dicoba lagi, bukan vektor yang tidak cocok dengan indeks Anda.

Batas

  • Hingga 2,048 input per permintaan.
  • Hingga 8,192 token di setiap input, dan 300,000 di seluruh permintaan.
  • Tidak boleh ada string kosong.
  • dimensions dari 1 sampai panjang penuh model: 1,536 di text-embedding-3-small, 3,072 di text-embedding-3-large.
  • Permintaan yang melewati batas ditolak dengan 400 yang menyebutkan batasnya, dan tidak dipungut biaya.
  • Kunci yang dibatasi ke model tertentu harus mencantumkan model embedding di daftarnya. Lihat Batas dan aturan kunci.

Membayar embeddings

Embedding ditagih hanya atas token input, dihitung dengan cara OpenAI, dan vektornya gratis. Text Embedding 3 Small berbiaya $0.01 per 1M token dan Text Embedding 3 Large $0.065, setengah harga OpenAI. Sejuta teks berisi 100 token masing-masing, 100M token, hanya $1.00 untuk di-embed dengan Text Embedding 3 Small dan $6.50 dengan Text Embedding 3 Large, dibandingkan $2.00 dan $13.00 di OpenAI.

Tidak ada minimum per request: request 10 token ditagih 10 token. dimensions yang lebih pendek dan base64 biayanya sama. Header usage dan x-zurelay-input-tokens di setiap respons menyebutkan dasar penagihannya, setiap request ada di request log Anda, dan request yang gagal tidak dikenai biaya.

Kesalahan

Error-nya berbentuk seperti milik OpenAI, jadi SDK OpenAI memunculkannya seperti untuk OpenAI.

StatusKodeKapan
400invalid_requestAda field yang hilang atau salah: string kosong, lebih dari 2,048 input, dimensions yang bukan bilangan bulat, atau encoding_format selain float atau base64. Pesannya menyebutkan yang mana.
400invalid_valuedimensions lebih besar dari panjang penuh model.
400context_length_exceededSebuah input melebihi 8,192 token, atau request-nya melebihi 300,000. Pecah teksnya, atau kirim lebih sedikit input sekaligus.
503model_unavailableModel sedang tidak tersedia untuk sementara. Coba lagi setelah jumlah detik pada header retry-after.

Key, kredit, anggaran, dan batas laju menghasilkan error yang sama seperti endpoint lainnya: lihat Error. SDK OpenAI akan mencoba ulang error yang memang layak dicoba ulang.

Coba dulu

Di Playground pada dasbor, pilih model embedding, tulis beberapa teks lalu embed: Anda melihat tiap vektor, token yang ditagih, dan cosine similarity setiap pasangan. Tombol Dapatkan kode menuliskan permintaan yang sama untuk Python, Node.js, atau cURL.

Ada pertanyaan, atau ada yang kurang? Tanyakan kepada tim dukungan kami dan kami akan menjawab lewat email, biasanya dalam satu menit.