Billig og dyr språkmodell per oppgave: to knapper i en produksjonsapp

Prisgapet mellom åpne vektmodeller og kommersielle frontier-modeller har krympet kraftig i 2026. En open-weight-modell holder ofte til rutinearbeid, mens tunge oppgaver fortsatt trenger frontier. Jeg har bygd inn valg av modell per oppgave i en produksjonsapp jeg drifter: billig modell til enkle endringer, dyr modell til vanskelige.

To knapper: Billig og Dyr

Appen har en AI-funksjon som gjør promptdrevne kodeendringer: en admin skriver hva som skal endres, en runner kjører en kodeagent headless (klon, endre, kjør tester, push), og deploy skjer automatisk. Den eneste endringen i brukergrensesnittet var at «Send»-knappen ble byttet ut med to knapper, «Billig» og «Dyr». Valget lagres på jobben som model_tier og følger med når runneren plukker den opp.

Runneren bygger miljøet til kodeagenten ut fra valgt tier. Dyr peker rett på frontier-APIet. Billig peker på OpenRouter, som har et Anthropic-kompatibelt /api/v1/messages. Kodeagenten kjører dermed uendret mot begge, uten proxy imellom.

Routing-diagram: én jobbkø splittes i billig (OpenRouter) og dyr (frontier), begge samles i samme runner som kjører kodeagenten headless
Én kø, to ruter. Tier-valget avgjør bare hvilke miljøvariabler runneren setter før den starter kodeagenten.

Felle 1: alle fem modellvariablene må settes

Base-URL og token er ikke nok for at kodeagenten skal snakke med OpenRouter. Agenten har flere interne modell-slotter (hoved, liten/rask og standardvarianter). Setter du bare noen av dem, faller resten tilbake til Anthropic-modellnavn som OpenRouter ikke kjenner, og kallet feiler. Alle må peke på samme OpenRouter-modell:

# Billig: hele settet må settes
export ANTHROPIC_BASE_URL=https://openrouter.ai/api
export ANTHROPIC_AUTH_TOKEN=sk-or-v1-...
export ANTHROPIC_MODEL=openai/gpt-oss-120b
export ANTHROPIC_SMALL_FAST_MODEL=openai/gpt-oss-120b
export ANTHROPIC_DEFAULT_HAIKU_MODEL=openai/gpt-oss-120b
export ANTHROPIC_DEFAULT_SONNET_MODEL=openai/gpt-oss-120b
export ANTHROPIC_DEFAULT_OPUS_MODEL=openai/gpt-oss-120b
Felle 2: agentens kostnadstall er feil for billig-jobbene
Kodeagenten regner ut total_cost_usd med frontier-priser uansett hvilket endepunkt den peker mot. En triviell filendring mot den billige modellen ble rapportert til 0,167 USD. Det er frontier-pris for det token-forbruket, og ikke det OpenRouter tar. Bruker du det tallet i regnskapet, ser billig-ruten like dyr ut som den dyre.

Løsningen er å ignorere agentens kosttall for billig-jobber og regne selv: token-forbruket ganger dine egne OpenRouter-satser.

kost_usd = (tokens_inn / 1_000_000) * PRIS_INN_USD
+ (tokens_ut / 1_000_000) * PRIS_UT_USD
Bytter du modell, må prisene byttes samtidig. Prisene ligger derfor som miljøvariabler ved siden av modellnavnet og er ikke hardkodet.

Kostnad per jobb

Samme type jobb, målt ende til ende mot den ekte kodeagent-loopen:

Jobb Tier Modell Kost
#2 dyr frontier 24,58 kr
#3 dyr frontier 4,55 kr
#4 billig openai/gpt-oss-120b 0,33 kr
Billig-jobben kostet 0,33 kr, den dyreste 24,58 kr. Det er to størrelsesordener. Den billige modellen er svakere, men klarer nok av oppgavene til at snittkostnaden per jobb faller kraftig.

Tre modeller testet mot ekte filendringer

Gode benchmark-tall betyr ikke at en modell klarer å kalle verktøy, lese filer og skrive tilbake i en agent-loop. Jeg testet tre modeller mot ekte filendringer:

openai/gpt-oss-120b OK $0.037 / $0.17 (valgt)
qwen/qwen3-coder OK $0.30 / $1.00 (reserve, mest token-effektiv)
deepseek/...-v4-flash FEIL tomt svar, null verktøykall
Deepseek-varianten returnerte tomt innhold og gjorde ingen verktøykall. Den er en kodemodell på papiret, men var ubrukelig i denne loopen. Test mot din egen agent før du velger modell.

Hva den billige modellen gjorde feil

Kodeendringen var korrekt, og modellen rettet sin egen feilende test i reparasjonsrunden. Feilene lå i alt rundt:

  • Den satte en changelog-oppføring midt inne i et eksisterende avsnitt og brøt en setning i to.
  • Den lagde en ny testfil med duplisert hjelpekode i stedet for å utvide den eksisterende testklassen.
  • Commit-meldingen beskrev reparasjonsrunden, ikke selve endringen.
  • Den brukte Unicode-bindestrek og krøllete anførselstegn i markdown.

Ingenting av dette er farlig, men alt må ryddes. Billig passer derfor til små, avgrensede endringer, med litt opprydding i dokumentasjonen etterpå. Begge tiers har de samme kontrollene: testene må være grønne før push, en røyktest kjøres etter deploy, og feiler noe, rulles endringen tilbake automatisk.

Synkront kall eller egen runner

Den samme billige modellen brukes også i en samtalefunksjon i systemet. Der kalles OpenRouter synkront rett fra PHP, uten kø. For korte, chat-lignende kall er det enklere, og svaret kommer med en gang.

Valget avhenger av hvor lenge kallet varer. Kodeendringene kan ta minutter, og infrastrukturen har en hard grense på 120 sekunder på synkrone fjernkall. Alt som varer lenger, må kjøres som bakgrunnsjobb via runneren med logging og polling. Ellers blir det kuttet midtveis.

gpt-oss-120b er en reasoning-modell. Svaret ligger i content og resonnementet i et eget felt. Setter du token-kappet for lavt, bruker resonnementet hele budsjettet, og content kommer tomt tilbake. Reasoning-tokenene telles med i completion_tokens, så kostnaden blir riktig, men kappet må være høyt nok til at det kommer et svar.

Når jeg velger billig og når jeg velger dyr

Billig brukes til avgrensede endringer i én eller få filer: rett en feilmelding, juster en validering, legg til et felt. Dyr brukes når modellen må holde mange filer i hodet samtidig eller resonnere seg gjennom et design: refaktorering, ny modul, endringer i arkitekturen. De fleste oppgaver er små, og det er bortkastet å betale frontier-pris for å bytte en feilmelding. Er du i tvil, start billig og eskaler. Den billige jobben koster brøkdeler av en krone, så et bomskudd koster nesten ingenting.