02 · How LLMs Actually Work

You don't need the maths to understand how an LLM works. You do need the right mental model. With it you can predict when the model will shine, when it will fail, and why prompting and context matter so much.

Level 145 minTrack 2 · LLMs & internals

By the end of this page you can

The core idea: predict the next token

An LLM does one thing over and over. Given some text, it predicts what piece of text comes next, adds that piece, and repeats. Everything else (answering questions, writing code, translating, reasoning) emerges from doing this extremely well after training on a vast amount of text.

"def add(a: Int, b: Int) =" LLMbillions of weights " a" → 0.81" b" → 0.07" {" → 0.04 … pick one token: " a" append it to the input and repeat → "def add(a: Int, b: Int) = a + b"
Autoregressive generation: one token at a time. Each new token becomes part of the input for the next prediction.
Analogy: the world's best autocomplete Your phone keyboard suggests the next word from your recent typing. An LLM is the same idea scaled up enormously. It has learned from a large part of the public internet, books and code, and it considers thousands of previous tokens at once. To predict the next line of a Scala proof well, it has to "understand" a lot about Scala.

Tokens: how models see text

Models don't read characters or words. They read tokens: chunks of text from a fixed vocabulary, typically 30,000 to 200,000+ entries. A tokenizer splits text into tokens and maps each one to an integer ID.

"Scala is functional"       -> ["Sc", "ala", " is", " functional"]
"val total = xs.sum"        -> ["val", " total", " =", " xs", ".", "sum"]
"unbelievably"              -> ["un", "belie", "vably"]
"    def f():" (Python)     -> ["    ", "def", " f", "():"]

Embeddings: meaning as numbers

Each token ID is turned into an embedding: a list of hundreds or thousands of numbers (a vector). Training arranges these vectors so that similar meanings end up close together.

collections ListVectorSeqArray concurrency FutureIOTask animals catdoghorse (real space: ~1,000+ dimensions)
Embeddings place related concepts near each other. This is also the basis of semantic search and RAG (Level 2).

You can do "maths with meaning". The classic example is that king − man + woman lands near queen. Embeddings are also used outside the LLM to search documents by meaning. That is the foundation of RAG.

The Transformer and attention

The Transformer is the neural network architecture behind modern LLMs. Its key trick is attention: for every token, the model decides which other tokens in the context are relevant and blends information from them.

The function returns an Option so it …? thick lines = high attention weight
To understand "it", the model attends strongly to "function" and "Option". This is how it tracks meaning across a long context.

A Transformer stacks dozens of layers of attention plus small feed-forward networks. Early layers pick up syntax and local patterns. Deeper layers represent more abstract things: types, intent, style, logic. Attention works in parallel across all tokens, so Transformers train efficiently on GPUs, and that is why they scaled.

Deep dive: query, key, value (optional)

Each token produces three vectors: a query ("what am I looking for?"), a key ("what do I contain?") and a value ("what information do I pass on?"). The attention weight between two tokens is the similarity between one token's query and the other's key, normalised with softmax. The output is the weighted sum of values. "Multi-head" attention runs many of these in parallel, each specialising in different relationships. Level 4 implements this in code.

How a model is trained

1. Pre-trainingtrillions of tokenspredict next tokenweeks on GPU clusters 2. Fine-tuning (SFT)curated examples ofgood conversations→ follows instructions 3. Preference / RLhumans/AI rank answers;rewards for verifiedcorrect code & maths 4. Evaluate & shipbenchmarks, red-teaming,safety tuning→ released model
Pre-training creates a "base model" that knows a lot but just continues text. Post-training (steps 2–3) turns it into a helpful assistant.

Inference: generating an answer

When you send a prompt, the model runs inference. It computes a probability for every possible next token, picks one according to the sampling settings, and repeats until it emits a stop token or hits the limit.

SettingWhat it doesDeveloper guidance
Temperature0 = almost always pick the most likely token (focused, repeatable). Higher (0.8–1.2) = more varied and creative, and more errors.Code, extraction, classification: low (0–0.3). Brainstorming and naming: higher.
Top-p (nucleus)Only sample from the smallest set of tokens whose probabilities add up to p (e.g. 0.9).Usually adjust temperature or top-p, not both.
Max output tokensHard limit on answer length.Set high enough for full code files, or output will be cut off.
Stop sequencesStrings that end generation.Useful when parsing output programmatically.
SeedMakes sampling more repeatable (where supported).Helps with tests and evals.
Even temperature 0 is not perfectly deterministic Large-scale serving (batching, floating-point maths on GPUs) can produce small differences between runs. Never build systems that assume identical outputs every time. Validate the output instead.

The context window

The context window is the maximum number of tokens the model can consider at once: the system prompt, conversation history, files, tool results and its own answer. Modern models range from tens of thousands to a million or more tokens.

system prompt rules / AGENTS.md history + files + tool results your prompt model's answer free everything shares one budget, measured in tokens
When the window fills up, older content is truncated or summarised. The model cannot see what is not in the window.

Messages and roles

Chat models receive a list of messages, each with a role:

{
  "messages": [
    { "role": "system",    "content": "You are a senior Scala 3 reviewer. Be concise." },
    { "role": "user",      "content": "Review this function: def avg(xs: List[Int]) = xs.sum / xs.size" },
    { "role": "assistant", "content": "It throws ArithmeticException on an empty list..." },
    { "role": "user",      "content": "Fix it using Option." }
  ],
  "temperature": 0.2,
  "max_tokens": 800
}

Why hallucinations happen

A hallucination is fluent, confident output that is false: a made-up API, a non-existent library version, a fake citation. It happens because the model is trained to produce plausible continuations, not to check facts. When the true answer was rare or absent in its training data, a plausible-looking guess often wins.

Reasoning ("thinking") models

Many current models can spend extra tokens thinking before answering: they work through a problem step by step internally, check intermediate results, and then give a final answer. This uses more test-time compute. It helps with multi-step logic, debugging, maths and planning. It adds latency and cost and is unnecessary for simple tasks.

TaskFast/standard modelReasoning model / high effort
Rename variables, write docstrings, boilerplate✓ Best choiceOverkill
Explain a stack trace✓ Usually fineFor subtle concurrency bugs
Design a migration plan, tricky algorithm, cross-file refactorMight miss things✓ Better

Open-weight vs closed models

Closed / hosted (API)

Accessed over the internet. Usually the most capable. No hardware needed. Your data goes to the provider, so check their data policies. Pay per token.

Open-weight (downloadable)

Weights are published. You can run them locally (Ollama, LM Studio, MLX on a Mac) or on your own servers. Full privacy and control. Often smaller and less capable, but improving fast.

Build intuition: a toy next-word model

Real LLMs use neural networks. A tiny bigram model (next word based only on the previous word) still shows the core loop: learn probabilities from data, then sample.

import random
from collections import defaultdict, Counter

corpus = "the cat sat on the mat . the dog sat on the log . the cat saw the dog ."
words = corpus.split()

# 1. "Training": count which word follows which
follows: dict[str, Counter] = defaultdict(Counter)
for prev, nxt in zip(words, words[1:]):
    follows[prev][nxt] += 1

# 2. "Inference": sample the next word, with temperature
def next_word(prev: str, temperature: float = 1.0) -> str:
    options = follows[prev]
    weights = [count ** (1 / temperature) for count in options.values()]
    return random.choices(list(options), weights=weights)[0]

def generate(start: str, n: int = 8, temperature: float = 1.0) -> str:
    out = [start]
    for _ in range(n):
        out.append(next_word(out[-1], temperature))
    return " ".join(out)

print(generate("the", temperature=0.3))  # focused
print(generate("the", temperature=2.0))  # more random
//> using scala 3
import scala.util.Random

@main def toyBigram(): Unit =
  val words = "the cat sat on the mat . the dog sat on the log . the cat saw the dog .".split(" ").toVector

  // 1. "Training": count transitions
  val follows: Map[String, Map[String, Int]] =
    words.zip(words.tail)
      .groupMap(_._1)(_._2)
      .view.mapValues(_.groupMapReduce(identity)(_ => 1)(_ + _)).toMap

  // 2. "Inference": sample with temperature
  def nextWord(prev: String, temperature: Double): String =
    val opts    = follows(prev).toVector
    val weights = opts.map((_, c) => math.pow(c, 1 / temperature))
    var r       = Random.nextDouble() * weights.sum
    opts.zip(weights).find { case (_, w) => r -= w; r <= 0 }.map(_._1._1).getOrElse(opts.last._1)

  def generate(start: String, n: Int, t: Double): String =
    Iterator.iterate(start)(w => nextWord(w, t)).take(n + 1).mkString(" ")

  println(generate("the", 8, 0.3))
  println(generate("the", 8, 2.0))

An LLM replaces "count the previous word" with "a Transformer with billions of parameters that looks at thousands of previous tokens". The loop is the same.

Try it Run either script above. Then ask an AI assistant: "Explain how this toy bigram model differs from a Transformer LLM, in 5 bullet points." Then: "Modify it to be a trigram model." Run the result and verify it works.

Key takeaways