Vibe Engines
YouTube

Vibe Engines is free, interactive AI engineering & system design — runs in your browser. Pick a learning path

~10 min readOpenAI · 2021

Codex,
explained.

Take GPT, feed it a mountain of public code, and it learns to write programs from a comment. That model, Codex, became the engine of GitHub Copilot and put AI pair-programming in millions of editors. But the paper's quiet, lasting contribution isn't the model — it's how to measure one. You can't grade code by how similar it looks to an answer key; you have to run it. Codex's answer, pass@k, asks the honest question: if the model takes a few shots at a problem, does at least one of them actually work? Here's the model, the benchmark, and the metric that reshaped how code AI is judged.

The delta

What changes here: correctness replaces resemblance

Rung 1, so the comparison is against how generated code was scored before, which was borrowed from machine translation: measure the text overlap between the generated program and a reference solution. For code that is close to meaningless. Two programs with almost no tokens in common can both be perfectly correct, and a program differing from the reference by one character can be broken.

The change is to run it. A generated program is correct if it passes the unit tests, full stop — functional correctness rather than similarity, evaluated by execution. That sounds obvious and it was the field's methodological turning point for code, because it makes the metric agree with what anyone actually wants. The accompanying benchmark pairs function signatures and docstrings with hidden tests, so a model is asked to implement a specification and is judged on whether the implementation works.

The measurement detail is worth the attention it gets, because it is where naive evaluation goes wrong. What you want to know is whether at least one of k samples solves the problem — that is how a developer uses a code assistant, with several suggestions to pick from. Sampling exactly k and checking is a very high-variance estimate of that. Instead, draw n samples with n larger than k, count how many pass, and compute the probability that a random subset of size k contains a passing one analytically from the count. Same quantity, far less noise, for free — and it is the reason numbers from this benchmark are comparable at all.

01

GPT that writes code

Code is text, and a lot of it is public. Codex's recipe was simply to take the GPT architecture and fine-tune it on billions of lines of source code from GitHub. The result is a language model whose "language" was Python source (the paper's models are trained on Python only; the multi-language models behind Copilot are separate) — a model that, given a function signature and a docstring, continues the "sentence" by writing the function body. Because programming languages have tighter structure than natural language, and because so much example code exists, the model became strikingly capable at turning intent into working code.

That capability, wrapped in an editor, became GitHub Copilot — autocomplete that finishes not just the line but the whole function. But shipping a code model raised a sharp evaluation problem the natural-language world had mostly dodged: how do you know if generated code is good? That question is where the paper made its deepest mark.

The one-sentence version

Fine-tune GPT on public code to get a programming assistant, and measure it by whether generated programs actually pass tests — pass@k — not by how they look.

02

Run it, don't match it

The old way to score generated text is to compare it to a reference with a similarity metric like BLEU. For code this is badly broken: a correct program can be written a hundred different ways, so a working solution that looks different from the reference scores terribly, while a broken one that looks similar scores well. Text similarity measures the wrong thing entirely.

Codex insisted on functional correctness: a generated program is right if and only if it passes the unit tests. To measure this it introduced HumanEval — 164 hand-written problems, each a function signature, a docstring describing the task, and a set of hidden tests. Generate a solution, run it against the tests, and it counts only if every test passes. Hand-writing the problems (rather than scraping them) was deliberate, to reduce the chance they'd leaked into training data. Grade by execution, not appearance.

03

The pass@k metric

Now the subtle part. A code model is a sampler — ask it twice and you get two different programs. So the right question isn't "is its single output correct" but "if it takes k attempts, does at least one work?" That's pass@k: the probability that at least one of k sampled solutions passes the tests. Estimating it naively (sample k, check) is high-variance, so Codex uses an unbiased estimator: sample a larger n, count c that pass, and compute the chance a random k-subset contains no passing one, subtracted from 1:

C(n−c, k)/C(n, k) is the probability that all k drawn solutions come from the failing ones — so 1 minus it is the probability at least one passes. It reduces to the fraction correct at k = 1, hits 1 when every solution passes (or when there are fewer failures than k), and 0 when none pass. Computing it from a big n gives a stable estimate of a small-k quantity. The runnable version below computes the whole pass@k curve.

04

Sampling helps

The pass@k framing exposes a practical truth: more attempts dramatically raise your odds. A model with a modest 30% chance of solving a problem on the first try has a much higher chance that one of ten tries works — because the failures are somewhat independent, ten shots cover far more ground than one.

pass@k climbs with attempts (30% per-sample)
pass@1~30% — one shot, the raw solve rate.
pass@5~83% — five shots cover much more.
pass@10~97% — ten shots almost always land one (if samples were independent, which real samples are not quite).
CatchYou still must pick the right one — sampling raises "a solution exists," not "you'll choose it."

That gap between "one of these works" and "I know which one" is the crux. High pass@k says the model can produce a solution if you can verify which sample is correct — which for code you often can, by running tests. This is exactly the generate-and-verify asymmetry: generating many candidates is cheap, checking them is cheap (run the tests), so sampling plus a verifier is a powerful recipe. Codex made that concrete for code and standardized how to measure it.

How it works

How Codex was trained and evaluated, step by step

The paper (Chen, Tworek, Jun, Yuan and many colleagues at OpenAI) trains a family of models from 12 million to 12 billion parameters and evaluates them on HumanEval, a benchmark it introduces. The procedure:

pass@k 1.0 0 k = 1 10 100 samples allowed k (log scale) T = 0.2 T = 0.4 T = 0.8 k = 1: low T wins k = 100: high T wins
Schematic, not the paper's measured curves: low temperature maximizes pass@1 and high temperature maximizes pass@100, which is why the Codex paper found T = 0.2 and T = 0.8 optimal at those two ends.
  1. Collect the code. In May 2020 the team gathered 54 million public GitHub repositories and kept 179 GB of unique Python files under 1 MB. Removing files that looked auto-generated, had an average line length above 100 or a maximum above 1,000, or contained few alphanumeric characters left 159 GB. The corpus is Python only.
  2. Adapt the tokenizer. The GPT-3 text tokenizer splits code whitespace badly, so extra tokens for runs of whitespace were added, cutting the number of tokens needed for code by about 30 percent.
  3. Fine-tune GPT models on it. Training ran for 100 billion tokens with Adam (β1 = 0.9, β2 = 0.95, ε = 10^−8, weight decay 0.1), a 175-step linear warmup and cosine learning-rate decay. Starting from GPT-3 weights did not improve final performance, presumably because the code corpus is so large, but it converged faster, so the models were initialized from GPT-3 anyway.
  4. Prompt with a specification. Each HumanEval prompt is a function header and docstring, sometimes with imports or helper functions; the model writes the body.
  5. Sample and stop. Completions are drawn with nucleus sampling (top p = 0.95) and cut at the first stop sequence, such as a new top-level def, class, if, print or comment line, so the model cannot carry on past the function.
  6. Execute in a sandbox. Generated programs run in a gVisor-based sandbox with no network access, because the code is untrusted by construction.
  7. Estimate pass@k without bias. For each problem, n = 200 samples are drawn and the c that pass every unit test are counted; pass@k for k up to 100 comes from the unbiased estimator below, averaged over problems.
  8. Codex-S: fine-tune on standalone functions. A second training set was built in HumanEval's format: about 10,000 problems from competitive-programming sites and about 40,000 from continuous-integration runs of open-source Python packages, where the inputs and outputs of functions were traced while the projects' own tests ran. Problems Codex-12B could not solve in 100 samples were dropped as either ambiguous or too difficult.
  9. Rank without tests. When only one sample can be shown and no tests are available, the paper picks the sample with the highest mean token log-probability.

Temperature is part of the method

Because pass@k rewards diversity, the best sampling temperature depends on k. The paper swept it and found T = 0.2 best for pass@1 and T = 0.8 best for pass@100: one attempt wants the single most likely program, while a hundred attempts want programs that differ from one another. The same sweep is why a pass@k number is incomplete without the temperature it was measured at. A third variant, Codex-D, was trained in the reverse direction, writing a docstring from a function body, and because no unit test can check a docstring, its outputs were graded by hand.

The math

The unbiased pass@k estimator, and why the obvious one is biased

pass@k = 𝔼problems [ 1 − C(n − c, k) / C(n, k) ]
C(n − c, k) / C(n, k) = Πi=n−c+1^n (1 − k / i)
naive plug-in: 1 − (1 − c/n)^k, which is biased low
  • n — samples drawn per problem (200 in the paper); c — how many pass every test; k — attempts allowed.
  • C(n − c, k)/C(n, k) — the chance that k samples drawn without replacement from the n are all failures.
  • Π(1 − k/i) — the same ratio as a product of c terms, which avoids enormous binomial coefficients; the paper's reference code computes it this way.
  • 𝔼problems — the estimate is made per problem and then averaged, so pass@k depends on how solve rates are spread across problems, not only on their mean.

Plugging the observed rate c/n into 1 − (1 − p)^k looks natural but underestimates: that function is concave in p, so its average over the noise in c/n is smaller than its value at the true rate. At the extremes the unbiased estimator gives c/n at k = 1, exactly 1 when fewer than k samples fail (n − c < k), and 0 when nothing passes.

The evidence

What the Codex paper measured on HumanEval

The headline evaluation is HumanEval, 164 hand-written Python problems with an average of 7.7 unit tests each, scored with n = 200 samples per problem. The comparison models were GPT-3, which had no code-specific training, and the open GPT-Neo and GPT-J models, trained on the Pile, which includes GitHub code.

Modelpass@1pass@100
GPT-30%—
GPT-J 6B11.4%—
Codex-12B28.8%about 70%
Codex-S-12B37.7%77.5%
Codex-S-12B, one of 100 picked by mean log-probability44.5%—

pass@1 rose smoothly with model size across the family. The gap between pass@1 and pass@100 is the paper's case for sampling plus a selection step: with an oracle that runs the hidden tests, the 12B model solves about 70 percent of problems from 100 samples, against 28.8 percent from one. Ranking by mean log-probability recovers part of that gap without any tests, while ranking by the summed log-probability did slightly worse than picking at random.

The negative results are as useful as the headline. BLEU scores of correct and incorrect solutions overlapped heavily, so a text-similarity metric could not tell them apart. Performance fell sharply as docstrings chained more operations together, roughly exponentially in the number of steps, which the paper reads as a weakness in binding many operations to variables. And when prompts contained subtle bugs, the models wrote worse code than they were capable of, a misalignment that grew with model size.

Since then

What the authors admit, and what happened next

The benchmark's narrowness is acknowledged: self-contained functions with clear docstrings and a handful of tests are not what software engineering is. There is no repository to navigate, no existing code to avoid breaking, no ambiguity in the specification. It measures a real skill and a small one.

The paper is also unusually direct about the problems that come with shipping this, and the list has aged well: the model produces code that is subtly wrong in plausible ways, can suggest insecure patterns because insecure patterns are abundant in the training data, may reproduce training material, and invites over-reliance from users who read fluent code as correct code.

How it held up: functional correctness won so completely that the alternative is unthinkable, and the unbiased estimator is standard. The benchmark itself became saturated and contaminated — it is small, public, and years old, so top scores now say little and the results cannot be cleanly separated from exposure during pretraining. That trajectory is the normal life of a good benchmark, and rung 3 exists largely because of it.

SOLVE IT YOURSELF

The pass@k curve

pass@k is the unbiased estimator 1 − C(n−c, k)/C(n, k), and it behaves exactly as intuition says. This computes it: pass@1 equals the raw solve fraction (30/100 = 0.30), and the curve climbs steeply with more samples — 0.30 at one shot, 0.84 at five, 0.98 at ten — because independent attempts cover more ground. It also checks the edges: all solutions correct gives 1.0, none gives 0.0, and when there are fewer failing solutions than k every k-subset must include a passing one. Change the counts and watch the curve move.

YOUR TASK

Write the body of pass_at_k. Everything else in the file is already written; this is the function the paper is about. Press ▶ Run to check it against the 5 assertions below — they start red.

WHAT IT HAS TO SATISFY — 5 ASSERTIONS
  1. Pass@1 equals the fraction correct c/n
  2. Pass@k increases with more samples k
  3. All solutions correct gives pass@k = 1
  4. No solution correct gives pass@k = 0
  5. When n-c < k every k-subset contains a passing one
CPython · WebAssembly
06

What it set up

Codex kicked off the code-model era: a lineage of ever-stronger coding models, richer benchmarks (MBPP, SWE-bench, and beyond), and eventually the coding agents that don't just autocomplete but plan, edit, run, and debug across a repository. The through-line from Codex is the pairing it made standard — a generative model plus an executable check.

That pairing is its deepest legacy. Code is special among AI tasks because correctness is mechanically verifiable — you can just run it. Codex leaned into that: measure by execution (pass@k), and exploit it (sample many, keep what passes). The same generate-and-verify structure now underlies coding agents that iterate against tests and reasoning systems trained on verified answers. Codex was where "let the machine write it, then check it actually works" became the organizing principle of AI for code.

Worth knowing

pass@k's exploitable gap — high "a solution exists," lower "you picked it" — is why later systems add a selection step: run the samples against the visible tests and submit one that passes, converting pass@k into an actual solve.

Questions

Questions people ask about Codex

How do you compute the unbiased pass@k estimator?

Draw n samples per problem, with n at least k (the Codex paper used n = 200 for k up to 100), and count the c samples that pass every unit test. The probability that a random set of k of those samples contains no passing one is C(n − c, k) divided by C(n, k), so the problem's pass@k estimate is one minus that ratio, and the benchmark score is the average over problems. If fewer than k samples fail, the estimate is exactly 1. To avoid huge binomial coefficients, compute the ratio as the product of (1 − k/i) for i running from n − c + 1 to n, which is how the paper's reference code does it.

What is the best sampling temperature for pass@k?

It depends on k. The Codex paper swept temperatures and found that T = 0.2 gave the best pass@1 while T = 0.8 gave the best pass@100. With a single attempt you want the model's most likely program, so a low temperature helps. With many attempts, near-duplicate samples waste the budget, and a higher temperature spreads the samples over more distinct programs, which raises the chance that at least one is correct even though each individual sample is less likely to pass. The practical rule is to tune the temperature for the k you will actually use, and to report it, since pass@k numbers at different temperatures are not comparable.

Why is 1 − (1 − c/n)^k a biased estimate of pass@k?

Because it plugs a noisy estimate of the solve rate into a curved function. For one problem, pass@k equals 1 − (1 − p)^k, where p is the true per-sample solve rate. That function is concave in p, so by Jensen's inequality its average over the random fluctuations of c/n is smaller than its value at the true p: the plug-in systematically underestimates pass@k, most noticeably when n is small. The estimator in the Codex paper avoids the problem by computing, from the counts themselves, the exact probability that a random k-subset of the n samples contains a passing one, which is unbiased for every problem.

What data was Codex trained on?

Public Python code from GitHub. In May 2020 the authors collected 54 million public repositories, kept 179 GB of unique Python files under 1 MB, and removed files that looked auto-generated, had very long lines or contained few alphanumeric characters, leaving 159 GB. Models from 12 million to 12 billion parameters were fine-tuned on it for 100 billion tokens, starting from GPT-3 weights, which sped up convergence but did not improve final results. The paper's models are Python only; the multi-language production models behind GitHub Copilot, which the paper says is powered by a distinct production version of Codex, are not what it trained or evaluated.

What is Codex-S and how much did it improve HumanEval?

Codex-S is Codex fine-tuned further on standalone functions formatted like HumanEval problems: about 10,000 from competitive-programming sites and about 40,000 traced from continuous-integration runs of open-source Python packages, after removing problems the base model never solved in 100 attempts. The point was to close the gap between GitHub code, which is mostly not self-contained functions with docstrings, and the benchmark's format. The 12B Codex-S reached 37.7 percent pass@1 against 28.8 percent for Codex-12B, and 77.5 percent pass@100. Picking one of 100 samples by mean log-probability raised its single-answer score to 44.5 percent.

Why does pass@100 grow much more slowly than independent sampling predicts?

Because pass@k is an average over problems whose solve rates are very uneven. If every HumanEval problem had the same 28.8 percent per-sample success rate as Codex-12B's pass@1, a hundred independent samples would solve essentially all of them. Instead the 12B model solves only about 70 percent with 100 samples. Many problems sit near 100 percent, and a large group sits near zero, where no amount of resampling helps, because the model essentially never writes a correct program for them. Sampling more lifts the problems the model can sometimes solve; it cannot reach the ones it cannot.

Check yourself

4 questions to test what you just read

Work each one out before you open it — a number, a prediction or a reason, not a definition. Producing the answer is what makes it stick. Your progress is kept on this device.

A problem has n = 200 samples, of which c = 10 pass. What are pass@1 and pass@10 under the unbiased estimator, and what does the naive plug-in give for pass@10?

Show answer

pass@1 = c/n = 0.05. pass@10 = 1 − Πi=191^200(1 − 10/i) ≈ 1 − 0.591 = 0.409. The plug-in 1 − 0.95^10 ≈ 0.401 comes out lower, as the concavity argument predicts.

Codex-12B has pass@1 = 28.8% but solves only about 70% of HumanEval with 100 samples. If every problem had the same 28.8% per-sample rate and samples were independent, what would 100 samples give, and what does the gap tell you?

Show answer

1 − 0.712^100 ≈ 100%. The real figure is about 70%, so solve rates must be very uneven across problems: a sizeable group of problems has a per-sample rate near zero, and more samples cannot reach them. pass@k averages per-problem probabilities, not one shared rate.

Why does the best temperature rise from 0.2 for pass@1 to 0.8 for pass@100?

Show answer

With one attempt you want the single most probable program, and a low temperature concentrates sampling there. With a hundred attempts duplicates are wasted, and a higher temperature spreads the samples across more distinct programs, so the chance that some sample is correct goes up even though each one is individually less likely to pass.

Ranking 100 samples by mean log-probability gave Codex-S 44.5%, but ranking by summed log-probability did slightly worse than random. Why might the sum mislead?

Show answer

A sum of log-probabilities gets more negative with every token, so it favors short programs, which are often incomplete or trivial bodies. The mean normalizes for length and measures how confident the model was per token, which tracks correctness better.

Where this sits

Models that write code

Completion, then competition, then a benchmark made of real GitHub issues — the point at which "can it code?" got an answer you could audit.

  1. 1Codex2021
  2. 2AlphaCode2022
  3. 3SWE-bench & SWE-agent2023

All 110 papers, in 19 ladders →

Finished this one? 0 / 110 Paper Breakdowns done
NextAlphaCode Next on the “Models that write code” ladder · rung 2 of 3

Explore the topic

See this alongside everything else on the same subject — handbooks, system designs, challenges and tools, in one place.

More Paper Breakdowns