Writing

Have AI Review AI: Building a Verification Loop You Can Trust

Have AI Review AI: Building a Verification Loop You Can Trust - abstract illustration

A model will hand you a wrong answer with exactly the same confidence it hands you a right one. There's no tremor in the output, no hedge, no tell. That's the core problem with shipping the first thing a model produces: the output looks finished whether or not it's correct. The fix isn't a better prompt on the first pass. The fix is a second pass whose entire job is to find what the first pass got wrong.

I run this loop across my agent fleet, and it catches things I would have shipped otherwise. This is how I build it.

A First Draft Is a Draft

The generation step of any AI task is optimistic by construction. The model is trying to finish. It wants to produce something coherent and complete, and it will bridge gaps with plausible-sounding material rather than stop and flag uncertainty. That's usually what you want from a generator. It's exactly what you don't want to be the last word.

The failure mode this produces is specific. The model doesn't fail loudly with a stack trace. It fails quietly with a function that looks right, compiles, and is wrong in a way you will discover in production three weeks later. It invents a config key that doesn't exist. It calls an API method with the wrong argument order. It writes a migration that works on an empty table and locks a real one. Each of these reads as finished work.

So treat the first output as a draft, always. Not because the model is bad at its job, but because the generation objective and the correctness objective are not the same objective. You need a second step whose objective actually is correctness.

The Review Pass Needs a Clean Context

The obvious move is to ask the same conversation: "is this correct?" This is the trap. The model that just wrote the code is the worst possible reviewer of it. It has all of its own reasoning in context, it's anchored on the choices it already made, and it's heavily biased toward agreeing with itself. Ask it to check its work and it will almost always tell you the work is fine. It's not lying. It's reading its own justification back to you.

The mechanism that fixes this is a fresh context. Start a new conversation, or spawn a separate reviewer, that has never seen the generator's reasoning. Give it the artifact and the requirement, and nothing about how the artifact came to exist. Now it has to actually evaluate the code against the spec instead of confirming a chain of thought it already believes.

Concretely, in my setup, the generator and the reviewer are two different invocations with two different system prompts. The reviewer receives the diff, the relevant files, and the task description. It doesn't receive the generator's transcript. That single separation is most of the value. This pairs naturally with scoping the task to fit the context window so the reviewer can hold the whole change at once instead of squinting at a fragment.

Prompt the Reviewer to Be Adversarial

A neutral reviewer is a weak reviewer. If you ask "does this look okay," you're inviting the same optimism that produced the draft. Ask the reviewer to assume the work is broken and go find where.

The prompts that actually surface problems are adversarial:

  • "There is at least one bug in this diff. Find it." Assuming a bug exists changes the search. The reviewer stops confirming and starts hunting.
  • "Refute this claim." If the generator asserts the change is backward compatible, make the reviewer argue that it isn't, and produce the case where it breaks.
  • "What input makes this fail?" Forces consideration of empty lists, nulls, concurrent access, the second call, the timezone boundary.
  • "List every assumption this code makes about its inputs and environment, then flag the ones that are not guaranteed."

The framing does real work. A model told to find fault will find fault it would have glossed over if you had asked it to give feedback. Some of what it flags will be noise, and that's fine. The cost of a false positive in review is a minute of your attention. The cost of a false negative is the bug you shipped.

Use a Strong Model to Review a Fast One

The generator and the reviewer don't need to be the same model, and usually shouldn't be. Bulk generation is a good fit for a fast model: Sonnet writes code quickly and well, and most of what it produces is fine. Review is a reasoning-heavy task where the marginal value of a more capable model is high. That's where a high-capability model, Opus or Fable, earns its cost.

The asymmetry is favorable. You run the fast, cheaper model on the large-volume step and the strong model on the single verification step. The strong model reads the diff once and tells you where it's thin. Paying more per token to review one change is roughly an order of magnitude cheaper than paying a senior engineer to trace the incident it would have caused. This is the same logic as matching the model to the task applied to the review step specifically: plan and verify with the capable model, generate with the fast one.

Make the Review Output Structured

A review that comes back as three paragraphs of prose is hard to act on. You end up re-reading it to figure out what actually needs a change versus what's a stylistic aside. Ask for structure so the output is directly actionable.

I have reviewers return findings as a list, each with:

  • Location. File and line, or the specific function. A finding you can't locate is a finding you won't fix.
  • Severity. Something like blocker, warning, or nit. This lets you triage: fix the blockers now, batch the nits, ignore the noise.
  • The claim. What's wrong, stated as a falsifiable assertion, not a vibe. "This throws on an empty result set" beats "error handling could be improved."
  • The fix, or a proposed one. Optional, but it turns a report into something you can apply.

Structured output also composes with the rest of a pipeline. A blocker-severity finding can gate a merge. A clean review can advance the task. Prose can't drive a decision like that without a human re-reading it every time. This is the same discipline I apply to data parsing pipelines: if you want to act on a model's output programmatically, make it emit structure, not paragraphs.

Where the Human Belongs

Automating the review loop doesn't mean removing yourself. It means moving your attention to where it's worth the most. The reviewer catches the mechanical errors: the wrong argument, the unhandled case, the assumption that doesn't hold. That frees you to look at the things a model still can't judge well.

Put yourself in the loop for consequential changes. Anything that touches money, deletes data, alters security or auth, or is hard to reverse gets a human gate regardless of how clean the automated review came back. The loop is a filter that removes the obvious problems before they reach you, not a replacement for judgment on the changes that matter. A schema migration, a change to how secrets are handled, a rewrite of billing logic: two AI passes agreeing doesn't clear those. Two AI passes agreeing means the change is ready for you to look at, not past you.

The distribution is roughly this. Most changes are low-stakes, the automated loop handles them, and you spot-check. A meaningful minority are consequential, and those you read yourself with the review as a head start. You're not reviewing everything. You're reviewing the things that would hurt.

The Loop, End to End

Put together, the pattern is small: generate with a fast model, review with a strong model in a clean context, prompt the reviewer to find fault, get structured findings back, fix the blockers, and gate the consequential changes on a human. None of the steps are expensive. The whole thing is cheaper than the incidents it prevents.

The reason it works is that it stops asking one optimistic process to also be its own skeptic. The generator finishes. The reviewer doubts. Keeping those two jobs in two heads, even when both heads are the same model family, is the entire point. A model that hasn't seen how the answer was built is the only one that can honestly ask whether it's right.

Building something like this?

This is the kind of work I do for clients. Tell me what you're building and I'll give you a straight read on the approach.

Book a 30-minute call