Why a Different Model Should Review the Code an AI Wrote
A model reviewing its own output shares its own blind spots. Route the diff to independent models from other providers and cross-check the results.
When one AI model writes a patch and the same model reviews it, the review is close to worthless on the bugs that matter. The model that produced the code also produced the reasoning behind it, so it carries that reasoning into the review and confirms its own work. If it hallucinated an API that does not exist, it will read the call as correct. If it misread the spec, it will grade the code against the same misreading. This is the machine version of a person proofreading their own writing and skimming past the typo they have read ten times.
The fix is not a better prompt. It is a second opinion from a model that did not write the code, ideally from a different provider trained on different data. Send the same diff to two or three independent models, ask each one for the bugs and risks, then combine their verdicts with a fixed rule. Where their blind spots do not overlap, the cross-check catches what a single reviewer misses. This post is about how to run that, what it costs, and when a single review is already enough.
Self-review shares the author's blind spots
A code review is only useful when the reviewer can see something the author could not. Two humans work because they have different mental models, different scars from different past bugs, and different assumptions about what the code is supposed to do. The reviewer flags the case the author never pictured.
A model reviewing its own output has none of that distance. Its "opinion" of the code is a continuation of the same weights, the same training data, and often the same context window that generated the code in the first place. Ask it "are there bugs here?" right after it wrote the function, and you are asking the author to disagree with the author. It will find surface issues, a missing nil check, an obvious typo, but the subtle logic error that came from a wrong assumption tends to survive, because the review inherits the assumption.
Empirically the failures cluster in a few places. A hallucinated method or field passes self-review because the model still believes the method exists. An off-by-one in a boundary condition passes because the model's idea of the boundary is the same wrong idea on both passes. A security gap, say a missing authorization check, passes because the model was focused on the happy path both times. These are exactly the defects that are expensive to catch later, and exactly the ones self-review is worst at.
Different models fail in different places
The reason a second model helps is that models do not share one set of blind spots. Each one was trained on a different mix of data, tuned with different objectives, and lands in a different place on the tradeoff between caution and confidence. One model is strong at spotting concurrency hazards and weak at SQL. Another reads data-flow well but waves through a race condition. Their errors are not identical, and that is the whole point.
This is the same idea that makes an ensemble beat a single classifier. If three reviewers each miss 30 percent of real defects, but they miss different 30 percents, the chance that all three miss the same specific bug is far lower than 30 percent. Independent errors cancel. The catch, and it is a real one, is the word independent. Two models from the same family, or the same model prompted twice, do not give you independent errors. They give you the same error twice with more confidence. To get the benefit you need genuine diversity of source: different providers, different model families, not two temperatures of one model.
So the design goal is not "more reviews." It is "reviews whose mistakes are uncorrelated." A single review from a truly different model is worth more than five re-rolls of the author model.
The workflow, step by step
The pipeline is small. One model writes, several independent models judge, a rule combines the judgments, and a human breaks ties.
| Step | Who | Output |
|---|---|---|
| 1. Implement | Author model | The diff or patch |
| 2. Review, in parallel | N independent models, none of them the author | Per-model verdict: GO or NO-GO, plus findings |
| 3. Apply consensus rule | Automation | Pass, fail, or escalate |
| 4. Resolve disagreement | Human | Final call on split verdicts |
Two properties make this work. The reviewers run independently, so they cannot anchor on each other. And each reviewer gets the same neutral prompt, so a NO-GO means the same thing across models. Keep the author model out of the review pool entirely. Its vote is the one you already have and the one you least trust.
Here is the shape of it in pseudocode:
def multi_model_review(diff, author_model, reviewers, rule):
verdicts = []
for model in reviewers: # reviewers excludes author_model
v = model.review(
diff=diff,
prompt="List concrete bugs, security risks, and correctness "
"issues in this change. Then answer GO or NO-GO.",
)
verdicts.append(v)
passed = rule(verdicts) # unanimous or majority, see below
if passed is UNDECIDED:
return escalate_to_human(diff, verdicts)
return passed, verdicts
The review call returns two things: a list of concrete findings and a single GO or NO-GO. The findings are what a human reads when a review fails. The GO or NO-GO is what the rule consumes.
Choose a consensus rule that matches the stakes
The rule that turns several verdicts into one decision is where you tune strictness. There are two sensible defaults and a spectrum between them.
Unanimous GO is the strict rule: the change passes only if every reviewer says GO, and a single NO-GO blocks it. This maximizes recall on bugs, you catch anything that any model can see, at the cost of more false alarms, since one overcautious reviewer stops the change. Use it for code that is hard to undo.
Majority GO is the lenient rule: the change passes if most reviewers say GO. A lone NO-GO from a model that is prone to crying wolf does not block the merge, but two out of three agreeing on a problem does. This trades a little bug-catching for far less friction. Use it for ordinary changes where a missed issue is cheap to fix in the next commit.
def unanimous(verdicts):
if all(v.decision == "GO" for v in verdicts):
return PASS
if all(v.decision == "NO_GO" for v in verdicts):
return FAIL
return UNDECIDED # split -> human decides
def majority(verdicts):
gos = sum(v.decision == "GO" for v in verdicts)
if gos > len(verdicts) / 2:
return PASS
return FAIL
Notice what the unanimous rule does with a split: it does not silently pick a side. It escalates. A disagreement between capable, independent reviewers is a strong signal that the change is genuinely ambiguous, and that is precisely the case worth a human minute. Treating a split as "eh, majority wins" throws away the most valuable output of the whole exercise.
Adversarial prompts beat "does this look right?"
How you ask matters as much as who you ask. The default review prompt, "does this look correct?", invites the model to agree, because agreeing is the easy completion. You get confirmation, not scrutiny. Two adjustments push against that.
The first is to make the reviewer argue against the code. Instead of "review this," ask "your job is to find why this change is wrong. Give me the strongest case that it has a bug." Framing the task as refutation reduces the pull toward agreement. The model is now rewarded for finding a flaw, not for blessing the diff, and it will surface concerns it would have smoothed over under a neutral prompt. You are not asking it to be right about the flaw, you are asking it to look hard, and a human filters the false alarms afterward.
The second is to give each reviewer a different lens. Rather than three general reviews, assign roles: one reviewer checks correctness against the spec, one checks security and input handling, one checks performance and resource use. Same diff, three angles. This widens coverage on purpose and keeps two reviewers from spending their whole budget on the same obvious issue while a third area goes unlooked-at.
Reviewer A: "Find correctness bugs. Where does this violate the stated behavior?"
Reviewer B: "Find security holes. Assume the input is hostile."
Reviewer C: "Find performance and resource problems under load."
Refutation and role diversity stack. An adversarial security reviewer on a different model from the author is about as far from self-confirmation as you can get with automation alone.
What it costs, and when to skip it
None of this is free. You are running the model call two or three extra times per change, so you pay two or three times the tokens and you add latency, since the slowest reviewer sets the pace even when they run in parallel. On a small or reversible change, that overhead buys almost nothing. Fixing a typo in a log line does not need a tribunal.
The value shows up on changes that are important and hard to walk back:
- A database migration that rewrites data in place.
- Deploy and infrastructure code where a mistake takes down production.
- An authorization or billing path where a subtle bug is a security or money problem.
- A one-way change, anything you cannot cleanly revert once it ships.
For those, the cost of three model calls is trivial next to the cost of the bug, and the strict unanimous rule earns its false alarms. For a routine change behind a feature flag that you can flip off in seconds, a single review, or none, is the right call. Match the ceremony to the blast radius.
A tiered policy captures this without thinking about it each time:
| Change type | Reviewers | Rule |
|---|---|---|
| Trivial or reversible | 1 (or author self-check) | Advisory only |
| Normal feature work | 2 independent | Majority GO |
| Migration, deploy, auth, billing | 3 independent | Unanimous GO |
The failure mode: models that agree can all be wrong
The honest limit of this technique is the correlated blind spot. Independent errors cancel only when the errors are actually independent. If every model in your pool learned the same wrong idiom from the same popular but buggy examples on the public internet, they will all repeat it, and they will all approve it, unanimously and confidently. Consensus is evidence, not proof. A green light from three models means three models did not see a problem, which is not the same as there being no problem.
This matters most for the newest kinds of bug and the most domain-specific ones. A subtle flaw in a brand-new framework, or a business rule that lives only in your company's head and nowhere in any training set, is invisible to all of them at once. No amount of cross-checking conjures knowledge that none of the reviewers have. Multi-model review shrinks the class of bugs that slip through, it does not empty it.
So keep the human in the loop where the stakes justify it, and read the actual findings, not just the GO or NO-GO tally. The verdicts are a filter that makes human attention go further, not a replacement for it. Use a different model to review the code an AI wrote, because a second set of blind spots is better than one. Just do not mistake agreement between machines for the truth.
Related posts
How Session Handoffs Keep Context Across AI Coding Sessions
AI coding agents forget everything when a session ends. A short handoff note carries what you did, what is unfinished, and what comes next.
Use an AI Agent as Your Shell Front End, Not More Aliases
The graveyard of forgotten shell scripts has an alternative. Describe the task in plain words and let an AI assemble grep, awk, and jq for you.