När vår AI-leverantör pensionerade modellen
Ett modellbyte, tomma svar utan fel och en faktura som plötsligt blev flera gånger högre. Vad som gick sönder, och varför orsaken var så svår att se.

I juli 2026 slutade flera funktioner att fungera på en gång: AI-chatten, AI-svar i tickets, ticketsammanfattningar, serverbyggaren, plus moderering och översättning av idéer och buggrapporter.
Orsaken var inte vår kod. Vår AI-leverantör hade pensionerat modellen vi använde.
Del ett: modellen är borta
Det är den uppenbara delen, och den åtgärdades snabbt. En leverantör lägger ner en modell, man anger efterträdaren, klart.
Den egentliga incidenten började efteråt.
Del två: tomma svar, utan fel
Efter bytet kom svar tillbaka. Bara ibland var de tomma. Inte avkortade, inte trasiga, utan ett helt tomt svar utan något fel alls.
Orsaken ligger i en skillnad som modellnamnet inte avslöjar: efterträdaren är en resonerande modell. Före själva svaret skriver den först en intern tankegång i ett separat fält. Båda drar från samma tokenbudget.
Om budgeten förbrukas av tänkandet kommer ett svar tillbaka som formellt är i ordning: leverantören rapporterar "längden uppnådd" och innehållsfältet är tomt. Inget fel, ingen ledtråd, inget som en try/catch skulle se.
Vi återskapade det med ett riktigt test: en budget på fem tokens räcker redan för att ge ett tomt svar på varje anrop.
Del tre: fakturan
På det dyraste anropsstället, AI-serverbyggaren, hade vi satt en generös budget eftersom långa svar produceras där. Så tänkandet slog inte i någon gräns, det bara fortsatte.
Följderna kom från två håll samtidigt. Anropen tog så lång tid att de gick in i timeouts. Och de kostade flera gånger mer, eftersom en hel osynlig tankegång betalades varje gång. Till slut kom ett felmeddelande vi inte hade planerat för: otillräckligt saldo.
Lösningen är en rad. Tänkandet kan stängas av i anropets innehåll, och modellen beter sig då som den gamla igen. Sedan dess hör den raden till varje anropsställe, och det finns fler än en handfull i kodbasen.
Del fyra: vad vi hittade när vi städade
Om man ändå rör varje AI-anropsställe tittar man på dem. Det lyfte fram ett andra ämne, som inte hade med incidenten att göra men som var lika dyrt.
Leverantörer tar betydligt mindre betalt för en prompt vars början förblir oförändrad och kan serveras från en cache. Skillnaden mellan en träff och en miss är ungefär trettiofaldig.
Den rabatten får man inte via en flagga. Vi testade det specifikt: ett fält i anropet avsett för det hade noll effekt, cachen gäller automatiskt ändå. Den enda spaken är ordningen i prompten, från stabilt till föränderligt.
Fyra ställen där vi hade gjort precis tvärtom:
Ett föränderligt värde i det fasta instruktionsblocket. Dubblettkontrollen för buggrapporter hade modulnamnet i instruktionstexten. Det gav ett annars identiskt block en egen cacherad per modul. Värdet hör hemma i den variabla delen, där det ändå ändras.
Det nya före det stabila. Samma kontroll skickade den nya buggrapporten före de upp till femtio jämförelsekandidaterna. Det gjorde API:ets största prompt till en permanent fullständig miss.
Data per användare i den fasta delen. Den offentliga AI-chatten hade anteckningarna om den enskilda användaren i instruktionsblocket, alltså före den gemensamma kanalhistoriken. Det gav varje användare i samma kanal en egen början, och den gemensamma historiken betalades separat per användare.
Ett glidande fönster över historiken. Att skicka de senaste N meddelandena vid varje meddelande flyttar början vid varje meddelande. Hela historiken blir då en permanent miss. Rätt sätt är att trimma i block, alltså sällan och ordentligt.
Plus en detalj som ser ut som pedanteri men inte är det: en lista i en prompt som bara sorteras efter ett kriterium kan byta ordning vid lika värden. En enda omkastad rad mitt i instruktionsblocket kostar träffen för allt som kommer efter. Sorteringar i prompter behöver ett entydigt avgörande kriterium.
Vad vi tog med oss
Ett modellbyte är ingen konfigurationsändring. Namnet ser ut som ett värde i en variabel. Bakom det fanns ett annat beteende, och beteendet bröt vår kod, inte gränssnittet.
Det farliga felet var det tysta. Att den gamla modellen försvann syntes direkt och åtgärdades på minuter. De tomma svaren kom tillbaka som formellt giltiga svar och hade kunnat förbli så hur länge som helst.
Mätbarhet hör hemma vid anropsstället. Vi loggar nu cacheträffsgraden vid vart och ett. Ett korrekt byggt ställe landar på en hög andel efter första anropet, ett felbyggt stannar på noll. Det ser man i en loggrad och ingen annanstans, eftersom båda fungerar.
Och den obekväma slutsatsen: att använda någon annans modell betyder att en del av din produkt beror på ett beslut som fattas någon annanstans. Därför kan sedan augusti varje server rikta AI-funktionerna mot sin egen endpoint i stället för att förlita sig på vår.
Fler artiklar
Koll på 4 000 Discord-servrar: Grafana, PostHog och vad de visade oss
En loop som i tysthet stod för halva vår trafik, tre miljoner meningslösa förfrågningar om dagen och en attack som var över efter en minut. Vad vår övervakning ser, och vad den medvetet inte ser.
Bakom kulissernaVad en bot på över 2 000 Discord-servrar har lärt oss
Fyra saker som fungerar annorlunda i stor skala än man tror medan man skriver koden.
Bakom kulissernaLagen i vår kod
En uppsägningsknapp som måste fungera utan inloggning. Ett formulär som aldrig får avvisa dig. Varför rättsliga skyldigheter är arkitektur för oss, inte standardtext.