OpenAI Embeddings Guide 2025: Semantic Search, RAG & Vector Storage
OpenAI's text-embedding-3 models turn text into semantic vectors, powering semantic search, RAG pipelines, and recommendation systems. This guide covers every model option, the full RAG pipeline from chunk to generation, vector storage integrations, and a pricing comparison against alternatives.
What Are Embeddings?
An embedding model converts text into a fixed-length numeric vector (e.g., 1536 numbers). Semantically similar texts produce vectors that are close together in vector space — measured by cosine similarity (1.0 = identical meaning, 0.0 = unrelated, -1.0 = opposite). This enables search without keyword matching: "car" and "automobile" will be retrieved together even though they share no characters.
Common applications: semantic search, RAG (Retrieval-Augmented Generation), recommendation engines, duplicate detection, clustering, and classification.
OpenAI Embedding Models Compared
| Model | Dimensions | Price (1M tokens) | Best for |
|---|---|---|---|
| text-embedding-3-small | 1536 | $0.02 | Default choice — best value |
| text-embedding-3-large | 3072 | $0.13 | Maximum accuracy (legal/medical/enterprise) |
| text-embedding-ada-002 | 1536 | $0.10 | Legacy only — do not use for new projects |
text-embedding-3-small outperforms ada-002 on MTEB benchmarks and costs 5x less. Always use text-embedding-3-small as the default.
Generating Embeddings
Python — single embedding
from openai import OpenAI
import numpy as np
client = OpenAI() # uses OPENAI_API_KEY env var
response = client.embeddings.create(
model="text-embedding-3-small",
input="The quick brown fox jumps over the lazy dog",
)
vector = response.data[0].embedding # list of 1536 floats
print(f"Dimensions: {len(vector)}") # 1536 Cosine similarity between two texts
def cosine_similarity(a: list, b: list) -> float:
a, b = np.array(a), np.array(b)
return float(np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b)))
texts = ["I love programming in Python", "Python coding is my passion"]
embeddings = [
client.embeddings.create(model="text-embedding-3-small", input=t).data[0].embedding
for t in texts
]
print(cosine_similarity(embeddings[0], embeddings[1])) # ~0.93 Building a RAG Pipeline
RAG connects an LLM to a vector knowledge base. The four phases:
- Chunk — split documents into 300-500 token chunks with ~50 token overlap
- Embed — embed each chunk with text-embedding-3-small
- Store — upsert vectors into a vector DB (Pinecone / Qdrant / Chroma / pgvector)
- Retrieve & Generate — at query time, embed the question, find top-K similar chunks, inject them into the LLM prompt
Minimal RAG with ChromaDB
from openai import OpenAI
import chromadb
client = OpenAI()
chroma = chromadb.EphemeralClient()
collection = chroma.get_or_create_collection("docs")
# --- Indexing ---
docs = [
"vLLM uses PagedAttention for efficient KV cache management.",
"OpenAI embeddings are generated via the /v1/embeddings endpoint.",
"Pinecone is a managed vector database with a generous free tier.",
]
embeddings = client.embeddings.create(
model="text-embedding-3-small",
input=docs,
).data
collection.upsert(
ids=[str(i) for i in range(len(docs))],
embeddings=[e.embedding for e in embeddings],
documents=docs,
)
# --- Query ---
query = "How does vLLM manage memory?"
q_embedding = client.embeddings.create(
model="text-embedding-3-small", input=query
).data[0].embedding
results = collection.query(query_embeddings=[q_embedding], n_results=2)
context = "\n".join(results["documents"][0])
answer = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": f"Answer using only: {context}"},
{"role": "user", "content": query},
],
).choices[0].message.content
print(answer) Matryoshka Dimensions (Smaller = Cheaper)
The text-embedding-3 models support a dimensions parameter that truncates vectors to a smaller size with only minor quality loss. Use this to reduce storage and query costs:
# Full 1536 dimensions (default)
client.embeddings.create(model="text-embedding-3-small", input="Hello")
# 512 dimensions — 3x less storage, ~2% quality drop
client.embeddings.create(
model="text-embedding-3-small",
input="Hello",
dimensions=512,
)
# 256 dimensions — 6x less storage, ~5% quality drop
client.embeddings.create(
model="text-embedding-3-small",
input="Hello",
dimensions=256,
) Batch Embedding for Cost Efficiency
Pass a list of strings to embed multiple texts in one API call. Batches of up to 2048 strings are supported. Use the Batch API for large jobs (>50k documents) to get a 50% discount:
texts = ["chunk 1 ...", "chunk 2 ...", "chunk 3 ..."] # up to 2048
response = client.embeddings.create(
model="text-embedding-3-small",
input=texts, # batch in one call
)
vectors = [item.embedding for item in response.data]
# response.usage.total_tokens shows exact tokens consumed OpenAI Embeddings vs Alternatives
| Provider | Best model | Price (1M tokens) | Notes |
|---|---|---|---|
| OpenAI | text-embedding-3-small | $0.02 | Easiest to start, MRL dimensions |
| Cohere | embed-english-v3.0 | $0.10 | Requires input_type param, multilingual v3 |
| Voyage AI | voyage-3 | $0.06 | Top MTEB scores, Anthropic-backed |
| sentence-transformers | all-MiniLM-L6-v2 | Free (self-hosted) | Local only, CPU-friendly, smaller quality |
See also: OpenAI API guide · Pinecone guide · Qdrant guide · Chroma guide · Supabase AI guide
Monitor the OpenAI API Your RAG Pipeline Depends On
RAG pipelines fail silently when the embedding API is degraded. Prismix tracks OpenAI API status in real-time with email and webhook alerts so you know before your users do.
Check OpenAI API Status →