Embeddings power semantic search, recommendations, clustering and the retrieval step of RAG.
An embedding turns a piece of text into a long list of numbers (a vector) so that texts with similar meaning get similar vectors. "How do I reset my password?" and "I forgot my login" end up close together even though they share no words.
Call client.embeddings.create(model=..., input=...). input can be one string or a list of strings; each result is in response.data[i].embedding. Send lists in one call rather than one call per string.
The current models are text-embedding-3-small (cheap, 1,536 numbers per vector) and text-embedding-3-large (more accurate, 3,072 numbers). Each input can be up to 8,192 tokens. The dimensions parameter returns shorter vectors, which saves storage with a small loss in quality.
To compare two vectors use cosine similarity: a score near 1 means very similar meaning, near 0 unrelated. OpenAI's vectors are normalised (length 1), so cosine similarity is just the dot product, the sum of the pairwise products.
Rules that save pain:
- Use the same model for your stored documents and your queries; vectors from different models can't be compared.
- Store vectors once (in a database or a vector store) instead of recomputing.
- If you shorten vectors yourself, normalise them again.
For a managed alternative where OpenAI stores and searches the vectors for you, see file search.
Example
from openai import OpenAI
client = OpenAI()
docs = ["How to reset your password", "Shipping times to Europe",
"Changing the email on your account"]
query = "I forgot my login"
resp = client.embeddings.create(model="text-embedding-3-small",
input=docs + [query])
vectors = [d.embedding for d in resp.data]
doc_vecs, q = vectors[:-1], vectors[-1]
def cosine(a, b): # vectors are normalised
return sum(x * y for x, y in zip(a, b))
ranked = sorted(zip(docs, doc_vecs), key=lambda p: cosine(q, p[1]), reverse=True)
for text, vec in ranked:
print(f"{cosine(q, vec):.3f} {text}")
# highest score: How to reset your passwordRemember
client.embeddings.createreturns one vector per input- text-embedding-3-small / -large;
dimensionsshortens vectors - Cosine similarity compares meaning; never mix models