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?
Rules on the diff send small changes to a cheaper, faster model and risky ones to the best.
Docs for Model RoutingEvery pull request goes to the same model with the same prompt, whatever its size.
Docs for Single ModelFor 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.
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.
- 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
- ✓S1 Cents aren't zero-padded, so 1205 shows as $12.5
- ✓S2 An empty cart reads "0 item"
| Model | Caught | Time | Cost |
|---|---|---|---|
| Haiku 5.5 | 2 of 2 | 3.8 s | $0.0005 |
| Sonnet 5.5 | 2 of 2 | 11.2 s | $0.015 |
| Opus 5.5 | 2 of 2 | 19.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.
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.
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 monthWhat they look likeRouting 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.
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
| Criterion | Model Routing | Single Model |
|---|---|---|
| Code you maintain | The review call, plus a router of about 20 lines | The review call |
| Model per pull request | Haiku 5.5, Sonnet 5.5 or Opus 5.5, picked by rules on the diff | Opus 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 change | Shortest, because it goes to the fastest model | Same model and effort as the biggest change |
| Risky changes | Only as safe as the router; a missed auth path goes to a cheaper model | Always reviewed by the best model |
| Prompt caching | A separate cache for each model | One cache |
| When a new model ships | Recheck every tier and the thresholds | Change one model ID |
When to pick which
- 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
- 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.