Easier to read with cream paper, a tint, more contrast or larger text? Choose your colours and text, once, for every page.

Free lesson

What embeddings are and cosine similarity

After this lesson: I can say what an embedding is and compare two with cosine similarity.

60 min lesson4 commandsAI coding agent lab: use opencode to explain and fix code, and check its work

The page that shares no words

An embedding is a list of numbers that stands for the meaning of a piece of text. Texts with similar meanings get lists that point the same way, so a program can compare meanings with arithmetic.

A library visitor searches for "borrowing rules". The page they need is headed "Lending policy". The two share no words, so a search that matches words finds nothing. Numbers can find it.

By the end of this lesson

Note

I can say what an embedding is and compare two with cosine similarity.

Key words

WordWhat it meansExample
Embeddinga list of numbers that stands for a meaning
Vectora list of numbers, seen as a point or an arrow
Dot productthe sum of the products of matching numbers
Cosine similaritya score of how alike two arrows point0.98
Retrievalfinding the pieces of text that fit a question

The cells students fill in are left blank in this preview.

Real embeddings and our stand-ins

A real embedding has hundreds of numbers and is made by a model. Nothing in this module makes one.

The lessons use small stand-ins instead: invented lists of three numbers, and counts of words that a script works out itself. That way every step can be run and checked here. The method is the same.

A vector is a list of numbers

Think of a list of numbers as a point on a map. Two numbers are a point on a flat map. Three are a point in a room.

Give each place in the list a meaning. Here the three places are animal, vehicle and food. A big number means the word is strongly about that thing.

Worked example: four invented vectors

WordAnimalVehicleFood
cat0.90.10.1
kitten0.80.10.2
bus0.10.90.0
scone0.10.00.9

The cells students fill in are left blank in this preview.

Cosine similarity scores how alike two vectors are

To compare two vectors you need three small steps. The dot product multiplies the numbers in matching places and adds them up. The length is the square root of a vector's dot product with itself.

The cosine is the dot product divided by the two lengths. It is 1 when the arrows point the same way, 0 at a right angle and below 0 when they point away.

Worked example: two small vectors

StepWorkingResult
Dot product1 x 2 + 2 x 14
Length of asquare root of (1 x 1 + 2 x 2)2.24
Length of bsquare root of (2 x 2 + 1 x 1)2.24
Cosine4 divided by (2.24 x 2.24)0.8

The cells students fill in are left blank in this preview.

Write the maths as a loop

The next script holds the four vectors and writes the three steps as small functions. It prints the cosine of every pair.

It also builds a count vector: a fixed list of words, and how many times each appears in a sentence. Two sentences that use the same words get vectors that point the same way.

Write the vector script, part 1

Command
docker exec -w /home/node/project agent sh -c "printf '%s\n' '// Small made-up vectors: [animal, vehicle, food]. A real embedding has hundreds of numbers.' 'const vectors = {' '  cat: [0.9, 0.1, 0.1],' '  kitten: [0.8, 0.1, 0.2],' '  bus: [0.1, 0.9, 0.0],' '  scone: [0.1, 0.0, 0.9],' '};' 'function dot(a, b) {' '  let total = 0;' '  for (let i = 0; i < a.length; i++) total = total + a[i] * b[i];' '  return total;' '}' 'function length(a) { return Math.sqrt(dot(a, a)); }' 'function cosine(a, b) { return dot(a, b) / (length(a) * length(b)); }' > vec.js"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Write the vector script, part 2

Command
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const names = Object.keys(vectors);' 'for (let i = 0; i < names.length; i++) {' '  for (let j = i + 1; j < names.length; j++) {' '    const score = cosine(vectors[names[i]], vectors[names[j]]);' '    console.log(names[i] + \" and \" + names[j] + \": \" + score.toFixed(2));' '  }' '}' '// A count vector: how many times each word of a fixed list appears.' 'const vocabulary = [\"open\", \"late\", \"book\", \"fine\"];' 'function counts(sentence) {' '  const found = sentence.toLowerCase().split(\" \");' '  return vocabulary.map(function (word) {' '    return found.filter(function (one) { return one === word; }).length;' '  });' '}' >> vec.js"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Write the vector script, part 3

Command
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const one = counts(\"open late open\");' 'const two = counts(\"book open late\");' 'console.log(\"Counts:\", one.join(\" \"), \"and\", two.join(\" \"));' 'console.log(\"Cosine of the counts:\", cosine(one, two).toFixed(2));' >> vec.js"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Run it and read the scores

Command
docker exec -w /home/node/project agent node vec.js

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

What it prints

LineWhat it shows
cat and kitten: 0.99Very alike
cat and bus: 0.22Not alike
bus and scone: 0.01Almost nothing in common
Cosine of the counts: 0.77The sentences share the words open and late

The cells students fill in are left blank in this preview.

A common mistake

Warning

Many people think a cosine of 0.9 means "90 per cent the same". It does not. The score only ranks: 0.9 is closer than 0.5. Use it to put things in order, never as a percentage of truth.

About this lab and its source: AI coding agent lab: use opencode to explain and fix code, and check its work

Teaching a class? Set this module for your students with a teacher guide, marked assignments and a lab for every student.