01 · NxtWave · 2025

MCQ Generation Pipeline

A generative agentic workflow that turns a curriculum into a verified, curriculum-mapped pool of multiple choice questions. Six agents write the questions. Twelve decide whether any of them are good enough. The second number is the one that mattered.

Role
Pipeline design: agent roles, evaluation criteria, quality loop
Focus
multi-agent, evaluation design, LLM orchestration

The problem

A quality bar that nobody could state

A curriculum needs a large pool of questions, and it needs them at a consistent quality bar. Every subtopic needs several. Every difficulty band needs coverage. The pool has to keep growing as the curriculum does, and it has to stay honest about what it covers, because a question pool that quietly misses a third of the syllabus is worse than no pool at all. It looks like coverage.

Hand authoring does not scale here, and the reason is not the writing. A good author writes a question in a few minutes. The bottleneck is review, and review is where the whole thing comes apart. Send the same twenty questions to three reviewers and you get three different verdicts. One rejects for ambiguous stems. One rejects for distractors nobody would ever pick. One rejects for being pitched two levels below where the curriculum says the student is. None of them are wrong, and no two of them agree, so the quality of any given question ends up being a function of who happened to open it.

So the obvious move is to have a model write the questions. That part works on the first afternoon. A model will write questions all day, in volume, in house style, on any subtopic you name. Fluency was never the constraint. The constraint is that nobody can tell you which of those questions is safe to put in front of a student, and the moment you try to answer that at scale you find out you never had a definition of good in the first place. You had four reviewers with four private ones.

Generation is easy. Evaluation is the product.

That reframing is the whole project. The deliverable is not a generator. It is a set of criteria precise enough that a machine applies them the same way twice, plus the architecture that applies them in an order where each pass catches what the pass before it let through.

The cull

Watch sixty questions become nine

Six generation agents write. Twelve evaluation agents read. What follows is the evaluation layer running: a field of generated questions thinning out as each layer rejects, with the reason each item died attached to it. Four layers of three evaluators, in the order they actually run.

The counts are a representative sample rather than a published statistic. Read the shape and not the numbers. Most of what gets generated does not survive, the drop is steep at every layer, and no two layers kill for the same reason. That last part is the design.

The part nobody sees

Generation is easy.Evaluation is the product.

Six agents write questions. Twelve decide whether any of them are good enough. Almost none are. Scroll to run the evaluation.

60

generated

6 generation agents

Survived all twelve

A hook returns a new array each call. A memoised child re-renders on every parent update even when the data has not changed. Most likely cause?

  1. The array is being mutated in place
  2. A new array reference is created each call, so the memo comparison fails
  3. The child is missing a key prop
  4. The parent stores the data in state instead of props
  • factual accuracy
  • stem clarity
  • single defensible answer
  • distractor plausibility
  • distractor diversity
  • no answer leakage
  • difficulty calibration
  • cognitive level
  • stem independence
  • curriculum alignment
  • language simplicity
  • duplicate check

The hard part was never generation. It was defining what good means, twelve different ways, and designing how each layer catches what the one above it missed.

What I decided

Six decisions the pipeline is made of

  1. 01

    Decompose the curriculum before generating anything

    Ask a model for questions on React and you get questions about the three things it finds most quotable. Coverage is a property of the map, not of the model, so the syllabus gets split into granular subtopics first and every generated item carries the address of the one it was written for. That single change turns coverage from a feeling into something countable: you can point at a subtopic with two items and one with thirty, and you know which one to generate against next.

  2. 02

    Separate generation from evaluation completely

    An agent asked to write a question and then judge it grades generously, and not because it is badly prompted. It has already decided the question is fine; that is why it wrote it. Splitting the two layers means the judge has no stake in the verdict. Six agents write, twelve read, and no agent ever reviews its own output. Everything else in the design depends on that boundary holding.

  3. 03

    Give each of the twelve evaluators exactly one dimension

    A prompt asking for accuracy and clarity and difficulty and coverage returns a confident paragraph and a useless verdict. Narrowing each evaluator to one question makes its answer legible three ways: you know which dimension failed, you can tune that criterion without disturbing the other eleven, and an evaluator that has started behaving badly is diagnosable instead of smeared across the whole judgement.

  4. 04

    Define good precisely enough to be gradeable, dimension by dimension

    A high quality question is not a criterion, it is a wish. Each of the twelve dimensions had to become something a reader could rule on with no other context: does exactly one option survive scrutiny, do the wrong options fail for different reasons, could a student answer this from the stem alone. Writing those definitions was the bulk of the work, and it behaved far more like writing a product spec than like prompting.

  5. 05

    Order the layers so each one catches what the one above it missed

    The twelve are a sequence, not a committee. Accuracy runs before distractor craft, because there is nothing to evaluate about the wrong options on a question whose right answer is wrong. Curriculum alignment runs last, once the item is known to be a good question and the only remaining question is whether the pool needs it. Every layer is allowed to be narrow precisely because it can assume the layers above it already did their job.

  6. 06

    Make the pool the unit of output, not the question

    A per-question pass rate is a vanity metric. What gets delivered is a pool that covers a curriculum at a bar, and once that is the unit, discarding most of what was generated stops looking like waste. Generation is the cheap half: another pass over an under-covered subtopic costs very little, while lowering the bar to rescue questions costs the only thing the system actually produces.

How it works

Curriculum in, verified pool out

Five stages. The interesting asymmetry is between stages three and four. The generation layer is deliberately loose and productive, the evaluation layer is deliberately narrow and sequential, and the whole pipeline is built on the assumption that most of what stage three produces will not get past stage four.

  1. Step 1

    Curriculum in

    A syllabus or curriculum document, plus sample questions if any exist. It runs with no samples at all, it simply has less to calibrate house style against.

  2. Step 2

    Subtopic decomposition

    The curriculum is split into granular subtopics. Every question after this point is generated against one of them and keeps that address, which is what makes coverage countable rather than assumed.

  3. Step 3

    Generation: six agents

    Each subtopic passes through a six-agent generation layer that writes raw MCQs from different angles. Deliberate overproduction: the job is to give the evaluators enough material to be picky with.

  4. Step 4

    Evaluation: twelve agents

    Four sequential layers of three. Accuracy and clarity, then distractor quality, then difficulty calibration, then curriculum coverage. Each evaluator owns one dimension and rules on that dimension alone.

  5. Step 5

    Verified pool out

    A curriculum-mapped pool at the required bar, every item traceable to its subtopic and to the twelve verdicts it cleared. A coverage gap comes back as a generation request, never as a lowered bar.

What each evaluator is allowed to ask

The cull is the population view. This is the single item view of the same pipeline: one question that made it through, and the twelve verdicts it cleared in order, each one narrow enough to be answered pass or fail. That narrowness is what makes a verdict useful. When an item fails you know which of the twelve failed it, and you can go and argue with that one criterion instead of with the general feeling that the question was not very good.

Evaluation pass: one item, twelve verdicts

Item under evaluation

A hook returns a new array each call. A memoised child re-renders on every parent update even when the data has not changed. Most likely cause?

  1. The array is being mutated in place
  2. A new array reference is created each call, so the memo comparison fails
  3. The child is missing a key prop
  4. The parent stores the data in state instead of props

The layers run in order. Accuracy before distractor craft, because there is nothing to evaluate about the wrong options on a question whose right answer is wrong.

accuracy and clarity

evaluators 1-3

  1. 01 factual accuracyIs the keyed answer actually true?
  2. 02 stem clarityCan the stem be read only one way?
  3. 03 single defensible answerDoes exactly one option survive scrutiny?

distractor quality

evaluators 4-6

  1. 04 distractor plausibilityWould a wrong option tempt someone who half knows this?
  2. 05 distractor diversityDo the wrong options fail for different reasons?
  3. 06 no answer leakageDoes phrasing or length give the answer away?

difficulty calibration

evaluators 7-9

  1. 07 difficulty calibrationIs this pitched at the level the curriculum claims?
  2. 08 cognitive levelDoes answering need reasoning rather than recall?
  3. 09 stem independenceCan it be answered from the stem alone?

curriculum coverage

evaluators 10-12

  1. 10 curriculum alignmentDoes this map to a subtopic we actually teach?
  2. 11 language simplicityIs the difficulty about the concept, not the English?
  3. 12 duplicate checkIs this already covered by an item in the pool?
Twelve evaluators, four ordered layers. A verdict is only ever pass or fail on one dimension.

Illustrative panel, not a product screenshot. The question and the twelve dimension names are the pipeline's own.

What was hard

The honest part

Defining good twelve different ways sounds like a taxonomy exercise. It was mostly argument. Each definition had to be narrow enough that two different readers would rule the same way on the same item, and broad enough to catch more than one specific failure. Ambiguous stem is easy to say and very hard to grade, so it had to become something like can the stem be read only one way, which is answerable. Multiply that by twelve, then check the twelve do not quietly overlap, because two evaluators enforcing the same criterion is not redundancy. It is one wasted evaluator and a blind spot somewhere else.

Then there is what happens when an agent produces junk. Occasionally a generation agent returns something that is not really a question: four options where two say the same thing, a stem referencing a code block it never included, an answer key pointing at an option that is not there. Deciding what the pipeline does with those mattered more than reducing how often they happen. Dropping them silently hides a generation problem. Passing them through spends twelve verdicts on something that was never a question. So malformed output fails structurally, before evaluation, and it gets counted, because that count is the only early signal that a generation prompt has drifted.

The harder failure mode is the opposite one: an evaluation layer so strict that nothing survives. Every time a criterion got tightened survival dropped, and from the inside a well calibrated bar and an overfit one look identical. A layer that rejects almost everything even reads as rigour on a dashboard. The only check that worked was reading the rejections rather than the survivors. If a strict evaluator is throwing out questions a competent human author would have shipped without hesitation, the criterion is wrong, not the questions.

Underneath all of it is an asymmetry that decides every close call. A question thrown away costs one more generation pass, which is cheap. A wrong question reaching a student teaches them something false, and they will not argue with it, because they trust that the platform is teaching them correctly. They will remember the wrong answer as the right one and be marked correct for it later.

A rejected question costs one generation pass. A wrong question costs a student their trust in being taught correctly.

That asymmetry is why the evaluation layer has twice as many agents as the generation layer, and why every ambiguous verdict resolves toward rejection.

Outcome

Review stopped being the bottleneck

The pipeline runs end to end. A curriculum goes in, a curriculum-mapped pool comes out, and every item in it carries the record of which subtopic it belongs to and which twelve verdicts it cleared. That record is what changed the working process. Review stopped being a queue of questions somebody had to read and became sampling: nobody reads every item, and the thing worth reading is the rejections, because the rejections are where you find out whether a criterion is doing what you meant it to do.

The more durable shift is where quality lives. It used to be a property of whoever reviewed an item. Now it is a property of the criteria themselves, which means moving the bar is an edit to a definition rather than a conversation with four people who each had a different bar in their head. That is a smaller sounding outcome than a percentage and a considerably more useful one.

There are no public numbers to report here, so there are none on this page. The survivor counts in the cull above are a representative sample where the ratios are the honest part, and the figures below describe the shape of the system rather than its performance.

  • 6 + 12

    agents in the pipeline

    generation, then evaluation

  • 1

    dimension per evaluator

    one question, one owner

  • 4

    sequential evaluation layers

    each catches the last one's misses

What I would do differently

Criteria first, prompts second

I would write the twelve criteria before writing a single generation prompt. We built generation first because it was the half that visibly worked, then spent far longer than we needed to discovering that most of our disagreements about output quality were undefined criteria wearing a disguise. The definitions were the actual spec. Written first, the generation prompts would have fallen out of them almost for free, and we would have had a way to tell a strict layer from a broken one immediately instead of only once there was a pile of rejections to argue over.