Skip to content
Chapter 1 of 8

The real interview loop

Before you drill a single algorithm, understand the machine you are walking into. An AI-engineer loop in 2026 is usually four to seven rounds, and each one screens for a different thing. The recruiter screen checks that you can talk about shipped work in plain language. The practical coding round checks that you can write working code under mild pressure, usually something AI-adjacent, not LeetCode trivia. The from-scratch ML round checks that you actually understand the internals by asking you to implement one (attention is the favorite). The theory round checks judgment, not memory: it wants to know when you would NOT use a technique. The system-design round checks whether you can design a real LLM product with numbers attached. The take-home checks whether you handle ambiguity and build the right thing. The behavioral round checks ownership, especially of probabilistic systems that fail in ways deterministic ones do not. A real question they open with: "Walk me through a system you shipped and what broke." The answer that passes names a concrete system, one real failure, the metric that caught it, and the change you made. The answer that fails recites your resume. This chapter's lab is the warmup they hand you first in the practical round: implement cosine similarity and a tiny vector search from scratch. It looks trivial and it filters fast, because you have to be right about both the math and the retrieval loop.

The lab: read it, then run it

labs/interview-prep/ip1-cosine-retrieval.py
#!/usr/bin/env python3
"""
LAB IP1: Cosine-similarity retrieval, a mini vector search.

This is the single most common warmup an AI-engineer interview opens with:
"code cosine similarity and a tiny nearest-neighbor search, from scratch, no
libraries doing the ranking for you." It looks trivial and it filters people
fast, because you have to be right about the math (dot product over the product
of norms) AND about the retrieval loop (rank every document, return the best).

You build both here on real numpy vectors, then PROVE:
  - cosine(x, x) == 1.0 (a vector is identical to itself),
  - the document that shares the most query words ranks first,
  - the full ranking comes back in the correct order.

Run: python3 modules/academy-content/labs/interview-prep/ip1-cosine-retrieval.py
"""
import sys
import numpy as np

np.random.seed(7)  # reproducible


def bag_of_words(text, vocab):
    """Turn text into a term-frequency vector over a fixed vocabulary. Real
    systems use learned embeddings; a bag of words is enough to prove retrieval
    and is exactly the kind of from-scratch representation an interviewer wants
    to see you build without reaching for a library."""
    counts = np.zeros(len(vocab), dtype=np.float64)
    words = text.lower().split()
    index = {w: i for i, w in enumerate(vocab)}
    for w in words:
        if w in index:
            counts[index[w]] += 1.0
    return counts


def cosine(a, b):
    """Cosine similarity: the dot product divided by the product of the L2
    norms. It measures the ANGLE between two vectors, not their length, which
    is why it is the default similarity for retrieval."""
    na = np.linalg.norm(a)
    nb = np.linalg.norm(b)
    if na == 0.0 or nb == 0.0:
        return 0.0
    return float(np.dot(a, b) / (na * nb))


def search(query_vec, doc_vecs, k):
    """Rank every document by cosine similarity to the query and return the top
    k as (index, score) pairs, highest first. This IS a vector search, just
    without the approximate-nearest-neighbor index a production store would add
    for speed."""
    scored = [(i, cosine(query_vec, d)) for i, d in enumerate(doc_vecs)]
    scored.sort(key=lambda pair: pair[1], reverse=True)
    return scored[:k]


# A tiny corpus. The query is about sailing; doc 2 is the sailing passage.
vocab = ["sailboat", "wind", "ocean", "engine", "diesel", "truck",
         "recipe", "flour", "oven", "bread", "harbor", "sails"]
docs = [
    "diesel engine truck engine",            # 0: vehicles
    "recipe flour oven bread flour",         # 1: baking
    "sailboat wind ocean harbor sails wind",  # 2: sailing (the target)
    "ocean wind recipe",                     # 3: mixed, weak sailing overlap
]
query = "sailboat wind ocean sails"

doc_vecs = [bag_of_words(d, vocab) for d in docs]
query_vec = bag_of_words(query, vocab)

# 1. Identity property: a vector is perfectly similar to itself.
self_sim = cosine(query_vec, query_vec)
print("STEP 1: cosine identity")
print(f"  cosine(q, q) = {self_sim:.6f}  (must be 1.0)")

# 2. Rank the corpus and read off the winner.
ranking = search(query_vec, doc_vecs, k=len(docs))
print("")
print("STEP 2: ranked retrieval (index, score)")
for idx, score in ranking:
    print(f"  doc {idx}: {score:.4f}  {docs[idx]!r}")

top_index = ranking[0][0]
top_is_sailing = (top_index == 2)
order_indices = [idx for idx, _ in ranking]
# doc 2 (sailing) first, doc 3 (weak overlap) ahead of the two unrelated docs.
expected_front = order_indices[0] == 2 and 3 in order_indices[:3]

print("")
print(f"STEP 3: top hit is the sailing passage (doc 2) : {top_is_sailing}")
print(f"        identity holds                        : {abs(self_sim - 1.0) < 1e-9}")

ok = top_is_sailing and abs(self_sim - 1.0) < 1e-9 and expected_front
print("")
print(f"COSINE RETRIEVAL RANKS THE RIGHT DOCUMENT FIRST: {'YES' if ok else 'NO'}")
if not ok:
    sys.exit(1)
print("You just built the core of every vector database. Next round: tokenizers.")
Lab (read-only)
ip1-cosine-retrieval.py

Implement cosine similarity and a mini vector search from scratch, and prove it ranks the right document first.

Proves: COSINE RETRIEVAL RANKS THE RIGHT DOCUMENT FIRST: YES

The lab ranked the sailing passage first with no library doing the ranking for you, and it confirmed the identity property that a vector is perfectly similar to itself. That is the shape of the whole practical round: a small problem where being exactly right about the math and the loop is the entire test. Map your loop before you study. Ask the recruiter what the rounds are, then spend your two to six weeks putting more hours where you are weakest, not where you are already strong. Most people over-prepare the round they enjoy and walk into the one that sinks them cold. Next you drill the practical coding round proper.
Check your understanding
  1. 1. What does the practical coding round primarily screen for?

  2. 2. The behavioral round is most focused on which theme for an AI engineer?

  3. 3. What is the smart way to plan a two to six week interview process?