Using a frontier model for every request can increase costs when smaller models can handle much of the workload. Summarization, ticket classification, and extraction often need less capability than complex reasoning.
Build a router that classifies each request, selects a model tier, and sends the call through the AI Gateway. This guide uses Jev or OpenAI Decisions to select a model tier, AI Gateway to run generation, and budget limits to control spending.
Copy link to headingPrerequisites
Before you begin, ensure you have:
- Node.js 22.18 or newer
- A Next.js 16 project with TypeScript and the App Router
- A Vercel account with AI Gateway access
This guide uses the AI SDK 7.0.155. Its Decision API is experimental, so keep the tested version pinned while following along. The file paths below assume your Next.js project uses the @/* alias for its root directory. If it uses a src/ directory, place app/ and lib/ there instead.
Copy link to headingHow it works
Cost-aware routing has three moving parts:
- The AI SDK provides the same interface for every generation call. Model identifiers such as
openai/gpt-6-lunaresolve through the AI Gateway by default, so you can change providers without installing a separate SDK for each one. - The classifier first applies a few explicit rules. When those rules leave a request undecided, it asks Jev or OpenAI Decisions API to choose between the fast and frontier tiers. Your code sets the probability threshold and decides what happens next.
- AI Gateway handles authentication, provider routing, model fallbacks, budgets, and observability.
Copy link to headingConfigure AI Gateway with the AI SDK
Copy link to heading1. Install the dependencies
Run the following command to install AI SDK and Zod:
AI Gateway authenticates requests using Vercel OIDC tokens, which Vercel generates and links to your project automatically. Use the Vercel CLI to link the project and pull environment variables:
These commands add the VERCEL_OIDC_TOKEN to .env.local, which the SDK automatically detects and uses for authentication:
Local OIDC tokens are valid for 12 hours. Run vercel env pull again to refresh yours. If AI_GATEWAY_API_KEY is set, the SDK uses that credential instead.
Copy link to heading2. Use AI Gateway
You can use any model by specifying its name in the model option. To validate the setup, create scripts/gateway-smoke.mts:
Run it from the project root:
You should see a short answer. If you see an authentication error, a credits error, or no_providers_available, resolve the setup or model access issue before continuing.
Copy link to headingDefine your model tiers
A TIERS config object keeps generation model choices in one place, so the rest of the router stays model-agnostic. Each tier gets a primary model and a fallback from a different provider, which is what the router falls back to when a primary call fails. Create lib/tiers.ts:
Pick models based on cost, latency, and measured quality for the job the tier performs. The profiles above are example routing rubrics. Evaluate both tiers on representative requests, label the lowest-cost tier that meets the same acceptance criteria, and refine the profiles based on those results. Check their availability and current prices in the AI Gateway model catalog.
Keep model construction in one module, too. The budget section can then change credentials for all routed calls in that file. Create lib/models.ts:
Copy link to headingClassify request difficulty
Copy link to headingHeuristic classification without a model call
A heuristic checks the request for early signals and returns a tier, or null when it has no clear rule to apply. It adds zero latency and zero cost. Create lib/classify-heuristic.ts:
Treat the code and keyword checks as placeholders to start with. These checks route matches to the frontier, leaving everything else to the decision model. Request length does not select a tier. A short request can be difficult, and a long one can be straightforward. Narrow or remove a rule when evaluation shows it makes the wrong decision too often.
Copy link to headingClassify ambiguous requests with the AI SDK
When the heuristic returns null, the selected decision model can choose between the two tiers using a typed choice question. Use the AI SDK’s experimental_decide function to call the selected decision model through the AI Gateway.
The DECISION_MODELS config provides the typesafe-ai/jev and openai/gpt-6-luna-decisions model IDs.
Create lib/classify-decision.ts:
The classifier receives the request, along with the configured generation models and profiles. If your application has relevant conversation context or output requirements, include them in the classifier input.
This policy accepts the fast tier only when the decision model selects it and its probability meets the threshold. The policy selects the frontier when the decision is uncertain or has no probability distribution. The 0.85 threshold is an example to tune against labeled requests. It does not guarantee an 85% chance of an acceptable answer. Choice probabilities and a provider's separate confidence statistic are different values. See the SDK's probability guidance.
The two examples below share the same input, tier profiles, criteria, and probability policy. Only the decision model changes.
Copy link to headingJev example
Create lib/classify-jev.ts. This wrapper selects typesafe-ai/jev:
Copy link to headingOpenAI Decisions example
Create lib/classify-openai.ts. This wrapper selects openai/gpt-6-luna-decisions:
Use a separate holdout set to compare this policy with always-fast, always-frontier, and the heuristic baseline. Include short, difficult requests and long, routine requests, and measure the rate of incorrect fast routes alongside total cost and latency. Use one decision model per request. When comparing Jev and OpenAI Decisions, evaluate both on the same labeled set.
Copy link to headingRoute by tier with a single model-agnostic call
routeTier() selects a tier, then generate() calls that tier's model. The router reads from TIERS, and the model factory supplies the credentials. When the primary model cannot serve the request, AI Gateway's model fallbacks supply the second option under the same credentials.
Create lib/route.ts:
Classification chooses the tier, and the config resolves it to a model. The generation call receives that model and returns text. Changing the config leaves the call site unchanged. Pass "jev" or "openai" as the second argument to generate() to select the classifier. configuredDecisionProvider records that setting. An explicit heuristic rule can select the frontier without calling either decision model.
configuredPrimary names the first model requested. A fallback can serve the answer, so use AI Gateway's routing metadata or request logs when you need the serving model itself.
Copy link to headingEscalate to the frontier model
You can also start with the fast tier and escalate only when an answer fails a verifiable check. Use this as an alternative for a specific task, such as extracting a city and a supporting quote from supplied text. It does not need a decision call before the first attempt.
Create lib/escalate.ts:
Copy link to headingCap spend per tier with API key budgets
AI Gateway budgets let each tier reject further requests once it reaches its spending limit. Budgets can apply to several scopes, including teams, projects, and API keys. For independent limits on the router, fast tier, and frontier tier, create three AI Gateway API keys and set a budget on each.
Add the keys as ROUTER_GATEWAY_KEY, FAST_GATEWAY_KEY, and FRONTIER_GATEWAY_KEY in .env.local and in the appropriate Vercel project environments. Then replace lib/models.ts with this complete version:
Every router call now uses the router key, and every generation or extraction call uses its tier's key, including AI Gateway's configured fallback. A missing key stops setup instead of silently using the ambient OIDC token.
Budgets are soft caps checked when requests start. In-flight requests can finish after spending crosses the limit, including concurrent requests. AI Gateway rejects further requests with HTTP 402 and quota_for_entity_exceeded until the budget resets or you raise it. Do not retry that rejection through another key.
Handle budget rejections in the request handler. SDK errors can wrap the AI Gateway's response, so inspect the cause chain and the quota type rather than treating every 402 as a budget limit. Create lib/handle-budget.ts:
Copy link to headingTry the router
Create app/api/generate/route.ts. This endpoint validates the prompt, calls your router, and returns the answer and selected tier.
Run pnpm dev, then send a request from another terminal:
The response includes text and tier. OpenAI Decisions is the default classifier. Add "decisionProvider":"jev" to the JSON body to try Jev. The heuristic rules still run first.
Copy link to headingMonitor AI Gateway spend and latency
Use AI Gateway observability to track model usage and spending. The router's decision log records the decision model's choice, its fast-tier probability, and the tier your policy selected.
Track these metrics together:
- Total cost per completed task, including classification, generation, fallbacks, and escalation
- Routing latency and generation latency, so you can see whether the extra decision call pays for itself
- The actual model that served each request, plus the split between tiers
- Answer quality and failure rates against the same evaluation set used for your single-model baseline
If almost everything resolves to frontier, inspect the requests before lowering the threshold. The workload may need it. If quality falls on the fast path, tighten the policy or improve the task-specific gate. Lower spending alone does not establish that the routing decisions were correct.
The generation calls already attach role and tier tags. Add request IDs to your application logs, and use AI Gateway's supported user and tags metadata where you need attribution by customer, feature, or environment. Do not include prompt text or credentials in those tags.
Copy link to headingNext steps
You can further improve cost optimization and build on the current solution with these three techniques:
- Caching repeated prompts: An application response cache can avoid the model call entirely when reuse is appropriate. Prompt caching reuses input processing while generation still runs. AI Gateway supports automatic prompt caching, including adding cache markers for supported providers that require them.
- A/B testing: Use the Flags SDK to compare routing policies on production inputs after evaluating them offline. Compare quality and total cost, including the decision call.
- Advanced failover handling: The
generate()function already supplies a model fallback. Add provider ordering and timeouts where needed, while keeping all attempts within the intended tier's budget.
Copy link to headingTroubleshooting
Copy link to headingEverything escalates to the frontier
Check the heuristic rules and decision probabilities on labeled requests. A rule may match too broadly, the fast-tier probability threshold may be too high, or the workload may need the frontier tier. Change one setting at a time and check the answer quality again.
Copy link to headingA model string returns not found
The creator/model string has a typo or names a model that is not available through the AI Gateway. Check the model ID against the catalog character for character. Preview IDs can be retired or replaced, so verify both the primary and fallback.
Copy link to headingThe decision call fails or returns an uncertain decision
An uncertain successful decision follows the policy in classifyWithDecision() and selects the frontier. An API failure reaches the request handler instead. Fix authentication, credit, or quota errors before retrying; choose and test an explicit outage policy if your application must continue when classification is unavailable.
Copy link to headingLatency is worse than expected
Measure how often requests reach the decision model and how much latency it adds. Compare the combined routing and generation time against the single-model baseline. You may get better results by changing which requests reach the decision model, tuning the threshold, or using only heuristics.
Copy link to headingRelated resources
- AI SDK documentation
- AI Gateway: Model fallbacks
- AI Gateway: Automatic Caching
- AI Gateway: Observability
Copy link to headingFAQ
Does routing add latency?
The heuristic adds a small amount of local processing without a model call. Requests that the heuristic leaves undecided add a round trip, but the impact is small with fast decision models. Measure both paths against your baseline; an extra decision call can outweigh the benefit when the fast model already answers quickly.
Does BYOK still get cost tracking?
AI Gateway records usage and cost data for requests made with your own provider credentials. However, BYOK spend is metered separately and does not count toward AI Gateway’s team, project, API key, or user budgets. Use your provider’s spending controls to limit that usage. See Bring Your Own Key.
How is this different from setting a budget?
A budget rejects further requests after a spending limit is reached. Routing chooses which model handles each request before that point. Use both when you want to reduce unnecessary model spending and control how much the application can spend.
Can I route by user or plan instead of difficulty?
Yes. Apply plan entitlements, model allowlists, and other explicit constraints in application code before model selection. A decision model can help with an ambiguous classification inside those limits; it does not grant access to a model or override a budget.