ComparisonNew

Model Routing vs Single Model

Should your AI code reviewer pick a model for each pull request, or send every pull request to the same one?

Alex Garrett-SmithNov 35 minAgents and context
Model Routing

Rules on the diff send small changes to a cheaper, faster model and risky ones to the best.

Docs for Model Routing
Single Model

Every pull request goes to the same model with the same prompt, whatever its size.

Docs for Single Model

For PR reviews I'd start with one model. In the worked example below, routing caught the same bugs for less money and less waiting, but only because a path rule sent the auth change to Opus. At a few hundred PRs a month it saves less than an hour of a developer's time, so I'd only route once you're reviewing thousands a month or people are stuck waiting on reviews.

Try it

Route three pull requests

Here are three pull requests with bugs planted in them. The smallest changes a price formatter and the riskiest changes how refresh tokens work. Pick one, then switch between sending everything to Opus and letting the router decide, and see what each review caught.

Opus 5.5One model reviews every pull request, whatever its size.
  • majorformatPrice drops the leading zero on cents (1205 becomes $12.5)format.ts:8✓ S1
  • minorAn empty cart reads "0 item"format.ts:12✓ S2
  • minorRefunds (negative totals) format as $-2.-50format.ts:6Extra, real
  • minorThe tests only use amounts where the bug doesn't showformat.test.ts:6Extra, real
Time
19.6 s
Tokens in/out
610 / 1,800
Cost
$0.038
Planted bugs2 of 2 caught
  • ✓S1 Cents aren't zero-padded, so 1205 shows as $12.5
  • ✓S2 An empty cart reads "0 item"
Every model on this pull request
Model Caught Time Cost
Haiku 5.52 of 23.8 s$0.0005
Sonnet 5.52 of 211.2 s$0.015
Opus 5.52 of 219.6 s$0.038

Opus found the same two bugs as Haiku, plus a test that hides them, but it took five times as long.

All three pull requests
Opus for everything
9 of 9 bugs
Wait 1 min 38 s
Cost $0.242
Routed by the diff
9 of 9 bugs
Wait 1 min 8 s
Cost $0.150

Treat this as a worked example. The diffs, planted bugs, router rules and prices are real, but the reviews, timings and output token counts are made up to show how the comparison works. Every review used the same prompt with effort set to high, and you can run the same comparison on your own pull requests with the code below.

Your volume

What routing saves at your volume

Three pull requests don't tell you much about your bill, so let's scale it up. Pick how many pull requests your team opens a month and what most of them look like.

Pull requests a month
What they look like
Opus for everything$31.08 a monthAverage review 26.5 s
Routed by the diff$11.15 a monthAverage review 12.8 s

Routing would save you about $19.93 a month. That's less than an hour of a developer's time, so I'd stick with one model. And the average review would come back in 12.8 s instead of 26.5 s.

Each pull request is priced like the example of its size above, with the path rule on. The prices are Anthropic's published API rates; the token counts come from the made-up runs, so treat the totals as a rough guide and plug in your own.

The code

How much code routing adds

Here's everything behind both approaches, using the Anthropic TypeScript SDK. The routed version is the same call with a router in front of it, and the highlighted lines are what it adds.

import Anthropic from '@anthropic-ai/sdk' const client = new Anthropic() const SYSTEM = `You review pull requests. Report every problem that should be fixedbefore it merges: bugs, security issues, performance problems and missing edgecases. Leave out style preferences.` const MODEL_FOR = {  simple: 'claude-haiku-5-5',  medium: 'claude-sonnet-5-5',  complex: 'claude-opus-5-5'} // Changes here always get the best model, however small they areconst RISKY_PATH = /(^|\/)(auth|payments|billing|migrations|security)\// function classify(diff: string): keyof typeof MODEL_FOR {  const files = [...diff.matchAll(/^\+\+\+ b\/(.+)$/gm)].map(match => match[1]!)  const changedLines = diff.split('\n')    .filter(line => /^[+-]/.test(line) && !/^(\+\+\+|---) /.test(line))    .length   if (files.some(file => RISKY_PATH.test(file)) || changedLines > 300) {    return 'complex'  }  if (changedLines > 40 || files.length > 2) {    return 'medium'  }  return 'simple'} export async function reviewPullRequest(diff: string) {  return client.messages.create({    model: MODEL_FOR[classify(diff)],    max_tokens: 16000,    system: SYSTEM,    output_config: { effort: 'high' },    messages: [{ role: 'user', content: `<diff>\n${diff}</diff>` }]  })}

The router only reads the diff, so it doesn't add an API call or any waiting. What can go wrong is a dangerous change that looks small, like the refresh token pull request above when the path rule is off.

Side by side

CriterionModel RoutingSingle Model
Code you maintainThe review call, plus a router of about 20 linesThe review call
Model per pull requestHaiku 5.5, Sonnet 5.5 or Opus 5.5, picked by rules on the diffOpus 5.5 every time
Price per million tokens, in/out$0.10/$0.50 (Haiku), $2/$10 (Sonnet), $4/$20 (Opus)$4/$20
Waiting on a small changeShortest, because it goes to the fastest modelSame model and effort as the biggest change
Risky changesOnly as safe as the router; a missed auth path goes to a cheaper modelAlways reviewed by the best model
Prompt cachingA separate cache for each modelOne cache
When a new model shipsRecheck every tier and the thresholdsChange one model ID

When to pick which

Pick Model Routing if
  • You review thousands of pull requests a month
  • Most of your PRs are small fixes and dependency bumps
  • People wait for the review before they can merge
  • You can list the folders that always need your best model
Pick Single Model if
  • Your team opens a few hundred PRs a month or fewer
  • A missed bug costs you far more than the review bill
  • You don't want to retest three models every time one changes
  • Risky code is spread across the codebase, not in a few folders

How we tested

Task
Reviewed three sample pull requests with nine planted bugs (a 24-line price formatting change, a 67-line invoice endpoint and a 60-line refresh token change) on Haiku 5.5, Sonnet 5.5 and Opus 5.5, with the same prompt and a rule-based router.
Evidence
A worked example, not a benchmark. The diffs, bugs, router and prices are real; the review output, timings and token counts are made up.
With
Claude Haiku 5.5, effort high, Claude Sonnet 5.5, effort high, Claude Opus 5.5, effort high, A router on changed lines, files and paths

Updates

  • Published.