Så bygger jag en model router istället för att välja modell manuellt
När man arbetar mycket med AI är det lätt att få en ny sorts beslutsutmattning. Ska just den här uppgiften gå till den starkaste modellen, den billigaste, Claude, OpenAI eller Gemini?
När man arbetar mycket med AI är det lätt att få en ny sorts beslutsutmattning. Ska just den här uppgiften gå till den starkaste modellen, den billigaste, Claude, OpenAI eller Gemini? När jag gjorde valet manuellt blev resultatet inkonsekvent: ibland använde jag en dyr modell av vana, ibland en billig modell på en uppgift där ett fel kostade mer än tokensen jag sparade. Därför började jag tänka på modellval som routing, inte preferens. Uppgiften ska beskriva sina krav och systemet ska välja en rimlig modellklass. Frontiermodellen blir en eskalering, inte default.
"Bästa modellen" är fel fråga
OpenAI:s aktuella modellkatalog illustrerar problemet tydligt: samma modellfamilj kan ha varianter positionerade för komplex reasoning, balans mellan intelligens och kostnad samt högvolym- och kostnadskänsliga workloads. Det finns alltså inget skäl att anta att den dyraste varianten är rationell för varje steg. Samma sak gäller över leverantörer. En modell kan vara bättre på en viss codinguppgift, en annan på lång research, en tredje på enkel klassificering till mycket lägre kostnad. Frågan jag försöker besvara är i stället:
Det ger en annan arkitektur.
Jag routar arbete, inte användare
En vanlig routing-idé är att låta användaren välja modell i UI. Det kan vara bra för avancerade användare, men i mina egna system vill jag helst att produkten känner till arbetssteget. Ett contentflöde innehåller exempelvis source extraction, claim decomposition, evidence audit, outline, draft, fact-check, editorial pass och metadata. De stegen har helt olika krav — metadata behöver sällan samma reasoningbudget som evidence audit. Jag ger därför varje task type en profil:
Routerlogiken väljer sedan en modellpolicy, inte ett "favoritnamn".
Jag benchmarkar uppgiften, inte varumärket
Frågan "vilken AI-modell är bäst?" är för grov för hur jag faktiskt bygger. Jag vill veta vilken modell som är bäst för ett bestämt steg, med ett bestämt kvalitetskrav, en latency-budget och en kostnadsram. Det gör GPT, Claude och Gemini till komponenter i en routingtabell snarare än leverantörer att hålla på. För en researchuppgift kan coverage och källhantering väga tyngst. För en kodagent kan tool use, repo-navigation och regressioner vara viktigare. För batchklassificering är kostnad och throughput centralt. Jag bygger därför ett litet evalset från verkliga arbetsuppgifter och kör kandidaterna mot samma rubric, i stället för att gissa utifrån varumärke.
Börja med tre lanes
Jag tycker att routers ofta överdesignas. Man behöver inte en meta-LLM som bedömer 27 parametrar för varje call. Jag börjar hellre med tre lanes: FAST/CHEAP för repetitiva och lättvaliderade steg, BALANCED för normala språk- och koduppgifter, och FRONTIER för komplex reasoning, osäkra fall eller användarens uttryckliga begäran.
I OpenAI-termer kan en aktuell policy exempelvis mappa dessa lanes till Luna/Terra/Sol eller motsvarande framtida modeller (illustrativa exempel — inte faktiska modellnamn). Google gör en liknande uppdelning med sina Flash- och Flash-Lite-varianter. Poängen är inte namnen; det är att leverantörerna själva erbjuder olika price/performance-profiler, och att applikationen använder lane-namnet internt så att den faktiska modellen kan bytas utan att affärslogiken skrivs om:
När leverantören deprekerar en modell ändrar jag mappingen, inte hela systemet. Anthropic publicerar löpande model-deprecation-status och rekommenderade ersättare (kontrollera den aktuella sidan vid publicering, den uppdateras löpande). Det är ännu ett skäl att inte hårdkoda modellnamn djupt i produktlogik.
Default ska vara den billigaste godkända vägen
Jag har en ganska hård princip: den dyraste modellen ska inte vara default bara för att den är bäst i ett benchmark. Den ska användas när arbetssteget motiverar den eller när användaren uttryckligen ber om den. Det betyder inte "alltid billigast". Det betyder att routingpolicyn ska ha en kvalitetsgräns.
Om bara frontiermodellen klarar evalen blir den rätt val. Om en billig modell klarar uppgiften lika bra är extra reasoning en kostnad utan produktvärde.
Evals måste komma före routing
Det går inte att bygga seriös routing på magkänsla. Jag behöver ett litet testset per task type. För en faktakontroll kan evalen mäta om modellen hittar unsupported claims, om den bevarar qualification, om den fabricerar källstöd och om den följer output-schema. För SQL kan den mäta om den bara använder verifierade kolumner, om den bevarar metric-definitionen, om den introducerar grain-buggar och om den returnerar validation queries. För humanisering kan den mäta om fakta och säkerhetsgrad bevaras, om mekaniska fraser försvinner och om nya erfarenheter läggs till. Routerbeslutet bör bygga på sådana test, inte på "modell X känns smartare".
Jag skiljer på hårda capability-krav och mjuka preferenser
Vissa uppgifter kan inte gå till alla modeller oavsett pris. De kan kräva ett visst context window, tool use, vision, structured output, web- eller filsökning, viss maximal outputlängd eller region- och datapolicy. Dessa är hårda filter. Sedan kommer mjuka kriterier: kostnad, latency, kvalitetsmarginal, provider diversity och cache hit-rate. Det är en viktig separation. En router ska aldrig välja en billig modell som saknar en nödvändig capability bara för att score-formeln råkade väga cost högt.
Confidence från modellen är inte routingens sanning
Det är lockande att låta första modellen svara med confidence: 0.62 och eskalera om siffran är låg. Jag använder sådana signaler försiktigt. En språkmodells egen confidence är inte automatiskt en kalibrerad sannolikhet. Jag föredrar observerbara triggers:
Dessa kan eskalera till en starkare modell eller människa. Modellens självbedömning kan vara en signal bland flera, men inte ensam gate.
Eskalering ska ha ett stopp
En dålig router kan skapa dyra loops:
Jag definierar därför max escalation depth och terminala states:
Om frontier fortfarande saknar evidens ska systemet inte "försöka hårdare". Problemet kanske inte är intelligens utan saknad data. Detta är särskilt viktigt i research och finansiell analys. En starkare modell kan skriva ett mer övertygande svar på samma otillräckliga underlag. Det gör inte svaret sannare.
Provider routing kräver normaliserad output
När jag blandar leverantörer vill jag inte att resten av applikationen ska känna till varje API-format. Jag bygger ett tunt adapterlager:
Då kan logging, evals och fallback fungera likadant oavsett leverantör. Det är också där jag fångar provider-specifika fel och mappar dem till egna felklasser som RATE_LIMIT, INVALID_REQUEST, PROVIDER_DOWN och OUTPUT_VALIDATION_FAILED.
Routing behöver en fallback
En router får inte anta att favoritmodellen alltid finns. Rate limits, deprecations, regional tillgänglighet och incidenter händer. Därför mappar jag varje capability profile till en lista: primär modell, kompatibel fallback och eventuell manuell escalation. Anthropic publicerar uttryckliga deprecation- och retirementdatum, vilket är en bra påminnelse om att ett modell-ID är en dependency med egen livscykel — precis som med lane-mappingen ovan, inte något som ska hårdkodas djupt i produktlogiken.
Jag låter heller inte modellen välja helt fritt vem som får denna fallback-status. En modell kan hjälpa till att klassificera svårighetsgrad, men själva routingpolicyn bör ha deterministiska gränser. Känslig finansiell analys får exempelvis kräva den högsta godkända reasoningprofilen och source verification, oavsett vad en billig classifier säger. Bulk-normalisering kan däremot gå till en billigare modell så länge evals håller.
Cost per token räcker inte
När jag jämför modeller tittar jag inte bara på listpris. Den verkliga kostnaden per lyckad uppgift påverkas av antal retries, hur lång output modellen tenderar att skriva, hur ofta den behöver reviewer, latency som påverkar användarflödet, contextstorlek, cache och hur ofta ett fel skapar mänskligt efterarbete. En billig modell som misslyckas 20 procent av gångerna kan vara dyrare än en dyrare modell som passerar första gången. Det mått jag egentligen vill åt är:
Det kräver egen telemetry — jag följer pass rate, revisionsbehov, latency och human review time tillsammans med API-kostnaden. Evals gör den diskussionen konkret.
Routing i min contentfabrik
Ett konkret exempel är artikelproduktionen. Jag skulle inte lägga samma lane på alla nio roller. Research extraction kan ofta gå billigare om källorna är tydliga. Evidence audit får högre krav eftersom den bestämmer vad writern får hävda. Draft kan använda en balanserad modell. Fact-check kan eskalera vid conflict. SEO metadata är lättare och starkt validerbart. En policy kan se ut så här:
Detta är ett bättre kostnadsinstrument än att bara byta hela systemet till en billig modell.
Routing i coding
Samma princip fungerar i Claude Code-liknande arbetsflöden. En enkel filändring eller testfix behöver inte samma reasoning som en arkitekturgranskning över flera services. Jag beskriver därför codingtasken med signaler: antal berörda filer, risk för dataförlust, om schema eller migration ingår, testtäckning, om kraven är tydliga och om uppgiften kräver extern research. Ju fler osäkerheter och irreversibla konsekvenser, desto starkare lane eller mer human review.
Failover är inte samma sak som quality routing
Det är också viktigt att skilja två problem. Quality routing: vilken modell är bäst lämpad för uppgiften? Availability routing: vad gör vi när vald provider är nere eller throttlad? En fallback-provider kan vara sämre men tillräcklig för vissa task types. För andra ska systemet hellre vänta eller blockera. Jag definierar därför per task:
Det gör outage-beteendet förutsägbart.
Jag loggar routerbeslutet
Om en output blir dålig vill jag veta varför en viss modell användes. Jag sparar därför minst:
Utan detta går det inte att optimera routern. Man ser bara total API-kostnad.
Modellbyten ska vara en konfigurationsändring
Modeller förändras snabbt. Anthropic har tydliga deprecation-cykler och OpenAI uppdaterar löpande sin katalog. Därför bör produktlogik inte innehålla resonemang som:
Jag vill hellre ha:
När modeller byts kör jag evals igen och uppdaterar mappingen.
När användaren ska få välja
Jag gömmer inte alltid modellvalet. I avancerade verktyg kan användaren ha legitim anledning att be om en viss modell, särskilt för research eller coding. Då behandlar jag det som override:
men behåller fortfarande safety- och capability-kontroller. Ett användarval får inte kringgå exempelvis datakrav eller blockerande publisher gate.
Den enklaste router som är värd att bygga
Om jag skulle börja i dag skulle version ett bara innehålla tre lanes, task-type mapping, capability filter, ett litet evalset per viktig task, en eskaleringsregel och usage/acceptance logging. Ingen meta-agent. Ingen reinforcement learning. Ingen komplex bandit. Efter hundratals verkliga calls kan jag se var routern har något att optimera.
Min viktigaste lärdom
Model routing är egentligen inte ett modellproblem. Det är ett system för att uttrycka kvalitetskrav. När alla uppgifter går till frontiermodellen behöver jag aldrig definiera hur bra "bra nog" är. Så fort jag vill optimera kostnad tvingas jag skapa evals, acceptance criteria och felklasser. Det är nyttigt även om kostnadsbesparingen vore noll. Jag använder därför routern som en arkitekturprincip: börja med minsta godkända modell, eskalera på observerbara signaler och sluta när problemet inte längre är modellkapacitet. Det gör systemet billigare i många fall. Viktigare är att det gör modellvalet reproducerbart. Det viktigaste beslutet är därför sällan GPT vs Claude vs Gemini — det är vilka kvalitetskrav varje steg har och hur systemet bevisar att de fortfarande uppfylls.
En router behöver ett eget eval-register
När antalet task types växer vill jag kunna se varför en lane är godkänd. Jag lagrar därför en enkel matrix:
Då blir routingpolicyn en konsekvens av mätning. Om en ny billig modell plötsligt klarar evidence audit kan jag flytta tasken utan att ändra resten av systemet. Jag vill också behålla gamla evalresultat. En modelluppgradering kan förbättra coding men försämra ett smalt formatkrav. Regression syns bara om jag jämför samma testset över tid.
Route policy bör vara versionerad
Precis som prompts behöver routerregler ett versionsnummer.
Om kostnaden plötsligt stiger kan jag se om det sammanföll med att en task flyttades till frontier. Om kvaliteten sjunker kan jag replaya ett sample mot tidigare policy. Det ger också tryggare A/B-test:
Jag skulle inte göra detta på högriskuppgifter utan kontroll, men för lättvaliderade steg kan det snabbt ge verklig data.
Contextkostnaden kan dominera modellpriset
En sak som lätt missas är att routing inte bara handlar om modellens listpris. Om en task skickar 80 000 tokens kontext till varje call kan även en billig modell bli dyr. Jag vill därför att routern eller upstream-lagret kan välja context strategy: full document, retrieved chunks, summary + evidence refs eller cached system context. En fast router som bara byter modell men skickar samma gigantiska context till alla löser inte hela kostnadsproblemet. I vissa steg kan en starkare modell med bättre retrievaldisciplin faktiskt bli billigare per accepted output än en billig modell som behöver flera försök.
Latency behöver ett SLA per task
Alla AI-calls behöver inte svara på två sekunder. En researchbatch kan få ta längre tid. En intervjusimulator med voice kan inte det. Jag sätter därför latency som krav:
Routern kan då välja annorlunda även om två modeller har liknande kvalitet och kostnad.
Riskklass ska kunna tvinga upp lane
Jag vill inte bara routea på task type. Samma task kan bli mer riskfylld beroende på innehåll. Exempel i content:
I SQL:
Jag använder alltså en tvådimensionell policy:
Det gör säkerhetskrav explicita.
Provider diversity är en resilience-fråga
Om hela produkten är byggd för exakt en providers tool semantics kan "multi-model routing" bli dyrt att lägga till senare. Jag behöver inte stödja allt från dag ett, men jag vill ha en intern representation av messages/input, tool definitions, structured output schema, usage och errors. Provider-adaptern översätter detta. Det innebär lite boilerplate, men gör det möjligt att senare köra evals över flera leverantörer på samma task contract.
Caching och deterministic prefix påverkar ekonomin
Många återkommande tasks delar långa instruktioner, policies eller dokument. Om providern stödjer caching vill jag designa prompten så stabila prefix faktiskt kan återanvändas. Det kan påverka routervalet. En modell med högre listpris men mycket bättre cache-ekonomi för ett visst workload kan vinna i praktiken. Det är ännu ett argument för att mäta verklig cost per accepted output snarare än läsa prissidan isolerat.
Jag undviker router-LLM i version ett
Det känns elegant att använda en LLM för att välja LLM. Men då har jag skapat ett nytt probabilistiskt steg som själv kostar pengar och kan routa fel. För mina första versioner föredrar jag deterministiska regler:
Först när rules blir uppenbart otillräckliga skulle jag överväga en learned/router-model och då behöver även den evals.
Budget kan vara en explicit input. I vissa batchar vet jag hur mycket jobbet får kosta. Då kan routerpolicyn planera mot budget:
Routern kan välja billig lane för enkla items och reservera frontierbudget för unresolved cases. Det är bättre än att sänka kvaliteten på allt när budgeten är pressad.
När frontier ska vara direktval: det finns samtidigt uppgifter där jag inte vill börja billigt bara för principens skull. Om failure cost är högt och input redan signalerar komplexitet kan direkt frontier vara rationellt — kritisk arkitekturreview, komplex finansiell analys med många beroenden, hög-risk evidence conflict, svår debugging över stor kodbas, eller att användaren uttryckligen har valt premiumläget. Routing betyder alltså inte "alltid cheap-first". Det betyder att valet följer policy.
Ett verkligt beslutsträd jag kan leva med ser ungefär ut så här:
Det är inte magiskt. Just därför går det att förstå när det går fel.
Jag vill också kunna simulera routing utan att skicka riktiga calls. Innan jag ändrar en policy vill jag kunna köra historiska task-metadata genom routern i dry-run och se hur fördelningen hade förändrats: hur många calls skulle ha flyttats från frontier till balanced, vilka high-risk tasks skulle få en annan route, vilken ungefärlig kostnad hade policyn gett med samma volym. Det kräver inte att jag replayar alla prompts. Ett första lager kan arbeta på metadata och historisk usage. Därefter kan ett representativt sample replayas mot kandidater för faktisk kvalitetsjämförelse. Detta gör kostnadsoptimering säkrare. Jag vill inte upptäcka efter en vecka att en aggressiv cheap-first-regel flyttade just de fem procent svåraste fallen till en modell som passerar enkla evals men missar edge cases.
Routern ska också kunna säga "ingen modell är godkänd". Det kanske viktigaste terminala utfallet är inte en modell, utan BLOCKED. Om capability saknas, evalgränsen inte klaras eller evidensen är för tunn ska routern inte alltid hitta ett alternativ.
Det håller routingproblemet ärligt. En större modell är inte automatiskt en lösning på en dåligt specificerad eller ofullständig uppgift.
Min första dashboard för routern skulle börja med fyra grafer: calls per lane, expected cost per accepted output, escalation rate per task type och validation failure per modell. Därefter vill jag kunna filtrera på policyversion. Om frontier-användningen ökar ska jag direkt kunna se om det beror på mer komplex trafik, en svagare balanced-modell eller en regeländring. Det gör routern till ett system som går att förvalta. Utan den insynen blir "smart routing" bara ytterligare ett lager som flyttar kostnader och fel utan att någon vet varför.
En bra router gör även avveckling enklare. När en modell ska pensioneras kan jag fråga vilka lanes och task types som fortfarande pekar på den, köra deras evals mot ersättaren och flytta trafik kontrollerat. Det är mycket säkrare än att söka efter ett modellnamn i hela kodbasen och hoppas att ingen hårdkodad specialregel missas. Routinglagret blir därmed också ett lifecycle-lager för modellerna.
Routern blir då inte bara billigare utan också enklare att granska, byta och felsöka över tid.