Build your own RAG pipeline
Embed & index chunks·20 min

The embedding vector

0 / 1
# grade this stage (from your course directory)
npx theinference test --stage embed-vector --watch

Let's pin down the embedder itself. This step grades the exact 256-dim vector your embedText produces for a fixed text — a numeric adapter, compared with allclose. Get this right and every retrieval downstream lines up.

src/embed.ts
export const DIM = 256;
// fnv1a(s) is provided. embedText:
//   s = " " + text.toLowerCase().replace(/\s+/g," ").trim() + " "
//   for each 3-char window gram of s:
//     h = fnv1a(gram);  bucket = h % DIM;  sign = (h & 0x100) ? -1 : 1
//     v[bucket] += sign
//   L2-normalize v (divide by sqrt(sum of squares); return as-is if norm is 0)

What to build

Your task

Implement embedText (via runEmbed)

Implement embedText in src/embed.ts following the pinned algorithm, then wire it into the runEmbed adapter. The adapter receives a text and returns the 256-dim number[].

tests/adapters.ts
import { embedText } from "../src/embed.ts";
export function runEmbed(text: string): number[] {
  return embedText(text);
}
How it's graded

adapter mode. The harness calls runEmbed on a fixed text and compares your number[] to the reference with allclose (atol 1e-5) and a shape check ([256]).

The sign bit and the padding matter

Two easy mistakes: forgetting to pad the text with a leading/trailing space (short texts then produce no 3-grams), and using the wrong sign bit (h & 0x100). Both shift the vector and fail the allclose. Match the pinned algorithm exactly.