Skip to content
← All writing

Route cheap models to orchestration, not to the work

4 min readUpdated
.md
Cover illustration for Route cheap models to orchestration, not to the work

TL;DR

Assign models by agent role, not by task. Orchestration and classification are routing problems with tiny output spaces, so a small model handles them as well as a frontier one. Reserving frontier models for actual reasoning cut my cost per completed task by just over half.

The first version of my agent harness used one model for everything. It was the obvious choice: one provider, one set of prompts, one place to tune. It also meant a frontier model was deciding which sub-agent should handle a request, reading a tool manifest, and emitting about forty tokens of JSON. That decision cost the same per token as the reasoning we actually cared about.

Splitting model selection by role rather than by task is where the cost curve bent.

Why is orchestration a routing problem, not a reasoning problem?

An orchestrator agent does a narrow job. It reads a user message, looks at a list of available specialists, and emits a choice. There is very little latent reasoning in that step, and the output space is tiny. Once the tool manifest is well described, a small model is close to indistinguishable from a large one at it.

The roles, and what makes each one cheap or expensive to serve:

RoleOutput spaceLatent reasoningTier it needs
OrchestratorOne name from a known listAlmost none once the manifest is well describedSmall
ClassifierOne label from a fixed setAlmost noneSmall
SummariserBounded prose over supplied textSome, but the input carries the contentMid
ReasonerOpen endedThis is the actual workFrontier

The mapping lives in one file. Model identifiers are the real ones: Workers AI models are prefixed @cf/, and Anthropic publishes its model identifiers separately.

const ROLE_MODELS = {
  orchestrator: '@cf/meta/llama-3.1-8b-instruct',
  classifier: '@cf/meta/llama-3.1-8b-instruct',
  summariser: 'claude-haiku-4-5',
  reasoner: 'claude-opus-5',
} as const

type Role = keyof typeof ROLE_MODELS

export async function runRole(env: Env, role: Role, prompt: string) {
  const model = ROLE_MODELS[role]

  // Workers AI models run on the binding; frontier models go out over the API.
  if (model.startsWith('@cf/')) {
    return env.AI.run(model, { prompt })
  }

  return callAnthropic(env, model, prompt)
}

The Workers AI binding is declared in the Wrangler config, so no key management is needed for the cheap tier:

[ai]
binding = "AI"

The important property is that the mapping is declarative and lives in one place. When a provider ships something cheaper, you change a string. You do not go hunting for the seven call sites where a model name was inlined.

Measure per role before you optimise

I only found the orchestration overhead because token metering was tagged by role from the start. Aggregate token counts told me I was spending a lot. Per-role counts told me that a third of spend was going to a step whose entire output was a sub-agent name.

RoleShare of callsShare of spend beforeAfter
Orchestrator41%33%4%
Reasoner22%48%61%
Summariser37%19%35%

Spend did not just move around. Total cost per completed task dropped by a bit over half, and the reasoner got a larger share of a smaller bill, which is the direction you want.

Before reaching for a cheaper model, check what you are re-sending. Anthropic’s prompt caching removes a large part of the cost of a stable system prompt, and it applies regardless of which tier you settle on.

Fallback is part of the design, not an afterthought

Cheap models fail more often, and they fail differently. A small orchestrator will occasionally emit a sub-agent name that does not exist. That is fine, as long as the harness treats an invalid choice as a signal rather than an exception:

  1. Validate the choice against the live manifest.
  2. On a miss, retry once at the same tier with the manifest restated.
  3. On a second miss, escalate to the next tier up and record the escalation.

The escalation rate is the number to watch, and it reads in both directions:

Escalation rate for a roleWhat it meansWhat to do
Near zero for weeksThe role is over-provisionedTry the next tier down
Low single digitsCorrectly tieredLeave it alone
Above a few percentMis-tiered, or the manifest is badly describedFix the manifest first, then move the tier
Climbing over timeThe task shape has drifted from the mappingRe-examine what the role is actually being asked to do

The goal is not the cheapest possible model. It is the cheapest model whose failure mode you have already handled.

What this does not solve

Per-role routing does nothing for a badly shaped task. If a single agent turn is doing retrieval, reasoning and formatting at once, no amount of model selection will make it cheap, because the expensive part is the context you keep re-sending. Decomposition comes first. Routing is what you do once the roles are actually distinct.

Sources

Common questions

Should you use the same LLM for every agent in a system?

No. Assign models by role rather than by task. An orchestrator reads a message, looks at a list of specialists and emits a choice, which is a routing problem with a tiny output space. Paying frontier prices for roughly forty tokens of JSON is the most common avoidable cost in an agent harness.

How much does routing models by role actually save?

In my harness, orchestration fell from 33% of spend to 4%, and total cost per completed task dropped by a bit over half. The reasoner ended up with a larger share of a smaller bill, which is the direction you want, because spend moved toward the step that does the actual work.

How do you know which agent role is wasting money?

Tag token metering by role from the start. Aggregate token counts only tell you that you are spending a lot. Per-role counts are what revealed that a third of spend was going to a step whose entire output was a sub-agent name.

What happens when a cheap model picks a sub-agent that does not exist?

Treat it as a signal rather than an exception. Validate the choice against the live manifest, retry once at the same tier with the manifest restated, and escalate to the next tier up on a second miss while recording the escalation. The escalation rate then tells you whether the role is correctly tiered.

When does model routing not help?

When the task itself is badly shaped. If a single agent turn does retrieval, reasoning and formatting at once, the expensive part is the context being re-sent, and no model choice fixes that. Decomposition comes first; routing is what you do once the roles are genuinely distinct.

Written by Elson Tan, Head of Technology and co-founder at Nedex Group, working on AI harness and agent infrastructure.

AboutRSS
  • 5 min read

    Metering tokens when the bill is the product

    Billing per message is easy and wrong: one user sends a sentence, another uploads a report. Metering the tokens you actually spend is harder, and the hard parts are idempotency, allowance checks and what to do mid-conversation.

  • 17 min read

    The product was the easy part

    What a SaaS needs before it can charge anyone: credit billing in Stripe, invoicing and sales tax, email unsubscribe law, terms and privacy, and an admin panel.

  • 5 min read

    Citations that survive the question

    A RAG answer with a source name under it is not a citation. If a teacher cannot open the page and see the sentence, the system has not shown its work. Carrying page numbers through retrieval is most of the job.

Get in touch

Tell me who you are and what you are working on.

Your details are used only to reply to this message.