Cosine Similarity

The most common way to score how close two embedding vectors are.

Syntaxcosine(a, b) = dot(a, b) / (norm(a) * norm(b))

Cosine similarity measures the angle between two vectors. It ignores length and focuses on direction, which works well for comparing meaning.

Reading the score

  • 1.0 — same direction (very similar).
  • 0 — unrelated.
  • -1 — opposite.

In practice, embedding vectors of related text score close to 1, and you rank results by their cosine score. You do not usually compute this by hand — vector databases do it for you — but it helps to know what the number means.

Example

Example · javascript
function cosine(a, b) {
  let dot = 0, na = 0, nb = 0;
  for (let i = 0; i < a.length; i++) {
    dot += a[i] * b[i];
    na += a[i] * a[i];
    nb += b[i] * b[i];
  }
  return dot / (Math.sqrt(na) * Math.sqrt(nb));
}

console.log(cosine([1, 0, 1], [1, 0, 1])); // 1  (identical)
console.log(cosine([1, 0, 0], [0, 1, 0])); // 0  (unrelated)

When to use it

  • A vector search index uses cosine similarity to rank thousands of product embeddings against a query embedding in milliseconds.
  • A duplicate-detection pipeline flags pairs of support tickets whose embeddings score above 0.95 cosine similarity for human review.
  • A news aggregator clusters articles by computing cosine similarity between their embeddings and grouping those above a threshold.

More examples

Cosine similarity from scratch

Implements cosine similarity from first principles to show the dot-product-over-magnitudes formula.

Example · python
import math

def cosine_similarity(a, b):
    dot = sum(x * y for x, y in zip(a, b))
    mag_a = math.sqrt(sum(x**2 for x in a))
    mag_b = math.sqrt(sum(x**2 for x in b))
    return dot / (mag_a * mag_b)

v1 = [1.0, 0.5, 0.2]
v2 = [0.9, 0.6, 0.1]
v3 = [-1.0, -0.5, -0.2]  # opposite direction
print(f'v1 vs v2: {cosine_similarity(v1, v2):.4f}')  # close to 1
print(f'v1 vs v3: {cosine_similarity(v1, v3):.4f}')  # close to -1

Cosine similarity with numpy

Uses numpy for efficient cosine similarity on real embeddings, confirming related words score higher.

Example · python
import numpy as np
from openai import OpenAI

client = OpenAI()

def embed(text):
    return np.array(
        client.embeddings.create(model='text-embedding-3-small', input=text).data[0].embedding
    )

def cosine(a, b):
    return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))

pairs = [
    ('cat', 'kitten'),
    ('cat', 'automobile'),
]
for w1, w2 in pairs:
    score = cosine(embed(w1), embed(w2))
    print(f'{w1} vs {w2}: {score:.4f}')

Threshold-based similarity filter

Filters candidates to only those whose cosine similarity exceeds a minimum threshold score.

Example · python
import numpy as np
from openai import OpenAI

client = OpenAI()

def embed(text):
    return np.array(
        client.embeddings.create(model='text-embedding-3-small', input=text).data[0].embedding
    )

cosine = lambda a, b: np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))

query   = 'password reset'
candidates = ['reset my login', 'forgot credentials', 'best pizza in town', 'account recovery help']
THRESHOLD = 0.5
q_vec = embed(query)
matches = [c for c in candidates if cosine(q_vec, embed(c)) >= THRESHOLD]
print('Matches above threshold:', matches)

Discussion

  • Be the first to comment on this lesson.
Cosine Similarity — AI | SoundsCode