OpenAI text-embedding-ada-002 (1536 Dimensions)

text-embedding-ada-002 is OpenAI's hosted embedding model released in December 2022. It returns a 1536-dimensional, unit-length vector for inputs of up to 8,191 tokens, and for a long time it was the default embedding choice in RAG tutorials and vector-database quick-starts. It has since been superseded by the text-embedding-3 models, but many production indexes still hold ada-002 vectors.

It is listed here alongside encoder-only embedding models because it plays the same role in a retrieval stack; OpenAI has not published its architecture. Compare with local models MiniLM (384 dims) and multi-qa-mpnet (768 dims).


1. How It Is Used

Embedding via the OpenAI API Chunks<= 8191 tokens cl100k_basetiktoken count POST /embeddingsbatched inputs 1536 floatsunit length Vector DB Cost: billed per input token; batch many inputs per request. Normalised: cosine similarity and dot product give the same ranking. Closed model: architecture and training data are not published.

You send text (a string or a list of strings) to the embeddings endpoint and receive one vector per input. Inputs are tokenized with the cl100k_base encoding; count with tiktoken and truncate or chunk beyond 8,191 tokens, otherwise the request is rejected. Although long inputs are accepted, embedding a whole document into one vector blurs its topics — retrieval usually works better on chunks of a few hundred tokens.

2. Runnable Example

# pip install openai tiktoken numpy
import numpy as np, tiktoken
from openai import OpenAI

client = OpenAI()                       # reads OPENAI_API_KEY
enc = tiktoken.get_encoding("cl100k_base")
MAX_TOKENS = 8191

def embed(texts, model="text-embedding-ada-002", batch=256):
    out = []
    for i in range(0, len(texts), batch):
        chunk = [enc.decode(enc.encode(t)[:MAX_TOKENS]) for t in texts[i:i + batch]]
        resp = client.embeddings.create(model=model, input=chunk)
        out.extend(d.embedding for d in resp.data)     # order matches input
    return np.array(out, dtype="float32")

docs = ["Refunds are processed within 5 business days.",
        "Shipping is free on orders over $50."]
D = embed(docs)
q = embed(["how long does a refund take"])[0]
print(D.shape)                          # (2, 1536)
print(D @ q)                            # vectors are unit length -> cosine

Batch inputs to reduce request overhead, retry with exponential backoff on rate-limit errors, and cache embeddings keyed by a hash of (model, text) so re-runs do not pay twice.

3. Similarity Score Behaviour

Cosine Similarity Scores Are Compressed 0.0 0.5 0.7 1.0 unrelated related Typical behaviour: most pairs score in a narrow high band. Rank, don't threshold globally. Schematic, not measured data.

Vectors are normalized, so cosine similarity, dot product and Euclidean distance all produce the same ranking. In practice ada-002 cosine scores cluster in a fairly narrow, high range even for unrelated text, so a fixed threshold like "0.8 means relevant" transfers poorly between corpora. Rank results, and if you need a cut-off, calibrate it on labelled pairs from your own data.

4. Lineage and Migration

OpenAI Embedding Model Lineage First-gen (2022)separate similarity / searchmodels, many dims text-embedding-ada-002Dec 2022, one model,1536 dims text-embedding-3small 1536 / large 3072,'dimensions' parameter ada-002 vectors are not compatible with text-embedding-3 vectors: migrating means re-embedding the whole corpus.

ada-002 replaced several first-generation task-specific models with one model. The text-embedding-3-small and -large models that followed support a dimensions parameter, so you can request shorter vectors (trained so that truncated prefixes remain useful) to trade quality for storage. Vectors from different models live in different spaces — never mix them in one index.

5. Hosted vs Local Embeddings

Concernada-002 / hosted APILocal (MiniLM, mpnet)
OperationsNo GPUs to run; scales with your quotaYou host and scale the model
Data residencyText is sent to a third partyStays in your network
Cost modelPer token, recurring on re-embedsHardware; marginal cost near zero
Input length8,191 tokens256–512 wordpieces
Storage1536 x 4 B = 6 KB per vector1.5–3 KB per vector
Version controlProvider may deprecate modelsPinned weights

6. Common Pitfalls

7. Similarity Math and a Worked Example

For two vectors a and b, cosine similarity is a·b / (‖a‖‖b‖). Because ada-002 returns vectors with ‖a‖ = 1, the denominator is 1 and cosine equals the dot product. Squared Euclidean distance becomes ‖a − b‖2 = 2 − 2 a·b, a monotone function of the dot product, which is why all three metrics give the same ranking. In practice, choose inner product in the vector index: it is the cheapest to compute and equivalent here.

Consider a query scored against three chunks with similarities 0.86, 0.81 and 0.78. All three look "high" in absolute terms, but only the ranking is meaningful. A useful habit is to inspect score gaps rather than raw values: a clear margin between the first and second result suggests a confident match, whereas a flat sequence suggests the corpus has no strong answer and the application should say so or fall back to keyword search.

Anisotropy. The narrow score range is a known property of many learned embedding spaces: vectors occupy a cone rather than spreading evenly over the sphere, so even unrelated texts share a large common component. Techniques such as subtracting the corpus mean vector and re-normalizing can spread scores out; they do not change much for top-k ranking but can make thresholds and clustering behave better. Validate any such transform on your own retrieval labels.

8. Sizing, Cost and Throughput

Estimate cost and storage before indexing. Storage is predictable: 1536 dimensions × 4 bytes = 6,144 bytes per vector, so 1 million chunks need roughly 6 GB of raw float32 plus index overhead (an HNSW graph adds neighbor lists per node). API cost scales with total tokens embedded, so count tokens with tiktoken on a sample of documents, multiply out, and check current pricing on OpenAI's pricing page rather than relying on a figure from a tutorial. Remember that every change to chunking or to the model triggers a full re-embed, which is the recurring cost that local models avoid.

For throughput, send many inputs per request, run several requests concurrently within your rate limit, and handle HTTP 429 responses with exponential backoff and jitter. Keep a persistent cache keyed on a hash of model name plus exact text, so unchanged chunks are never re-sent.

9. Migrating Off ada-002

Re-Embedding Migration Without Downtime Old index ada-002 vectors serving traffic Backfill embed corpus with new model into a second index Shadow eval same queries on both compare recall@k, MRR on labels Cut over switch alias, keep old for rollback Queries must be embedded by the same model as the index they search.

Because vectors from different models are incompatible, a migration is a rebuild, not an in-place update. Build a second index with the new model (for example text-embedding-3-small, or a local model such as multi-qa-mpnet), run the same labeled query set against both, and compare recall@k and mean reciprocal rank. Store the model identifier alongside every vector and every index so a query can never be embedded with the wrong model. Switch traffic with an alias or configuration flag and keep the old index until the new one has proved itself on live traffic.

When choosing the target, weigh retrieval quality on your own data, vector size (text-embedding-3 models let you request shorter vectors), language coverage, data-residency requirements, and whether you want to own the serving infrastructure. Public benchmarks such as MTEB help shortlist candidates but do not replace an in-domain evaluation.

10. Typical Uses

Further reading. OpenAI (December 2022), "New and improved embedding model" announcement; OpenAI (January 2024), announcement of the text-embedding-3 models; Neelakantan et al. (2022), "Text and Code Embeddings by Contrastive Pre-Training", arXiv:2201.10005; Ethayarajh (2019), "How Contextual are Contextualized Word Representations?" (anisotropy); Kusupati et al. (2022), "Matryoshka Representation Learning"; Muennighoff et al. (2022), "MTEB: Massive Text Embedding Benchmark".